Custom Local Repository (Русский)
Contents
Новый метод (repo-add)
В pacman 3 появился новый скрипт repo-add, который делает генерацию собственного локального репозитория еще проще. Используйте repo-add --help для больших подробностей по его использованию.
При помощи этого скрипта очень легко поддерживать состояние вашей базы данных в актуальном состоянии. Просто сохраните все пакеты, которые вы хотите положить в свой репозиторий, в одной папке, перейдите в эту папку, и запустите следующую команду:
repo-add /path/to/repo.db.tar.gz *.pkg.tar.xz
где 'repo' - это имя вашего собственного репозитория. Последний аргумент добавляет все pkg.tar.xz файлы к вашему репозиторию, так что будьте внимательны, если вы имеете несколько разных версий одного и того же пакета в вашей папке. Неизвестно какая версия попадет в репозиторий, но попадет только одна!
Для добавления нового пакета (и удаления старого, если он есть) просто запустите:
repo-add /path/to/repo.db.tar.gz packagetoadd-1.0-1-i686.pkg.tar.xz
Если есть пакет, который вы не хотите видеть в репозитории, читайте repo-remove --help.
Старый метод (свой репозиторий из дерева ABS)
Этот документ описывает то, как создать ваш собственный репозиторий из индивидуализированного дерева ABS, содержащего только те PKGBUILD'ы которые вы хотите включить в ваш репозиторий. Это полезно для создания локального репозитория или особого репозитория для пакетов, которых нет в официальных репозиториях.
Основано на: https://bbs.archlinux.org/viewtopic.php?p=29474
Выполните gensync и прочитайте опции командной строки.
Коротко: параметрами являются корни PKGBUILD'ов, сортированные в подкаталогах (например, как дерево ABS), предполагаемые имя и местоположение файла базы данных и директория, содержащая бинарные пакеты.
Создайте дерево ABS. Вы можете сделать это, используя команду abs, если вы хотите создать копию обычного дерева ABS или создать дерево вручную. Придерживайтесь следующего правила: каждый PKGBUILD находится в своей собственной директории (официальный ли это PKGBUILD или тот, который вы создали сами). Если вы изменяете официальный ABS репозиторий, удалите любые abs директории, которые вы не хотите включать в конечный репозиторий.
Сохраните все пакеты, для которых вы хотите создать репозиторий, в особый каталог (например, /home/arch/i686/core). Вы можете создать пакет, используя makepkg, или скачать их с помощью pacman'а, это зависит от ситуации.
Выполните gensync, подставляя необходимые параметры. Например:
gensync /var/abs /home/arch/i686/core/core.db.tar.gz /home/arch/i686/core
построит репозиторий для репозитория core, если он расположен в /home/arch/i686/core. Имя файла db.tar.gz - это имя репозитория, который вы создаёте. Обычно используют такое же имя для и директории, которая хранит пакеты.
Используйте
tar -tzf core.db.tar.gz || less
для того чтобы удостовериться, что база содержит верные пакеты.
Быстрый способ (свой репозиторий из директории с пакетами)
Не работает пакетами с суффиксами -i686/-x86_64
Если у вас есть директория с большим количеством пакетом (core/extra/testing/selfbuild/etc) и вы хотите включить их в один репозиторий .
(Мне нужно было пересобрать установочный диск для того чтобы положить всё, что нужно на компьютер без интернет соединения). Вы можете создать core.db.tar.gz из этой директории, используя маленький скрипт (не очень элегантно, зато работает)
#!/usr/bin/perl
use strict;
unless (defined $ARGV[0] && defined $ARGV[1]){
print STDERR "\nUsage: gendb <DIR> <NAME>\n\n";
exit 1;
}
`rm -rf /tmp/pkgdb`;
opendir(DIR, $ARGV[0]) || die "Can't open dir $ARGV[0]: $!";
while(my $file=readdir(DIR)){
if($file =~ /^(.+)\.pkg.tar.gz$/){
my $pkg = $1;
my @filedata=stat($ARGV[0]."/".$file);
my %info = ();
my $i;
print STDERR "Processing $file\n";
`mkdir -p /tmp/pkgdb/$pkg`;
`rm -f /tmp/PKGINFO ; tar -O -xzf $ARGV[0]/$file .PKGINFO > /tmp/PKGINFO`;
open(INPUT, "/tmp/PKGINFO") || die "can't open PKGINFO file: $!";
while(<INPUT>)
{
chomp;
if( /^([a-z]+)\s?[=]\s?(.+)$/ )
{
my $attr = $1;
my $value = $2;
$info{$attr} .= $value." ";
}
}
close(INPUT);
open(OUT, "> /tmp/pkgdb/$pkg/desc") || die "can't open desc file: $!";
print OUT "\%NAME\%\n".$info{"pkgname"}."\n\n";
print OUT "\%VERSION\%\n".$info{"pkgver"}."\n\n";
print OUT "\%DESC\%\n".$info{"pkgdesc"}."\n\n";
print OUT "\%CSIZE\%\n".$filedata[7]."\n\n";
print OUT "\%MD5SUM\%\n";
close(OUT);
`md5sum $ARGV[0]/$file | cut -f1 -d' ' >> /tmp/pkgdb/$pkg/desc`;
open(OUT, ">> /tmp/pkgdb/$pkg/desc") || die "can't open desc file: $!";
print OUT "\n\%REPLACES\%\n";
foreach $i (split(' ',$info{"replaces"})){ print OUT $i."\n";}
print OUT "\n";
close(OUT);
open(OUT, "> /tmp/pkgdb/$pkg/depends") || die "can't open depends file: $!";
print OUT "\%DEPENDS\%\n";
foreach $i (split(' ',$info{"depend"})){ print OUT $i."\n";}
print OUT "\n";
print OUT "\%CONFLICTS\%\n";
foreach $i (split(' ',$info{"conflict"})){ print OUT $i."\n";}
print OUT "\n";
print OUT "\%PROVIDES\%\n";
foreach $i (split(' ',$info{"provides"})){ print OUT $i."\n";}
print OUT "\n";
close(OUT);
}
}
closedir DIR;
`cd /tmp/pkgdb ; tar -czf $ARGV[1].db.tar.gz *`;
`cp /tmp/pkgdb/$ARGV[1].db.tar.gz $ARGV[0]/`
Поместите содержимое скрипта в файл gendb и укажите, что он исполняемый:
chmod +x gendb
После этого скриптом уже можно пользоваться и натравливать на папку с пакетами в таком стиле:
./gendb /путь/к/папке название_репозитория
Результат будет храниться в /путь/к/папке/название_репозитория.db.tar.gz.
Другой быстрый способ, скрипт на Python
Этот скрипт также создаёт репозиторий из директории, содержащей пакеты, не нуждаясь в ABS. Он также показывает неудовлетворённые зависимости (хотя на этот момент игнорирует номера версий) и может фильтровать их в довольно примитивным образом, игнорируя определённое множество (например, пакеты в /var/lib/pacman/local).
#!/usr/bin/env python # gen_repo.py - build a repository db file from a set of packages # # Author: gradgrind <mt.42-at-web.de> # # This file is part of the larch project. # # larch 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 2 of the License, or # (at your option) any later version. # # larch 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. # # You should have received a copy of the GNU General Public License # along with larch; if not, write to the Free Software Foundation, Inc., # 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # #---------------------------------------------------------------------------- # import os import os.path import shutil import sys import tarfile from types import * import re # Regex to remove version comparison from package dependency onlyname = re.compile("[^=><]+") def create_db(dbname, packagesdir, dep_ignore_list): os.chdir(packagesdir) # Open tar archive for db dbtar = tarfile.open(dbname + ".db.tar.gz", "w:gz") # Get a list of packages packages = filter(lambda s: s.endswith(".pkg.tar.gz"), os.listdir(".")) packages.sort() # Make a dict for keeping track of dependencies dep_dict = {} if os.path.isdir(dbname): shutil.rmtree(dbname) os.mkdir(dbname, 0755) for p in packages: pkg_dict = get_pkg_info(p) pkg_name = pkg_dict["pkgname"] pkg_dbname = pkg_name + "-" + pkg_dict["pkgver"] pkg_dir = os.path.join(dbname, pkg_dbname) os.mkdir(pkg_dir, 0755) mkdesc(pkg_dir, pkg_dict) mkdepends(pkg_dir, pkg_dict) # Add dependency info to dependency dict for d in pkg_dict["depend"]: # But also need to cater for versioning!!! # I will just ignore it here ... d = onlyname.match(d).group() if d not in dep_dict: dep_dict[d] = [False] dep_dict[d].append(pkg_name) # Mark packages provided by this one for p in (pkg_dict["provides"] + [pkg_name]): if p in dep_dict: dep_dict[p][0] = True else: dep_dict[p] = [True] dbtar.add(pkg_dir, pkg_dbname) # Mark packages in ignore list for p in dep_ignore_list: if p in dep_dict: dep_dict[p][0] = True # Close db tar archive dbtar.close() # Remove directory structure shutil.rmtree(dbname) # Now display unstaisfied dependencies # Should add the possibility of declaring a list of packages # available (e.g. the base set, or all those on the live CD ..." print "-------------\nUnsatisfied dependencies:" for d, r in dep_dict.iteritems(): if not r[0]: print " ", d, "- needed by: ", for p in r[1:]: print p, " ", print "" def get_pkg_info(pkg): tf = tarfile.open(pkg, "r:gz") pkginfo = tf.extractfile(".PKGINFO") pkg_dict = {# the first ones go to 'desc' "pkgname" : None, "pkgver" : None, "pkgdesc" : None, # from here they are optional, and can occur more than once "group" : [], "replaces" : [], # the rest go to 'depends' "depend" : [], "conflict" : [], "provides" : [], } while True: l = pkginfo.readline().strip() if not l: break if l[0] == "#": continue split3 = l.split(None, 2) while len(split3) < 3: split3.append(None) key, eq, value = split3 if key not in pkg_dict: continue val = pkg_dict[key] if val == None: pkg_dict[key] = value continue if not isinstance(val, ListType): print "Unexpected situation ...\n key [oldvalue] <- newvalue" print key, "[%s]" % val, "<-", value sys.exit(1) pkg_dict[key].append(value) pkginfo.close() pkg_dict["md5sum"] = md5sum(pkg) pkg_dict["csize"] = str(os.path.getsize(pkg)) return pkg_dict def mkdesc(pkg_dir, pkg_dict): f = open(os.path.join(pkg_dir, "desc"), "w") f.write("%NAME%\n" + pkg_dict["pkgname"] + "\n\n") f.write("%VERSION%\n" + pkg_dict["pkgver"] + "\n\n") f.write("%DESC%\n" + pkg_dict["pkgdesc"] + "\n\n") f.write("%CSIZE%\n" + pkg_dict["csize"] + "\n\n") f.write("%MD5SUM%\n" + pkg_dict["md5sum"] + "\n\n") groups = pkg_dict["group"] if groups: f.write("%GROUPS%\n") for g in groups: f.write(g + "\n") f.write("\n") replaces = pkg_dict["replaces"] if replaces: f.write("%REPLACES%\n") for r in replaces: f.write(r + "\n") f.write("\n") f.close() def mkdepends(pkg_dir, pkg_dict): f = open(os.path.join(pkg_dir, "depends"), "w") depends = pkg_dict["depend"] if depends: f.write("%DEPENDS%\n") for d in depends: f.write(d + "\n") f.write("\n") conflicts = pkg_dict["conflict"] if conflicts: f.write("%CONFLICTS%\n") for c in conflicts: f.write(c + "\n") f.write("\n") provides = pkg_dict["provides"] if provides: f.write("%PROVIDES%\n") for p in provides: f.write(p + "\n") f.write("\n") def md5sum(filepath): f = file(filepath, 'rb') m = hashlib.md5() while True: d = f.read(8192) if not d: break m.update(d) f.close() return m.hexdigest() def cat(path): """Python version of 'cat'""" fp = open(path, "r") op = "".join(fp) fp.close() return op def usage(): print """ genrepo.py package-dir [repo-name] [-- ignore-list] Generate a pacman db file for the packages in package-dir. If repo-name is given, this will be used as the name for the repository, otherwise the name of the directory containing the packages will be used. All dependencies of the packages in the repository will be listed to standard output, but a list of packages not to be included in this list can be specified: ignore-list should be either a file containing the names of packages not to be listed as dependencies (separated by space or newline), or a directory containing 'package directories', like /var/abs/base or /var/lib/pacman/local """ sys.exit(1) if __name__ == "__main__": if os.getuid() != 0: print "Must be root to run this" sys.exit(1) if len(sys.argv) < 2: usage() pkgdir = sys.argv[1] if len(sys.argv) == 2 or sys.argv[2] == "--": dbname = os.path.basename(os.path.abspath(pkgdir)) i = 2 else: dbname = sys.argv[2] i = 3 if len(sys.argv) == i: ignore_list = [] elif len(sys.argv) == i+2 and sys.argv[i] == "--": ignore_list = sys.argv[i+1] else: usage() if not os.path.isdir(pkgdir): print "\n1st argument must be a directory" sys.exit(1) print "\nCreating pacman database (%s.db.tar.gz) file in %s" % (dbname, pkgdir) i = raw_input("Do you want to do this? [Y/n] ").strip() if i and i[0] not in "Yy": print " -> Not creating package db" sys.exit(0) if ignore_list: # Get list of packages to be ignored in dependency list if os.path.isfile(ignore_list): # A simple file containing the names of packages to ignore # separated by space or newline. ignore_list = cat(ignore_list).split() elif os.path.isdir(ignore_list): # A directory containing packages or package-directories (like in abs) l = os.listdir(ignore_list) # See if there are packages in this directory lp = filter(lambda s: s.endswith(".pkg.tar.gz"), l) if lp: l = map(lambda s: s.replace(".pkg.tar.gz", ""), lp) re1 = re.compile(r"(.+)-[^-]+?-\d+") ignore_list = [] for f in l: m = re1.match(f) if m: ignore_list.append(m.group(1)) else: print "!!! Invalid ignore-list" usage() create_db(dbname, pkgdir, ignore_list)
Заключительная часть
При желании вы можете добавить репозиторий (директорию, содержащую пакеты и файл db.tar.gz) на ftp (или nfs) сервер машины.
Добавьте репозиторий в ваш pacman.conf. Именем репозитория должно быть имя файла db.tar.gz. Вы можете сослаться непосредственно на него, используя синтаксис file:// или обратиться по ftp: ~ftp://localhost/path/to/directory
Не забудьте добавить ваш собственный репозиторий в наш список неофициальных пользовательских репозиториев для того чтобы другие пользователи могли найти и установить ваши пакеты!