[devel] #! shebang fixer
Alexey Tourbin
=?iso-8859-1?q?at_=CE=C1_altlinux=2Eru?=
Пн Сен 10 03:48:27 MSD 2007
On Mon, Sep 10, 2007 at 02:27:11AM +0300, Led wrote:
> > Этот пакет содержит некоторое количество tcl скриптов.
> > $ rpmfile /ALT/Sisyphus/files/noarch/RPMS/TclTutor-2.0-alt0.2.noarch.rpm |grep tcl
> > /usr/bin/TclTutor.tcl 100755 Bourne shell script text executable
> > /usr/bin/tcltutor 120777 symbolic link to `TclTutor.tcl'
> > /usr/share/TclTutor/htmllib.tcl 100644 Bourne shell script text executable
> > /usr/share/TclTutor/scaler.tcl 100644 ASCII English text
> > $
> >
> > Эти скрипты, по-видимому, не требуют никаких tcl пакетов.
>
> Там вот такое:
> $ head -3 /usr/bin/TclTutor.tcl
> #!/bin/sh
> # \
> exec wish "$0" "$@"
>
> Наветное, имеет смысл заменить на явное
> #!/usr/bin/wish
> ?
Здесь есть два подхода.
Во-первых, можно написать shebang fixer. То есть чтобы на стадии fixup,
перед поиском зависимостей, совершенно автоматически выправлять все
кривые шебанги. Но этот фиксер будет эвристическим, и если он
облажается, то это будет пшик и автору фиксера дадут подзатыльник.
Подумайте: на самом деле придётся писать full-fledged шелл-парсер.
Ведь "$0" "$@" это простейший вариант, а любая менее тривиальная
манипуляция с аргументами может ввести фиксер в глубокий ступор.
В лучшем случае он просто ничего не зафиксит. А в худшем случае
зафиксит так что мало не покажется.
Кроме того, есть такие случаи, которые зафиксить принципиально нельзя,
и которые, вместе с тем, имеют свой глубокий смысл.
$ head -3 /usr/lib/rpm/tcl.req
#!/bin/sh
# -*- tcl -*- \
exec ${RPM_TCLSH:-/usr/bin/tclsh} "$0" "$@"
$
Поэтому я решил, что можно реализовать менее навязчивые варианты.
В частности, в новом rpm-build уже реализовано распознавание
/usr/bin/env для всех типичных случаев. В частности,
релевантная часть анализатора шебанга (shebang.req) выглядит так:
local f="$1" line=; shift
line=$(sed -n '1s|^#![[:space:]]*/|/|p' "$f")
[ -n "$line" ] || return 0
set -- $line
case "$#,$1" in
2,/usr/bin/env)
FindPackage "$f" "$1" "$2" ;;
*)
FindPackage "$f" "$1" ;;
esac
То есть скрыть зависимость на интерпретатор через /usr/bin/env
в типичном случае (если всего один аргумент у env) уже нельзя.
Теперь только остаётся придумать, что делать с re-exec'ом.
В принципе, подход тоже есть, он реализован в shell.req:
if ! reqs="$($sh --rpm-requires "$f")"; then
# sh --rpm-requires failed, and stderr is already there.
# We are almost dead. The last chance to escape is to see
# if the shell is used only to re-exec another interpreter, e.g.
# exec tclsh "$0" "$@"
if line1=$(egrep -m1 -v '^[[:space:]]*(#|$)' "$f"); then
set -- $line1
if [ $# -gt 1 ] && [ "$1" = exec ]; then
Info "$f is $2 script!"
FindPackage "$f" "$2"
return 0
fi
fi
Fatal "$f: $sh --rpm-requires failed"
fi
Проблема тут в том, что этот код нельзя сделать вполне универсальным,
то есть реализовать на его основе диспетчерезацию на другой тип
зависимостей. Но можно просто вставить аналогичный код в tcl.req.files.
Кажется, это единственный язык, который в котором любят делать
шебанг-хак через re-exec в первой значащей строчке.
----------- следующая часть -----------
Было удалено вложение не в текстовом формате...
Имя : =?iso-8859-1?q?=CF=D4=D3=D5=D4=D3=D4=D7=D5=C5=D4?=
Тип : application/pgp-signature
Размер : 189 байтов
Описание: =?iso-8859-1?q?=CF=D4=D3=D5=D4=D3=D4=D7=D5=C5=D4?=
Url : <http://lists.altlinux.org/pipermail/devel/attachments/20070910/3989cdb2/attachment-0002.bin>
Подробная информация о списке рассылки Devel