Obtenha o diff recursivo codificado em delta binário de dois diretórios como um único arquivo de correção na CLI (e uso on-line)

9

Essencialmente, eu estou procurando por uma ferramenta GNU / Linux, que poderia recursivamente iterar através de dois diretórios, encontrar mudanças de arquivos / adições / exclusões; e para todos os arquivos alterados, imprima um diff. Isso já pode ser feito por diff eficientemente para arquivos de texto, mas não para arquivos binários grandes - Eu também gostaria de "diffs" eficientes entre arquivos binários incluídos no patch final (que, eu sei, é conhecido como Compressão delta binário - Wikipedia como subconjunto de codificação Delta - Wikipédia . Ou, em outras palavras, faça algo como descrito neste comentário "wishlist" (de CommandLineSyntax - xdelta - Google Project Hosting ):

  

Seria muito bom se o xdelta suportasse vários arquivos de correção. Algo como:

     

xdelta3 -r /path/folder1 /path/folder2 >allfilesrecursivepatch.xdelta

     

Para comparação recursiva de todos os arquivos na pasta1 e na pasta2 e criação de um único arquivo de correção para todos eles. E:

     

xdelta3 -r -d /path/folder1 <allfilesrecursivepatch.xdelta

     

Para aplicar o patch em todos os arquivos contidos na pasta1

Este recurso não existe, a julgar por Edição 21 - xdelta - Suporte a diff de diretório recursivo - Google Project Hosting , embora existam maneiras: a página de problemas tem várias sugestões para wrappers de script, mas eu prefiro manter as coisas independentes em uma única ferramenta.

O mais importante para mim seria a correção de uma parte do diretório do sistema de arquivos "ao vivo" como mostrado acima, devido ao meu caso de uso - descrito em mais detalhes abaixo e ilustrado com um script bash que usa git . / p>

Gostaria de poder atualizar um site estático em um host / webfarm baratinhos, que só permite a transferência por FTP (portanto, não rsync e outros) com uma velocidade de transferência bastante baixa e permite apenas a execução de scripts PHP . Normalmente, eu preciso sincronizar de local / cliente / home para servidor / webhost, mas é claro que eu não quero carregar 200 MB cada vez que eu quero atualizar uma página :)

Eu poderia usar outlandishideas / sync · GitHub para "Sincronizar o conteúdo do diretório via HTTP usando PHP", mas além de apenas sincronizar do servidor para local, também somente arquivos inteiros são enviados: "Nenhuma tentativa é feita para enviar diffs; isto não é rsync". Da mesma forma, eu poderia usar o GNU FTPsync ; provavelmente poderia manipular a criação, modificação e exclusão de arquivos, mas tem o mesmo problema - somente arquivos inteiros serão enviados.

