Vraag Krijg binaire delta-gecodeerde recursieve diff van twee mappen als enkelvoudig patchbestand in CLI (en online gebruik)


In essentie ben ik op zoek naar een GNU / Linux-tool, die recursief kan herhalen via twee mappen, bestandsveranderingen / toevoegingen / verwijderingen kan vinden; en voor alle veranderde bestanden, output een diff. Dit kan al gedaan worden door diff efficiënt voor tekstbestanden, maar niet voor grote binaire bestanden - ik zou ook efficiënte "diffs" willen tussen binaire bestanden in de laatste patch (die, ik verzamel, staat bekend als Binaire delta compressie - Wikipedia als subset van Delta-codering - Wikipedia). Of, met andere woorden, doe iets zoals beschreven in deze "verlanglijstje" (uit CommandLineSyntax - xdelta - Google Project Hosting):

Het zou heel fijn zijn als xdelta meerdere patches met patches ondersteunt. Zoiets als:

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

Voor recursieve vergelijking van alle bestanden op map 1 en map 2 en voor het maken van één patchbestand voor alle bestanden. En:

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

Voor het toepassen van de patch op alle bestanden in folder1

Deze faciliteit bestaat niet, te oordelen naar Editie 21 - xdelta - Ondersteuning van recursieve directory diff - Google Project Hosting), hoewel er manieren zijn om rond te lopen: de probleempagina bevat verschillende suggesties voor script-wrappers, maar ik houd de dingen liever op zichzelf in één tool.

Het belangrijkste voor mij zou zijn het patchen van een "live" bestandssysteem-informatiedeel zoals hierboven getoond, vanwege mijn beoogde use-case - hieronder in meer detail beschreven en geïllustreerd met een bash script dat gebruikt git.


Ik zou graag een statische website op een cheapish Linux host / webfarm kunnen updaten, die alleen FTP-overdracht toestaat (dus nee rsync en dergelijke) met een vrij lage overdrachtssnelheid, en staat alleen PHP-scriptuitvoering toe. Meestal moet ik synchroniseren van local / client / home naar server / webhost, maar ik wil natuurlijk niet 200 MB uploaden elke keer dat ik een pagina wil bijwerken :)

ik zou kunnen gebruiken outlandishideas / sync · GitHub om de inhoud van de map te synchroniseren via HTTP met behulp van PHP, maar behalve dat alleen van server naar lokaal wordt gesynchroniseerd, worden ook alleen hele bestanden verzonden: "Er wordt geen poging gedaan om diffs te verzenden, dit is geen rsync". Op dezelfde manier zou ik kunnen gebruiken GNU FTPsync; het zou waarschijnlijk bestand kunnen aanmaken, wijzigen en verwijderen, maar het heeft hetzelfde probleem - alleen hele bestanden worden verzonden.

In principe, git kan ook worden gebruikt - het onderstaande script genereert mappen testdir_old en testdir_new, en laat dat zien git kan de verschillen tussen hen coderen (in dit geval wordt "1024 verwijderd; 1024 toegevoegd; gewijzigd / toegevoegd 19; gewijzigd inline 1200"; of totaal 3267 bytes aan verandering.) als een "sneakernet" git bundle bestandsgrootte van 4470 bytes. Maar zelfs als ik de host kon overhalen om te installeren git daarboven moest ik nog steeds een .git repo op de webhost om de bundel netjes toe te passen - en dat wil ik absoluut niet doen, omdat ik het extra gebruik van de bestandsgrootte niet kon missen; ook lijkt het dat grote binaire bestanden beheren met git - Stack Overflow vereist git annex of git bup.. En het plaatsen van een script zoals hieronder zou problematisch zijn omdat git zou elke keer opnieuw nieuwe revisiehechten maken, waardoor de bundel niet netjes zou kunnen worden toegepast.

Ook omdat ik in PHP blijkbaar "untar-gz zonder exec ()? - Stapel overloop", misschien is het de moeite waard om te proberen de wijzigingen in de directory te bepalen, en pak dan alleen de gewijzigde bestanden in a tar.gz, en stuur dat naar PHP script op de server, dat het zou uitpakken over de doelmap. Dit zou nog steeds hele bestanden verzenden, maar ze zouden in elk geval gecomprimeerd zijn - maar verwijderingen op de server zouden moeilijk te behandelen zijn.

Ten slotte suggereren de hulpprogramma's voor het omzetten van binaire bestanden dat de mappen kunnen worden ingepakt in een .tar(.gz) elk, en voer dan het hulpprogramma uit op die bestanden - bijv. (via ExternalCompression - xdelta - Google Project Hosting):

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

... waarschijnlijk ook uitvoerbaar met JojoDiff / jdiff

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

... of met bsdiff. Daarvoor moet ik echter ook een tar-archief van de hele site op de webhost bijhouden, zodat de patches er netjes op kunnen worden toegepast, en de ruimte is hier opnieuw een probleem. Het zou me ook dwingen de webhost te vragen om me de installatie en het gebruik van tenminste de patching-delen van de tools toe te staan; en dat is misschien de moeite waard om opnieuw te proberen, als die tools me ook niet zouden verplichten om een ​​extra tar'd-kopie van de site op de host te bewaren.

Anyways, hieronder is het script dat extractie van een laat zien git  .bundle als een recursieve diff tussen twee mappen (of liever, twee versies van dezelfde directory); relevante terminaluitvoer is opgenomen in de opmerkingen:

#!/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 "test@test.com"

## 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

10
2017-11-23 23:05


oorsprong


Linux beschouwt zelfs mappen als bestanden, dus als u een nieuwe map toevoegt, waar verschilt u deze dan mee? - gokul_uf
Bekijk [Tiger Tree hash] (en.wikipedia.org/wiki/Merkle_tree#Tiger_tree_hash) - gokul_uf


antwoorden: