Difference between revisions of "Custom Local Repository (Русский)"

From ArchWiki
Jump to: navigation, search
(wikify some external links, use https for archlinux.org)
(Новый метод (repo-add))
Line 12: Line 12:
 
При помощи этого скрипта очень легко поддерживать состояние вашей базы данных в актуальном состоянии. Просто сохраните все пакеты, которые вы хотите положить в свой репозиторий, в одной папке, перейдите в эту папку, и запустите следующую команду:
 
При помощи этого скрипта очень легко поддерживать состояние вашей базы данных в актуальном состоянии. Просто сохраните все пакеты, которые вы хотите положить в свой репозиторий, в одной папке, перейдите в эту папку, и запустите следующую команду:
  
  repo-add /path/to/repo.db.tar.gz *.pkg.tar.gz
+
  repo-add /path/to/repo.db.tar.gz *.pkg.tar.xz
  
где 'repo' - это имя вашего собственного репозитория. Последний аргумент добавляет все pkg.tar.gz файлы к вашему репозиторию, так что будьте внимательны, если вы имеете несколько разных версий одного и того же пакета в вашей папке. Неизвестно какая версия попадет в репозиторий, но попадет только одна!
+
где 'repo' - это имя вашего собственного репозитория. Последний аргумент добавляет все pkg.tar.xz файлы к вашему репозиторию, так что будьте внимательны, если вы имеете несколько разных версий одного и того же пакета в вашей папке. Неизвестно какая версия попадет в репозиторий, но попадет только одна!
  
 
Для добавления нового пакета (и удаления старого, если он есть) просто запустите:
 
Для добавления нового пакета (и удаления старого, если он есть) просто запустите:
  
  repo-add /path/to/repo.db.tar.gz packagetoadd-1.0-1-i686.pkg.tar.gz
+
  repo-add /path/to/repo.db.tar.gz packagetoadd-1.0-1-i686.pkg.tar.xz
  
 
Если есть пакет, который вы не хотите видеть в репозитории, читайте '''repo-remove --help'''.
 
Если есть пакет, который вы не хотите видеть в репозитории, читайте '''repo-remove --help'''.

Revision as of 13:26, 20 October 2013

Merge-arrows-2.pngThis article or section is a candidate for merging with Pacman Tips (Русский).Merge-arrows-2.png

Notes: please use the second argument of the template to provide more detailed indications. (Discuss in Talk:Custom Local Repository (Русский)#)

Новый метод (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

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