extrai um arquivo do arquivo jar e obtém o diff

2

No mundo real, eu tenho um xsd em um arquivo jar em várias versões que estou tentando verificar se o xsd foi alterado entre os releases 10.x.y.z a 11.a.b.c

Eu tenho diferentes diretórios de lançamento que são lidos apenas como abaixo em alguns /m/n/i/10.x.y.z ou 11.x.y.z. Eu quero procurar por abc.jar que pode ser enterrado no meu diretório de lançamento 10.xyz ou 11.xyz em alguns p / q / r / abc.jar em todos os lançamentos e extrair xyz.xsd deles e fazer uma diferença entre Além disso, eu não tenho permissão de gravação para os diretórios de lançamento.

Como posso conseguir isso em Unix ou shell script? Eu sou novo no Unix. Estrutura de diretórios

.
|-- 10.1.2.2.0
|   '-- GENERIC
|       '-- RELEASE
          --  x/y/z/abc.jar
|-- 10.1.2.3.0
|   '-- GENERIC
|       '-- RELEASE
          -- x/y/z/abc.jar
|-- 10.1.3.1.0
|   '-- GENERIC
|       '-- RELEASE
|-- 10.1.3.3.0
|   '-- GENERIC
|       '-- RELEASE
|-- 10.1.3.3.0-HOTPLUG
|   '-- GENERIC
|       '-- RELEASE
|-- 10.1.3.3.0BPA
|   '-- GENERIC
|       '-- RELEASE
|-- 10.1.3.3.0WEBSPHERE
|   '-- GENERIC
|       '-- RELEASE
|-- 10.1.3.3.1
|   '-- GENERIC
|       '-- RELEASE
|-- 10.1.3.4.0
|   '-- GENERIC
|       '-- RELEASE
|-- 10.1.3.4.0MLR1
|   '-- GENERIC
|       '-- RELEASE
|-- 10.1.3.4.0MLR10
|   '-- GENERIC
|       '-- RELEASE
|-- 10.1.3.4.0MLR2
|   '-- GENERIC
|       '-- RELEASE
|-- 10.1.3.4.0MLR3
|   '-- GENERIC
|       '-- RELEASE
|-- 10.1.3.4.0MLR4
|   '-- GENERIC
|       '-- RELEASE
|-- 10.1.3.4.0MLR5
|   '-- GENERIC
|       '-- RELEASE
|-- 10.1.3.4.0MLR6
|   '-- GENERIC
|       '-- RELEASE
|-- 10.1.3.4.0MLR7
|   '-- GENERIC
|       '-- RELEASE
|-- 10.1.3.4.0MLR8
|   '-- GENERIC
|       '-- RELEASE
|-- 10.1.3.4.0MLR9
|   '-- GENERIC
|       '-- RELEASE
|-- 10.1.3.5.0
|   '-- GENERIC
|       '-- RELEASE
|-- 10.1.3.5.0.QA.06012009
|   '-- GENERIC
|       '-- RELEASE
|-- 10.1.3.5.1
|   '-- GENERIC
|       '-- RELEASE
|-- 10.1.3.5.2
|   '-- GENERIC
|       '-- RELEASE
|-- 10.1.3.5.3
|   '-- GENERIC
|       '-- RELEASE
|-- 10.1.3QAMLR6
|   '-- GENERIC
|       '-- RELEASE
|-- 11.1.1.1.0
|   '-- GENERIC
|       '-- RELEASE
|-- 11.1.1.1.0.BPA
|   '-- GENERIC
|       '-- RELEASE
|-- 11.1.1.1.0.CEP
|   '-- GENERIC
|       '-- RELEASE
|-- 11.1.1.2.0
|   '-- GENERIC
|       '-- RELEASE
|-- 11.1.1.3.0
|   '-- GENERIC
|       '-- RELEASE
'-- 11.1.1.4.0
    '-- GENERIC
        '-- RELEASE

93 directories, 0 files
    
por constantlearner 25.04.2013 / 17:52

6 respostas

1

Supondo que haja apenas um abc.jar em cada diretório:

basedir=path_to_your_Release_dirs
mkdir /var/tmp/reldiff
cd /var/tmp/reldiff
for x in Release1 Release2 Release3; do
   mkdir $x
   cd $x
   find $basedir/$x -name abc.jar -print0 | xargs -0 unzip -j xyz.xsd
   cd ..
done
diff3 */xyz.xsd
    
