Получите двоичный рекурсивный diff двух кодированных различий двух каталогов в виде одного файла исправления в CLI (и онлайн-использование)

По сути, я ищу инструмент GNU / Linux, который мог бы рекурсивно перебирать две директории, находить изменения / добавления / удаления файлов; и для всех измененных файлов выведите diff. Это уже может быть эффективно выполнено в diff для текстовых файлов, но не для больших двоичных файлов - я хотел бы также сделать эффективные "различия" между двоичными файлами, включенными в финальный патч (который, я так понимаю, известен как Binary). дельта-сжатие - Википедия как подмножество Дельта-кодирование - Википедия ). Или, другими словами, сделайте что-то подобное описанному в этом комментарии к списку пожеланий (из CommandLineSyntax - xdelta - Хостинг проектов Google ):

Было бы очень хорошо, если бы поддерживалась xdelta исправление нескольких файлов. Что-то вроде:

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

Для рекурсивного сравнения всех файлов в folder1 и folder2 и создания единого файла патча для всех них. И:

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

Для применения исправления ко всем файлам, содержащимся в папке 1

Эта возможность не существует, судя по Выпуск 21 - xdelta - рекурсивная поддержка различий в каталогах - хостинг Google Project ), хотя есть способы обойти: на странице выпуска есть несколько предложений для оболочек сценариев, но я бы предпочел, чтобы все было автономно в одном инструменте.

Самым важным для меня было бы исправление «живой» части каталога файловой системы, как показано выше, из-за моего предполагаемого варианта использования - описанного более подробно ниже и проиллюстрированного с помощью скрипта bash, который использует git. [тысяча сто сорок пять]


Я бы хотел иметь возможность обновлять статический веб-сайт на дешевом хосте / веб-ферме Linux, который позволяет передавать только по FTP (поэтому нет rsync и т. п.) с довольно низкой скоростью передачи и позволяет только Выполнение PHP-скрипта. Обычно мне нужно синхронизировать данные с локального / клиентского / домашнего на сервер / веб-хостинг, но, конечно, я не хочу загружать 200 МБ каждый раз, когда хочу обновить страницу :)

Я мог бы использовать outlandishideas / sync · GitHub для «Синхронизации содержимого каталога по HTTP с использованием PHP», но кроме синхронизации только с сервера на локальный, отправляются только целые файлы: «Не делается попытка отправки различий; это не rsync ». Точно так же я мог бы использовать GNU FTPsync ; он, вероятно, может обрабатывать создание, изменение и удаление файлов, но имеет ту же проблему - будут отправлены только целые файлы.

В принципе, можно использовать и git - приведенный ниже скрипт генерирует каталоги testdir_old и testdir_new и показывает, что git может кодировать различия между ними (в данном случае «удалено 1024; добавлено 1024; изменено / добавлено 19; изменено inline 1200», или всего 3267 байт изменения ) в виде файла git bundle «sneakernet» размером 4470 байт. Но даже если бы я мог убедить хост установить там git, мне все равно пришлось бы поддерживать репо .git на веб-хосте, чтобы пакет корректно применялся - и я определенно не хочу этого делать, так как Я не мог сэкономить дополнительное использование размера файла; также, похоже, что для управления большими двоичными файлами с помощью git - Переполнение стека требует git annex или git bup. А создание сценария, подобного приведенному ниже, будет проблематичным, поскольку git будет воссоздавать новые хэши ревизий каждый время, делая пакет не применять чисто.

Кроме того, поскольку в PHP я, по-видимому, могу « untar-gz без exec ()? - переполнение стека », возможно, стоит попытаться определить изменения в каталоге, затем упаковать только измененные файлы в tar.gz, и отправьте это PHP-скрипту на сервере, который распакует его в целевой каталог. Это все равно отправит целые файлы, но, по крайней мере, они будут сжаты - но с удалением на сервере будет сложно справиться.

Наконец, утилиты сравнения двоичных файлов предполагают, что можно упаковать каталоги в .tar(.gz) каждый, а затем запустить утилиту для этих файлов - например, (через ExternalCompression - xdelta - Хостинг проектов Google ):

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

... возможно, также можно выполнить с JojoDiff / jdiff

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

... или с bsdiff . Однако для этого требуется, чтобы я также содержал tar-архив всего сайта на веб-хосте, чтобы позволить патчам корректно применять его, и здесь снова возникает проблема. Это также вынудило бы меня попросить веб-хоста разрешить мне установку и использование хотя бы частей исправлений инструментов; и это может стоить попробовать еще раз, если эти инструменты также не потребуют от меня сохранения дополнительной tar-копии сайта на хосте.

В любом случае, ниже приведен скрипт, который демонстрирует извлечение git .bundle в виде рекурсивного diff между двумя каталогами (или, скорее, двумя версиями одного и того же каталога); соответствующий вывод терминала включен в комментарии:

#!/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
16
задан 23 May 2017 в 15:39

1 ответ

Я бы выбрал сдержанное решение.Если я вас правильно понимаю, вы хотите обновить веб-страницы и не ожидаете, что большинство из них изменится, и в этом случае я просто загружу измененные файлы целиком.

Это может быть достигнуто, например. в mc подключите одну панель через FTP к вашему веб-хосту, пусть другая панель покажет локальную версию. Затем выберите все и скопируйте и выберите перезапись только всех новых файлов (вы можете выбрать это для всех файлов сразу). Или используйте средство синхронизации другого файлового менеджера, я думаю, у krusader оно есть. Если у вас нет больших файлов, которые изменяются только локально (что это такое? базы данных1? может исполняемые файлы, но не сжатые?), бинарные дельты не дадут вам много IMO.

ПРИМЕЧАНИЕ 1. Синхронизация баз данных таким образом — плохая идея.

0
ответ дан 6 May 2020 в 17:07

Другие вопросы по тегам:

Похожие вопросы: