После покупки нового домашнего компа захотелось поставить на него последнего
Сизифа. Spring2001 взлетел просто на ура (cusl2-c bp на i815ep), с работы
я принес свое зеркало Sisyphus'а, apt-get dist-upgrade и
можно считать, что жизнь удалась.
Прошло недели две, в Сизифе появилось много новых обновлений, но тащить опять домой полное дерево, да еще и на чужом винте не очень весело, тащить свой комп на работу тоже не хотелось. Остается диалап, но на 1200 мне пришлось бы обновляться лет триста. На работе есть CD-RW, к которой у меня неограниченный доступ, и 700-метровая RW болванка, на которую при всем желании не поместится четыре с половиной гига Сизифа.
Итак, учитывая, что Сизиф - не просто свалка файлов, а репозитарий пакетов,
и меня в основном интересуют только каталоги RPMS и SRPMS,
у меня получились такие исходные данные:
/var/ftp/pub/distributions/ALTLinux/{Sisyphus,updates,etc...}
base/* обновляются всегда. Для начала надо узнать, что конкретно находится дома, для этого я воспользовался такой командой:
$ tree -afin /var/ftp/pub/distributions/ALTLinux | grep ^/ | sort > home.list
После чего home.list был благополучно унесен на работу.
Выясним, что же у нас творится с Сизифом:
$ tree -afin /var/ftp/pub/distributions/ALTLinux | grep ^/ | sort > current.list
Теперь надо узнать, что появилось нового и что пропало старого. Для этого
вполне подойдет diff (так как патч мы никуда накладывать
не будем, зафиксируем только изменения):
$ diff -U0 home.list current.list > distrib.diff
В файле distrib.diff то, "старые" файлы идут с префиксом
'-', а "новые" - с префиксом "+". Рисуем простенький фильтр на перле:
#!/usr/bin/perl
open NEW, ">newfiles" or die;
open OLD, ">oldfiles" or die;
while(<>) {
chomp;
($w, $f) = ($_ =~ /(.)(\S+)/);
next if $w !~ /[+-]/;
next if $f !~ /^\//;
if ($w =~ /-/) {
print OLD $f."\n";
} else {
print NEW $f."\n";
}
}
close OLD;
close NEW;
... и скармливаем ему наш distrib.diff. Таким образом в
файле oldfiles у нас то, что надо дома удалить, а в newfiles
то, что надо тыда скопировать.
Копируем:
$ tar cPf updates.tar `cat newfiles`
... и base/*
$ tar cPf base.tar /var/ftp/pub/distributions/ALTLinux/Sisyphus/i586/Mandrake/base/*После чего updates.tar, base.tar и oldfiles записываются на болванку и благополучно уносятся домой.
Монтируем диск...
$ mount /mnt/cdrom $ cd /mnt/cdrom
... и рутом удаляем "старые файлы"...
$ su Password: # rm -f `cat oldfiles` # rm -f /var/ftp/pub/distributions/ALTLinux/Sisyphus/i586/Mandrake/base/*
... а потом копируем "новые":
# tar xPf updates.tar # tar xPf base.tar
После чего apt-get update && apt-get dist-upgrade и вуаля :-)
Юниксоиды - народ ленивый, им проще потратить два часа на написание скрипта, который за две минуты сделает получасовую работу.
Все-таки, что делать, если мы хотим точное зеркало, причем неизвестно,
сколько у нас разных base/*? Возьмем вместо tree...
find и md5sum:
$ find /var/ftp/pub/distributions/ALTLinux -type f -print | sort | xargs md5sum > home.list
... это дома...
$ find /var/ftp/pub/distributions/ALTLinux -type f -print | sort | xargs md5sum > current.list
... а это на работе. И соответственно изменим genlists.pl:
- ($w, $f) = ($_ =~ /(.)(\S+)/);
+ ($w, $f) = ($_ =~ /(.)[0-9a-f]{32}\s+(\S+)/);
таким образом у нас получилась "оффлайновая версия" rsync :-)
Вот за что я люблю *никс, так это за длинные команды с кучей пайпов :-)
"На работе" вместо создания current.list перенаправим вывод find сразу
на diff, с diff'а на наш скрипт genlists (в виде perl -e ''
:-), в скрипте вместо создания newfiles будем печатать их на stdout и
отдадим сразу tar'у.
А чтобы "дома" не создавать файллист руками, добавим в скрипт парочку command-line параметров :-)
#!/bin/sh
Usage() {
cat <<EOF
Usage: ${0##*/} --genlist|--genupdate FILE DIR
--genlist will list DIR to FILE
--genupdate will make rmold.sh and updates.tar based on FILE
containing filelist and local DIR
EOF
exit $1
}
if [ ! $# -eq 3 ]; then
Usage 1 1>&2
fi
file=""
dir=""
what=""
case "$1" in
--genlist)
what="list";
shift
;;
--genupdate)
what="update";
shift
;;
*)
Usage 1 1>&2
;;
esac
file="$1"
dir="$2"
case $what in
list)
find "$dir" -type f -print | \
sort | \
xargs md5sum > "$file"
;;
update)
find /var/ftp/pub/distributions/ALTLinux -type f -print | \
sort | \
xargs md5sum | \
diff -U0 "$file" - | \
perl -e '
open OLD, ">rmold.sh" or die;
print OLD "#!/bin/sh\n";
while(<>) {
chomp;
($w, $f) = ($_ =~ /(.)[0-9a-f]{32}\s+(\S+)/);
next if $w !~ /[+-]/;
if ($w =~ /-/) {
print OLD "rm -f ".$f."\n";
} else {
print $f."\n";
}
}
close OLD;
' | \
tar cPf update.tar -T -
;;
esac
Ну а если мы хотим совсем универсальный скрипт для "оффлайнового
rsync'а", то после xargs md5sum можно воткнуть sed
-e 's# $dir# #', но это уже будет домашним заданием :-)