por 25.04.2013 / 18:17
1

Algo assim, talvez?

#!/bin/sh

number_of_releases = 3    

for i in $(seq 1 $number_of_releases)
do
cd Release$i
jar xf abc.jar xyz.xsd
mv xyz.xsd ../xyz.xsd_$i
cd ..
done

for i in $(seq 1 $(($number_of_releases-1)))
do
diff xyz.xsd_$i xyz.xsd_$(($i+1)) > diff_Release$(($i))_to_Release$(($i + 1))
done

EDITAR veja @ rany-albeg-wein comment

    
por 25.04.2013 / 18:13
0

Este script deve fazer o que você precisa. Existem várias suposições que estão sendo feitas e não são excessivamente modulares. Também não tem verificações. Precisaria de mais detalhes para torná-lo mais robusto.

find . -type f -name 'abc.jar' -exec sh -c '
num=$(echo {} | sed 's#.*Release##' | sed 's#/.*##')
jar xvf {} xyz.xsd
mv xyz.xsd xyz.xsd.${num}
' {} \;

for i in xyz.xsd*; do 
  currnum=$(echo $i | sed 's#xyz.xsd.##')
  let nexnum=currnum+1
  [ ! -f xyz.xsd${nexnum} ] || exit
  echo "diff $i xyz.xsd${nexnum} > diffs_xyz.xsd_${currnum}_${nexnum}.txt"
done

Dados de amostra

$ tree -A
.
├── myscript.bash
├── Release1
│   ├── abc.jar
│   └── xyz.jar
├── Release2
│   ├── abc.jar
│   └── xyz.jar
├── Release3
│   ├── abc.jar
│   └── xyz.jar
└── Release43
    └── xyz.jar

4 directories, 8 files
    
por 25.04.2013 / 20:43
0

Aqui está uma solução Perl:

#!/usr/bin/env perl
my $jar="abc.jar";       ## The jar file we will search for
my $target="xyz.xsd";        ## The file we will extract from it
my $data_dir=$ARGV[0]||"./";     ## The directory to search through

