Назад | Перейти на главную страницу

Почему tar flag --strip-components иногда игнорируется?

У меня есть автоматизированная сборка образов докеров, где я загружаю архив elasticsearch и извлекаю его через:

tar zxf archive.tar.gz --strip-components=1 -C /path/to/dir

И это всегда работало до последних выпусков (6.8.5 и 7.4.2). Он больше не работает в 6.8.5, что означает флаг --strip-components больше не действует. Однако он отлично работает для 7.4.2. После сравнения этих двух архивов единственная разница, которую я обнаружил, заключается в том, что 6.8.5 имеет другое право собственности на файлы в архиве - 631:503 против root:root в 7.4.2. Однако, если это была проблема, флаги --no-same-owner или --user должен был решить проблему, но они этого не сделали. Я даже создал пользователя / группу с этими идентификаторами и извлек архив под этим пользователем, но это тоже не повлияло.

Вот как вы можете воспроизвести (замените 6.8.5 на 7.4.2, чтобы попробовать оба):

$ docker run --rm -ti alpine:3.10.3 sh

### from the container

$ wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-6.8.5.tar.gz
$ apk add --update tar
$ mkdir elastic
$ tar zxvf elasticsearch-6.8.5.tar.gz --strip-components=1 -C elastic
$ ls -la elastic

В 6.8.5 вы получите промежуточный каталог, который не был удален, в 7.4.2 вы его не увидите, хотя он существует в обоих архивах.

Как вы могли заметить, я не использую tar из musl я использовал версию GNU из пакетов alpine (версия 1.32), которая существует уже несколько месяцев. Я использую этот пакет с теми же флагами во многих других сборках, и у меня он отлично работает.

Как это было объяснил для меня сотрудником Elastic на github это происходит из-за ведущего ./ по путям внутри архива:

/ # tar tvf elasticsearch-6.8.5.tar.gz --numeric-owner | head -n 2
drwxr-xr-x 631/503           0 2019-11-14 14:20 ./
drwxr-xr-x 631/503           0 2019-11-13 20:07 ./elasticsearch-6.8.5/

Итак, в этом случае --strip-components должно быть 2, а не 1. Чтобы справиться с подобными ситуациями повсеместно, вы можете перечислить архив перед извлечением, и если он ./ вы можете динамически изменять --strip-components количество:

$ if tar tf elasticsearch-6.8.5.tar.gz | head -n 1 | grep -q '^./$'; then STRIP_COMPONENTS_COUNT=2; else STRIP_COMPONENTS_COUNT=1; fi
$ tar zxvf elasticsearch-6.8.5.tar.gz --strip-components=$STRIP_COMPONENTS_COUNT -C elastic

Но, честно говоря, хорошие архивы надо создавать без всяких ./ что очень сбивает с толку, потому что, если вы не перечислите файлы в архиве, вы не заметите никакой разницы.