Введение
Есть большое желание использовать свой любимый Ubuntu там, где интернет слишком дорог или его вообще нет? У меня есть такое желание и оно начинает обостряться в связи со скорым выходом Ubuntu 7.10. На работе у меня с Интернетом довольно туго, поэтому когда я пол года назад ставил там себе Ubuntu 7.04, я сделал копию всего репозитория и принес на работу, после чего получил возможность быстро и, не тратя ни килобайта Интернет трафика, устанавливать любой пакет, имеющийся в репозитории Ubuntu 7.04. Единственный недостаток такого подхода - размер репозитория. Когда я выкачивал его для 7.04, я скачивал все бинарные пакеты. Результат - свыше 20000 пакетов и 16 Гб места на диске. Но, думаю, с сегодняшними объемами жестких дисков 16 Гб под такую полезную вещь может позволить себе практически каждый.
Так вот чтобы создать локальный репозиторий для Ubuntu 7.10, я решил написать скрипт для выкачивания всех необходимых пакетов и выложить его сюда, т. к. данный скрипт может кому-нибудь пригодиться.
Сразу скажу, что при написании скрипта я не ставил перед собой задачу предусмотреть и обработать все возможные ошибки при его работе, что практически не нужно и только увеличило бы его объем в несколько раз и отняло бы у меня солидную часть свободного времени. Например, если в /etc/apt/sources.list кроме обычных адресов вида http://... и ftp://... встретится что-нибудь вроде cdrom://..., то скрипт предупредит об ошибке, но сработает нормально.
Кратко опишу, что делает данный скрипт (а точнее их три):
Первый - get_lists просматривает /etc/apt/sources.list, в котором содержится список используемых вами репозиториев, скачивает необходимые файлы, содержащие информацию о всех пакетах в репозитории и составляет файл с URL'ами на данные пакеты.
Второй - get_packages просматривает полученный список URL'ов и скачивает их wget'ом.
Третий - create_repository формирует на основе скачанных пакетов репозиторий.
Так как объем скачиваемых файлов велик, я сделал так, что если вы прервете работу get_packages, а потом запустите снова, то он продолжит скачивание с того пакета, на котором остановился в прошлый раз.
Примечание 1: по умолчанию скрипт выкачивает пакеты с архитектурой i386. Если вы используете 64-битную версию Ununtu, то вам следует в файле get_lists исправить строку
dist_arch="i386"на
dist_arch="amd64"
Примечание 2: то, что в данной статье я пока что упоминал только Ubuntu, не означает, что мой скрипт будет работать только под этим дистрибутивом. Он будет без проблем работать со всеми дистрибутивами, использующими apt-get и deb пакеты. Для дистрибутивов, которые используют apt-get и RPM, данный скрипт не подойдет, но "заточить" под них будет очень легко - буквально надо будет изменить несколько строк.
Создание репозитория
Ну а теперь, пожалуй, перейдем к действию. Покажу, как с помощью моих скриптов создать себе локальный репозиторий. Предположим, что мы хотим, чтобы наш будущий репозиторий лежал в папке ./repository. Запускаем последовательно все три скрипта:
$ ./get_lists ./repository Получаем списки пакетов... http://archive.ubuntu.com/ubuntu/dists/feisty/main/binary-i386/Packages.gz [OK] http://archive.ubuntu.com/ubuntu/dists/feisty/universe/binary-i386/Packages.gz [OK] http://archive.ubuntu.com/ubuntu/dists/feisty/restricted/binary-i386/Packages.gz [OK] http://archive.ubuntu.com/ubuntu/dists/feisty/multiverse/binary-i386/Packages.gz [OK] http://security.ubuntu.com/ubuntu/dists/feisty-security/universe/binary-i386/Packages.gz [OK] http://security.ubuntu.com/ubuntu/dists/feisty-security/main/binary-i386/Packages.gz [OK] http://security.ubuntu.com/ubuntu/dists/feisty-security/multiverse/binary-i386/Packages.gz [OK] http://security.ubuntu.com/ubuntu/dists/feisty-security/restricted/binary-i386/Packages.gz [OK] http://archive.ubuntu.com/ubuntu/dists/feisty-updates/universe/binary-i386/Packages.gz [OK] http://archive.ubuntu.com/ubuntu/dists/feisty-updates/main/binary-i386/Packages.gz [OK] http://archive.ubuntu.com/ubuntu/dists/feisty-updates/multiverse/binary-i386/Packages.gz [OK] http://archive.ubuntu.com/ubuntu/dists/feisty-updates/restricted/binary-i386/Packages.gz [OK] http://archive.ubuntu.com/ubuntu/dists/feisty-proposed/universe/binary-i386/Packages.gz [OK] http://archive.ubuntu.com/ubuntu/dists/feisty-proposed/main/binary-i386/Packages.gz [OK] http://archive.ubuntu.com/ubuntu/dists/feisty-proposed/multiverse/binary-i386/Packages.gz [OK] http://archive.ubuntu.com/ubuntu/dists/feisty-proposed/restricted/binary-i386/Packages.gz [OK] http://archive.ubuntu.com/ubuntu/dists/feisty-backports/universe/binary-i386/Packages.gz [OK] http://archive.ubuntu.com/ubuntu/dists/feisty-backports/main/binary-i386/Packages.gz [OK] http://archive.ubuntu.com/ubuntu/dists/feisty-backports/multiverse/binary-i386/Packages.gz [OK] http://archive.ubuntu.com/ubuntu/dists/feisty-backports/restricted/binary-i386/Packages.gz [OK] Списки пакетов получены успешно $ ./get_packages ./repository Скачиваем пакеты... http://security.ubuntu.com/ubuntu/pool/universe/a/aircrack-ng/aircrack_0.6.2-7ubuntu1.1_all.deb [OK] http://security.ubuntu.com/ubuntu/pool/universe/a/aircrack-ng/aircrack-ng_0.6.2-7ubuntu1.1_i386.deb [OK] http://security.ubuntu.com/ubuntu/pool/universe/a/apache2-mpm-itk/apache2-mpm-itk_2.2.3-01-1build1.1_i386.deb [OK] http://security.ubuntu.com/ubuntu/pool/universe/a/asterisk/asterisk_1.2.16~dfsg-1ubuntu3.1_all.deb [OK] http://security.ubuntu.com/ubuntu/pool/universe/a/asterisk/asterisk-bristuff_1.2.16~dfsg-1ubuntu3.1_i386.deb [OK] http://security.ubuntu.com/ubuntu/pool/universe/a/asterisk/asterisk-classic_1.2.16~dfsg-1ubuntu3.1_i386.deb [OK] http://security.ubuntu.com/ubuntu/pool/universe/a/asterisk/asterisk-config_1.2.16~dfsg-1ubuntu3.1_all.deb [OK] http://security.ubuntu.com/ubuntu/pool/universe/a/asterisk/asterisk-dev_1.2.16~dfsg-1ubuntu3.1_all.deb [OK] http://security.ubuntu.com/ubuntu/pool/universe/a/asterisk/asterisk-doc_1.2.16~dfsg-1ubuntu3.1_all.deb [OK] http://security.ubuntu.com/ubuntu/pool/universe/a/asterisk/asterisk-h323_1.2.16~dfsg-1ubuntu3.1_i386.deb [OK] http://security.ubuntu.com/ubuntu/pool/universe/a/asterisk/asterisk-sounds-main_1.2.16~dfsg-1ubuntu3.1_all.deb [OK] http://security.ubuntu.com/ubuntu/pool/universe/a/asterisk/asterisk-web-vmail_1.2.16~dfsg-1ubuntu3.1_all.deb [OK] . . . . . http://archive.ubuntu.com/ubuntu/pool/main/z/zsh/zsh_4.3.2-25ubuntu1_i386.deb [OK] http://archive.ubuntu.com/ubuntu/pool/main/z/zsh/zsh-dbg_4.3.2-25ubuntu1_i386.deb [OK] http://archive.ubuntu.com/ubuntu/pool/main/z/zsh/zsh-dev_4.3.2-25ubuntu1_i386.deb [OK] http://archive.ubuntu.com/ubuntu/pool/main/z/zsh/zsh-doc_4.3.2-25ubuntu1_all.deb [OK] Все необходимые пакеты скачаны. $ ./create_repository ./repository Репозиторий создан.
Все, теперь запасаемся болванками, записываем на них папку ./repository и несем на компьютер, до которого еще не дошла цивилизация в лице безлимитного интернета.
На этом компьютере кладем папку repository, например, в /home/user/repository и в /etc/apt/sources.list прописываем следующую строку:
deb file:/home/user/repository ./выполняем
# apt-get updateИ с радостью пользуемся собственным репозиторием.
Обновление репозитория
Теперь переходим к следующему моменту: допустим вам мало просто репозитория - вы хотите его еще и регулярно обновлять. Нет проблем! Если вы заметили, то в нашей папке ./repository после создания репозитория появился файл Packages.list. Это список всех пакетов в вашем репозитории. Так вот допустим, что сегодня утром вы проснулись и у вас появилась твердая мысль обновить ранее созданный репозиторий. :) Вот что вам нужно сделать:
- Cоздайте на своем компьютере уже знакомую нам папку ./repository
- Заберите из ранее созданного репозитория файл Packages.list и киньте его в ./repository.
- Запустите
$ ./get_lists ./repository $ ./get_packages ./repository
Тем самым вы скачаете все новые пакеты, которые появились с того момента, когда вы создавали свой репозиторий (скрипт смотрит в Packages.list, какие пакеты уже есть в репозитории и скачивает все кроме них.
Теперь закатывайте ./repository на болванку, несите на компьютер с уже устаревшим репозиторием и копируйте все файлы и папки из ./repository в папку со старым репозиторием с заменой файлов с одинаковыми именами.
Далее запустите create_repository передав ему в качестве аргумента путь к папке в которой лежит теперь уже обновленный репозиторий.
$ ./create_repository /home/user/repository
Теперь в вашем репозитории будут доступны все новые пакеты.
Вот, собственно и все. Желаю успехов.
get_lists:
#!/bin/bash #*************************************************************************** #* Copyright (C) 2007, Konishchev Dmitry * #* http://konishchevdmitry.blogspot.com/ * #* * #* This program is free software; you can redistribute it and/or modify * #* it under the terms of the GNU General Public License as published by * #* the Free Software Foundation; either version 3 of the License, or * #* (at your option) any later version. * #* * #* This program is distributed in the hope that it will be useful, * #* but WITHOUT ANY WARRANTY; without even the implied warranty of * #* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * #* GNU General Public License for more details. * #**************************************************************************/ dist_arch="i386" # Удаление всех файлов, созданных скриптом cleanup() { if [ -e "$repository_dir/temp_list.gz" ] then rm "$repository_dir/temp_list.gz" fi if [ -e "$repository_dir/packages_list" ] then rm "$repository_dir/packages_list" fi } # Аварийное завершение работы при ошибках die() { echo "Ошибка!" cleanup exit 1 } # Проверка "исходных данных" и создание необходимых файлов и папок --> if [ "$1" == "" ] then echo "Исспользование: get_lists /path/to/repository" exit 1 fi repository_dir="$1" mkdir -p "$repository_dir" || exit 1 echo -n '' > "$repository_dir/packages_list" || die # Проверка "исходных данных" и создание необходимых файлов и папок <-- # Получаем из /etc/apt/sources.list всю необходимую информацию --> packages_lists=`egrep '^deb ' /etc/apt/sources.list \ | sed 's/#.*//' \ | awk '{ for(i = 0; i < NF - 3; i++) printf "%sdists/%s/%s/%s/Packages.gz\n", $2, $3, $(4 + i), "binary-'"$dist_arch"'"; }'` packages_base_addresses=`egrep '^deb ' /etc/apt/sources.list \ | sed 's/#.*//' \ | awk '{ print $2; }'` # Получаем из /etc/apt/sources.list всю необходимую информацию <-- # Скачиваем все необходимые списки пакетов и выдираем из них URL'ы на пакеты --> echo "Получаем списки пакетов..." is_wget_error=0 counter=0 for url in $packages_lists do ((counter++)) # Удаляем прошлый скачанный файл --> if [ -e "$repository_dir/temp_list.gz" ] then rm "$repository_dir/temp_list.gz" || die fi # Удаляем прошлый скачанный файл <-- # Скачиваем и обрабатываем очередной список пакетов --> echo -n $url wget --quiet -O "$repository_dir/temp_list.gz" $url if [ $? -ne 0 ] then is_wget_error=1 echo ' [ERROR]' else echo ' [OK]' # Получаем "базовый" адрес для списка пакетов --> i=1 for base_address in $packages_base_addresses do if [ $i -eq $counter ] then break; fi done # Получаем "базовый" адрес для списка пакетов <-- # Получаем список URL'ов на пакеты из скачанного списка --> gzip --decompress --stdout "$repository_dir/temp_list.gz" \ | awk '{ if($1 == "Filename:") printf "%s%s\n", "'"$base_address"'", $2; }' \ >> "$repository_dir/packages_list" # Получаем список URL'ов на пакеты из скачанного списка <-- fi # Скачиваем и обрабатываем очередной список пакетов <-- done # Чистим за собой --> if [ -e "$repository_dir/temp_list.gz" ] then rm "$repository_dir/temp_list.gz" || die fi # Чистим за собой <-- # Проверяем, были ли ошибки при скачивании списков пакетов --> if [ $counter -eq 0 ] then echo -e "\nНе удалось прочитать ни одного списка пакетов из /etc/apt/sources.list." die fi if [ $is_wget_error -eq 0 ] then echo -e "\nСписки пакетов получены успешно" else echo -e "\nПри получении списков пакетов произошли ошибки." fi # Проверяем, были ли ошибки при скачивании списков пакетов <-- # Скачиваем все необходимые списки пакетов и выдираем из них URL'ы на пакеты -->
get_packages:
#!/bin/bash #*************************************************************************** #* Copyright (C) 2007, Konishchev Dmitry * #* http://konishchevdmitry.blogspot.com/ * #* * #* This program is free software; you can redistribute it and/or modify * #* it under the terms of the GNU General Public License as published by * #* the Free Software Foundation; either version 3 of the License, or * #* (at your option) any later version. * #* * #* This program is distributed in the hope that it will be useful, * #* but WITHOUT ANY WARRANTY; without even the implied warranty of * #* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * #* GNU General Public License for more details. * #**************************************************************************/ # Проверка "исходных данных" --> if [ "$1" == "" ] then echo "Исспользование: get_packages /path/to/repository" exit 1 fi repository_dir="$1" if [ ! -e "$repository_dir" ] then echo "Ошибка! Дирректории \"$repository_dir\" не существует." exit 1 fi if [ ! -e "$repository_dir/packages_list" ] then echo "Ошибка! Файла \"$repository_dir/packages_list\" не существует. Перед запуском get_packages вам необходимо запустить скрипт get_lists." exit 1 fi # Проверка "исходных данных" <-- # Скачиваем все пакеты --> echo "Скачиваем пакеты..." urls=`cat "$repository_dir/packages_list"` for url in $urls do # Проверяем, есть ли у нас уже этот пакет в репозитории --> is_downloaded=0 if [ -e "$repository_dir/Packages.list" ] then if grep "$url" "$repository_dir/Packages.list" > /dev/null then is_downloaded=1 fi fi # Проверяем, есть ли у нас уже этот пакет в репозитории <-- # Скачиваем пакет if [ $is_downloaded -eq 0 ] then wget_result=1 while [ $wget_result -ne 0 ] do echo -n $url wget_output=`wget --timestamping --no-verbose --directory-prefix="$repository_dir" --no-host-directories --force-directories $url 2>&1` wget_result=$? if [ $wget_result -ne 0 ] then echo ' [ERROR]' echo $wget_output echo "Через 5 секунд произойдет повторная попытка..." sleep 5 else echo ' [OK]' fi done echo $url >> "$repository_dir/Packages.list" || exit 1 # Пропускаем пакет else echo "$url [ALREADY IN REPOSITORY]" fi done # Скачиваем все пакеты <-- echo -e "\nВсе необходимые пакеты скачаны." # Чистим за собой rm "$repository_dir/packages_list" || exit 1
create_repository:
#!/bin/bash #*************************************************************************** #* Copyright (C) 2007, Konishchev Dmitry * #* http://konishchevdmitry.blogspot.com/ * #* * #* This program is free software; you can redistribute it and/or modify * #* it under the terms of the GNU General Public License as published by * #* the Free Software Foundation; either version 3 of the License, or * #* (at your option) any later version. * #* * #* This program is distributed in the hope that it will be useful, * #* but WITHOUT ANY WARRANTY; without even the implied warranty of * #* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * #* GNU General Public License for more details. * #**************************************************************************/ tmp_file="/tmp/create_repository_$$" # Проверка "исходных данных" --> if [ "$1" == "" ] then echo "Исспользование: create_repository /path/to/repository" exit 1 fi repository_dir="$1" if [ ! -e "$repository_dir" ] then echo "Ошибка! Дирректории \"$repository_dir\" не существует." exit 1 fi # Проверка "исходных данных" <-- # Создаем репозиторий --> cd "$repository_dir" || exit 1 dpkg-scanpackages . /dev/null 2> $tmp_file | gzip -9c > Packages.gz if [ $? -eq 0 ] then echo "Репозиторий создан." else echo "Произошла ошибка при создании репозитория." cat $tmp_file exit 1 fi if [ -e $tmp_file ] then rm $tmp_file || exit 1 fi # Создаем репозиторий <--
8 комментариев:
А как выбрать нужные мне секции?
Допустим, мне нужно только main и univere, а restricted и multiverse мне не нужно?
А ещё - как выбрать нужную мне версию, например, gutsy или hardy?
Кроме того, какие адреса посоветуете для обновления? (updates, security и т.д.)
Из предыдущего выпадает вопрос - а как выбрать, например, gutsy,gutsy-updates,gutsy-security и т.д.?
Скрипт читает /etc/apt/sources.list и выкачивает описанные там репозитории (только по http). Соответственно, вам необходимо сформировать такой /etc/apt/sources.list, который соответствовал бы вашим требованиям.
Адреса посоветую те, которые по умолчанию установлены в дистрибутиве. :)
спасибо! грамотный скрипт. очень выручил.
я так и не понял
запускаю скрипты а они ничего не делают
не могли бы вы обьяснить куда их положить в какую папку и какую папку создать
я полный нуб ))
Анонимный, только что выкачал часть репозитория - все работает.
/etc/apt/sources.list у меня содержал следующую строку:
deb http://archive.ubuntu.com/ubuntu/ gutsy main universe restricted multiverse
Вот список команд, которые я выполнял:
/my_files/temp$ mkdir test
/my_files/temp$ cd test/
/my_files/temp/test$ mkdir repository
/my_files/temp/test$ /my_files/just4fun/scripts/my_create_local_repository/get_lists repository/
Получаем списки пакетов...
http://archive.ubuntu.com/ubuntu/dists/gutsy/main/binary-i386/Packages.gz [OK]
http://archive.ubuntu.com/ubuntu/dists/gutsy/universe/binary-i386/Packages.gz [OK]
http://archive.ubuntu.com/ubuntu/dists/gutsy/restricted/binary-i386/Packages.gz [OK]
http://archive.ubuntu.com/ubuntu/dists/gutsy/multiverse/binary-i386/Packages.gz [OK]
Списки пакетов получены успешно
/my_files/temp/test$ /my_files/just4fun/scripts/my_create_local_repository/get_packages repository/
Скачиваем пакеты...
http://archive.ubuntu.com/ubuntu/pool/main/a/abiword/abiword_2.4.6-2ubuntu2_i386.deb [OK]
http://archive.ubuntu.com/ubuntu/pool/main/a/abiword/abiword-common_2.4.6-2ubuntu2_all.deb [OK]
http://archive.ubuntu.com/ubuntu/pool/main/a/abiword/abiword-gnome_2.4.6-2ubuntu2_i386.deb [OK]
http://archive.ubuntu.com/ubuntu/pool/main/a/abiword/abiword-help_2.4.6-2ubuntu2_all.deb [OK]
http://archive.ubuntu.com/ubuntu/pool/main/a/abiword/abiword-plugins_2.4.6-2ubuntu2_i386.deb [OK]
http://archive.ubuntu.com/ubuntu/pool/main/a/abiword/abiword-plugins-gnome_2.4.6-2ubuntu2_i386.deb [OK]
http://archive.ubuntu.com/ubuntu/pool/main/a/acct/acct_6.4~pre1-4ubuntu1_i386.deb [OK]
http://archive.ubuntu.com/ubuntu/pool/main/a/acpi/acpi_0.09-3ubuntu1_i386.deb [OK]
http://archive.ubuntu.com/ubuntu/pool/main/a/acpi-support/acpi-support_0.103_i386.deb [OK]
http://archive.ubuntu.com/ubuntu/pool/main/a/acpid/acpid_1.0.4-5ubuntu8_i386.deb [OK]
http://archive.ubuntu.com/ubuntu/pool/main/a/adduser/adduser_3.103ubuntu1_all.deb [OK]
http://archive.ubuntu.com/ubuntu/pool/main/a/adept/adept_2.1.3ubuntu17_all.deb [OK]
...
/my_files/temp/test$ /my_files/just4fun/scripts/my_create_local_repository/create_repository repository/
Репозиторий создан.
"...если пользоваться моим скриптом, то для обновления репозитория вам не нужно хранить на своей машине копию ранее созданного репозитория..." - Поясни, плиз, я не понял.
GiNeR, ну вот, допустим, выкачал ты весь репозиторий и отнес другу, у которого нет Интернета, а у себя его удалил. Прошло какое-то время, появились обновления и друг захотел репозиторий со свежими пакетами. Что делать? Заново выкачивать весь репозиторий? Или вынуть жесткий диск, принести его другу, скопировать на него уже устаревший репозиторий, вернуться домой, натравить на него debmirror, чтобы он скачал только новые пакеты, и отнести обратно другу? :)
Оба способа не очень удобны. Для того чтобы обновить репозиторий при помощи моего скрипта, необходимо взять у друга только один файл в несколько мегабайт, содержащий список всех пакетов, которые у него уже есть - мой скрипт выкачает только те пакеты, которых нет в этом списке.
P.S.: Честно говоря, сам я уже не пользуюсь своим скриптом, а использую debmirror + еще несколько моих скриптов, которые как раз реализуют эту возможность. Делаю я это потому, что именно с выкачиванием пакетов debmirror справляется немного лучше моего скрипта - в созданном им репозитории все пакеты остаются подписаны ключом pgp, что не вызывает предупреждений apt-get'а. Плюс, запуская debmirror из еще одного скрипта, я заставил нормально работать apt-file с моим зеркалом репозитория.
Удобно, хотя сам пользуюсь debmirror )
Отправить комментарий