## Collect directory names, any directory that contains a file
## called whatever you set as $jar will be saved
my @dirs=split(/\n/,'find \"$data_dir\" -name \"$jar\" -exec dirname {} \;');
my @names;
foreach (@dirs) {
    ## Extract the $target from $jar
    system("cd \"$_/\"; jar xf \"$jar\" \"$target\"; cd -");
    ## Save the toplevel directory name
    my @a=split(/\//);
    push @names,$a[1];    
}
## Go through the list and run the diff
for ($i=0; $i<=$#dirs; $i++) {
    for ($k=$i+1; $k<=$#dirs; $k++) {
    system("diff \"$dirs[$i]/$target\" \"$dirs[$k]/$target\" > \"$names[$i]-$names[$k].$target.diff\"");
    }
}

Se você salvar o script Perl como foo.pl e, em seguida, executar o diretório que contém os vários subdiretórios Release , ele criará esses arquivos:

Release1-Release2.xyz.diff
Release1-Release3.xyz.diff
Release3-Release2.xyz.diff

Para executar o script, torne-o executável ( chmod a+x foo ) e execute-o diretamente ( ./foo.pl ) ou passe-o para perl ( perl foo.pl ). O diretório que contém os subdiretórios Release pode ser fornecido como o primeiro argumento (se nenhum for fornecido, o diretório atual é assumido):

perl foo.pl /path/to/releases
    
por 25.04.2013 / 18:15
0

Você pode usar esta função para extrair todos os arquivos de seus frascos

find /path/to/dir1 /path/to/dir2 -type f -name 'abc.jar' -exec bash -c 'jar xf "$1" "$2"' _ {} /path/to/file/inside/jar \;

Como você pode ver, jar pode levar um segundo (e mais) argumento depois de xf , que será o nome do arquivo que você deseja extrair do arquivo jar. Esse caminho deve ser absoluto na estrutura de sua árvore jar. Se você não souber o caminho para o arquivo no arquivo jar, poderá usar esse comando, que extrairá o arquivo jar inteiro:

find /path/to/dir1 /path/to/dir2 -type f -name 'abc.jar' -exec bash -c 'jar xf "$1"' _ {} \;

Se você usou o primeiro método, você pode apenas iterar seus arquivos xsd assim:

for i in *.xsd; do
    # diff your files here
done

Se você usou o segundo, você terá que usar algo assim:

while IFS= read -rd $'
for i in *.xsd; do
    # diff your files here
done
' xsd; do # diff your files here done < <(find /path/to/relevant/location -type f -name '*.xsd' -print0)
    
por 26.04.2013 / 00:05
0

Uma abordagem do Git

Dependendo das necessidades, pode ser bom usar o git também. Poderia ser facilmente estendido para incluir outros arquivos, etc. O script abaixo é uma variante simples de um mais complexo que eu escrevi para esse propósito. Funcionalidade de localização adicionada.

Ele lê as datas do arquivo extraído e usa isso no commit - assim você também tenha uma boa visão do tempo.

Uso de amostra

Como exemplo, você poderia diferenciar nas versões:

OuuseaGUIparamostrarasdiferenças.AoconservardatasemcometeroAvisãotambémforneceumaboavisãogeral:

Posicionada no diretório git, você também pode facilmente ver vários versões, por exemplo,

 gvim abc.xsd
 git checkout 10.1.2.2.0
 # Look at this version
 # Go back
 git checkout master
 # View pretty log
 git log --date-order --graph --tags --simplify-by-decoration --pretty=format:'%ai %h %d'

E assim por diante e assim por diante.

Caminhada rápida

  1. Crie um diretório de destino e inicialize o Git. (Remova primeiro se existir).
  2. Listar pastas no diretório de origem e classificá-las por classificação de versão. (Modifique o script, verificando qual tipo dá melhor resultado).
  3. Percorra cada diretório por ordem e localize o arquivo de origem.
  4. Copie o arquivo para o diretório de destino e extraia o arquivo necessário.
  5. Leia a data de modificação do arquivo add e commit.

Script

#!/bin/bash

#
# Please read script thoroughly before use.
#

# Git directory (created, old deleted!)
git_dir="git_proj"

# Project directory
proj_root="$HOME/tmp/jardiff/sample_proj"
release_dir="GENERIC/RELEASE"
# If file always is in same location:
target_dir="$release_dir/x/y/z"

# Files to (find) copy and extract
jar_file="abc.jar"
xsd_file="abc.xsd"

# If we should use relative absolute target directory or find
use_find=1
# If we want to commit empty (no change, but to list version as separate commit)
commit_empty=0

# Remove existing and create project diff directory
[ -e "$git_dir" ] && (echo y | rm -r "$git_dir")
mkdir -p "$git_dir"

cd "$git_dir"

# Init empty git
git init

# Date is read from file
export GIT_COMMITTER_DATE
export GIT_AUTHOR_DATE
# Author unknown (or extract it from elsewhere)
export GIT_AUTHOR_NAME="Unknown"
export GIT_AUTHOR_EMAIL="[email protected]"
# Committer
export GIT_COMMITTER_NAME="Auto Batch"
export GIT_COMMITTER_EMAIL="[email protected]"


for dir in $(ls -d "$proj_root"/* | sort -V); do
    echo "Processing: $dir"
    # Use root directory as project version
    bn=$(basename "$dir")
    # Copy target to git directory
    if ((use_find)); then
        if ! fn=$(find "$dir/$release_dir" -name "$jar_file" -print0); then
            fn="" # Probably not needed
        fi
    else
        fn="$dir/$target_dir/$jar_file"
    fi
    if [ -e "$fn" ]; then
        printf "Copying in %s\n" "$fn"
        cp --preserve=timestamps "$fn" .
        # Extract
        jar xf "$jar_file" "$xsd_file"
        # Read modified timestamp
        ts=$(stat -c %y "$xsd_file")
        # Set Git env date variables
        GIT_COMMITTER_DATE="$ts"
        GIT_AUTHOR_DATE="$ts"
        # Add file and commit
        git add "$xsd_file"
    else
        # Use timestamp from root directory
        # Here you would probably use a README file
        # or something else that has a more likely correct date
        # either by a new find or relative path.
        ts=$(stat -c %y "$dir")
        printf "Tagging empty %s - %s\n" "$bn" "$ts"
        # Set Git env date variables
        GIT_COMMITTER_DATE="$ts"
        GIT_AUTHOR_DATE="$ts"
    fi

    if ((commit_empty)); then
        git commit --allow-empty -am "Release $bn"
    else
        git commit -am "Release $bn"
    fi
    # Tag as release
    git tag -a "$bn" -m "Release $bn"
done
    
por 26.04.2013 / 03:57