Em princípio, git pode ser usado também - o script abaixo gera diretórios testdir_old e testdir_new e mostra que git pode codificar as diferenças entre eles ( neste caso sendo "removido" ; adicionado 1024; modificado / adicionado 19; modificado inline 1200 ", ou total 3267 bytes de alteração ) como um" sneakernet "git bundle tem 4470 bytes de tamanho. Mas mesmo que eu pudesse persuadir o host a instalar o git lá, eu ainda teria que manter um .git repo no webhost para que o pacote fosse aplicado corretamente - e eu definitivamente não quero fazer isso, Eu não poderia poupar o uso extra de tamanho de arquivo; Além disso, parece que gerenciando arquivos binários grandes com o git - o Stack Overflow requer git annex ou git bup .. E colocar um script como o abaixo seria problemático porque git recriaria novos hashes de revisão a cada vez, fazendo com que o pacote não se aplicasse de forma limpa.

Além disso, como no PHP, posso aparentemente " untar-gz sem exec ()? - Stack Overflow ", talvez valha a pena tentar determinar as alterações no diretório, empacote apenas os arquivos alterados em um tar.gz e envie para o script PHP no servidor, que o descompactaria sobre o diretório de destino. Isso ainda enviaria arquivos inteiros, mas pelo menos eles seriam compactados - mas as exclusões no servidor seriam difíceis de manipular.

Por fim, os utilitários de comparação de arquivos binários sugerem que é possível empacotar os diretórios em .tar(.gz) cada e, em seguida, executar o utilitário nesses arquivos - por exemplo, (via ExternalCompression - xdelta - Hospedagem do Google Project ):

gzip release-1.tar
gzip release-2.tar
xdelta3 -e -s release-1.tar.gz release-2.tar.gz delta-1-2.xd3
xdelta3 -d -s release-1.tar.gz delta-1-2.xd3 release-2.tar.gz

... provavelmente também é possível com o JojoDiff / jdiff

jdiff archive0000.tar archive0001.tar archive0001.jdf
jptch archive0000.tar archive0001.jdf archive0001b.tar

... ou com bsdiff . No entanto, isso exige que eu também mantenha um arquivo tar de todo o site no host, para permitir que os patches sejam aplicados de forma limpa a ele, e o espaço será problema aqui novamente.Também me forçaria a pedir ao webhost para permitir a instalação e uso de pelo menos as partes de correção das ferramentas; e isso pode valer a pena tentar novamente, se essas ferramentas também não exigirem que eu mantenha uma cópia adicional do site no host.

De qualquer forma, abaixo está o script que demonstra a extração de um git .bundle como uma diferença recursiva entre dois diretórios (ou melhor, duas versões do mesmo diretório); saída terminal relevante é incluída nos comentários:

#!/usr/bin/env bash

## comments with double ##; (relevant) terminal output with single #
## uses git, ImageMagick, tree

set -x

cd /tmp
rm -rf testdir export_compare
mkdir testdir
cd testdir
git init
  # Initialized empty Git repository in /tmp/testdir/.git/

git config user.name "test"
git config user.email "[email protected]"

## generate files - revision 1
## - text
cat /dev/urandom | tr -dc '[ -~]' | fold -w 80 -s | head -c 1024 > test_01.txt
mkdir subdir
cat /dev/urandom | tr -dc '[ -~]' | fold -w 80 -s | head -c 1024 > subdir/subtest_01.txt
cat /dev/urandom | tr -dc '[ -~]' | fold -w 80 -s | head -c 1024 > subdir/subtest_02.txt
## - binary
convert -depth 8 -size 200x150 xc:blue rgb:subdir/rgbimage.dat

## check:
## - files:
tree -s --dirsfirst .
  # .
  # ├── [       4096]  subdir
  # │   ├── [      90000]  rgbimage.dat
  # │   ├── [       1024]  subtest_01.txt
  # │   └── [       1024]  subtest_02.txt
  # └── [       1024]  test_01.txt
  #
  # 1 directory, 4 files
## - view image (press "q" to quit)
display -depth 8 -size 200x150 rgb:subdir/rgbimage.dat

git add *
git commit -m "initial commit"

## check usage
du -ba --max-depth=1 .
  # 1024    ./test_01.txt
  # 96144   ./subdir
  # 99947   ./.git
  # 201211  .

## change files - revision 2

## remove file:
REP="removed 1024;"
git rm subdir/subtest_02.txt

## add file
REP="$REP added 1024;"
cat /dev/urandom | tr -dc '[ -~]' | fold -w 80 -s | head -c 1024 > test_02.txt
git add test_02.txt

## change files:
## - text:
REP="$REP modified/added 19;"
echo "a new changed line" >> test_01.txt
## - binary
REP="$REP modified inline 1200"
convert -depth 8 -size 1x200 xc:red rgb:/dev/stdout | dd of=subdir/rgbimage.dat bs=1 seek=$((200*50*3)) count=$((200*3)) conv=notrunc
convert -depth 8 -size 1x200 xc:red rgb:/dev/stdout | dd of=subdir/rgbimage.dat bs=1 seek=$((200*100*3)) count=$((200*3)) conv=notrunc

## check:
## - files:
tree -s --dirsfirst .
  # .
  # ├── [       4096]  subdir
  # │   ├── [      90000]  rgbimage.dat
  # │   └── [       1024]  subtest_01.txt
  # ├── [       1043]  test_01.txt
  # └── [       1024]  test_02.txt
  #
  # 1 directory, 4 files
## - view image (press "q" to quit)
display -depth 8 -size 200x150 rgb:subdir/rgbimage.dat

git add *
git commit -m "second commit with changes"
  # [master 2b243fb] second commit with changes
  #  4 files changed, 16 insertions(+), 19 deletions(-) ...

## check usage
du -ba --max-depth=1 .
  # 1043    ./test_01.txt
  # 1024    ./test_02.txt
  # 95120   ./subdir
  # 123355  ./.git
  # 224638  .

## go back to parent dir (/tmp) and make a new directory for "clean" exports:
cd /tmp
mkdir export_compare
mkdir export_compare/testdir_new
mkdir export_compare/testdir_old
## from git, export each revision "cleanly"
cd testdir
git archive HEAD   | tar -x -C /tmp/export_compare/testdir_new
git archive HEAD^1 | tar -x -C /tmp/export_compare/testdir_old
## create git bundle, containing the changes between new and old revision
git bundle create ../commits_testdir.bundle HEAD HEAD^1
  # ... Writing objects: 100% (13/13), 4.30 KiB, done.
  # Total 13 (delta 2), reused 0 (delta 0)

## check
cd /tmp
echo $REP
  # removed 1024; added 1024; modified/added 19; modified inline 1200
du -b commits_testdir.bundle
  # 4470    commits_testdir.bundle
cd export_compare
du -bs testdir_old testdir_new
  # 101264  testdir_old
  # 101283  testdir_new
tree -s --dirsfirst .
  # .
  # ├── [       4096]  testdir_new
  # │   ├── [       4096]  subdir
  # │   │   ├── [      90000]  rgbimage.dat
  # │   │   └── [       1024]  subtest_01.txt
  # │   ├── [       1043]  test_01.txt
  # │   └── [       1024]  test_02.txt
  # └── [       4096]  testdir_old
  #     ├── [       4096]  subdir
  #     │   ├── [      90000]  rgbimage.dat
  #     │   ├── [       1024]  subtest_01.txt
  #     │   └── [       1024]  subtest_02.txt
  #     └── [       1024]  test_01.txt
  #
  # 4 directories, 8 files
  # + set +x

set +x
    
por sdaau 24.11.2013 / 00:05

0 respostas