core/larch/scripts/gen_repo
2010-05-21 22:16:47 +00:00

207 lines
6.9 KiB
Python
Executable File

#!/usr/bin/env python
# gen_repo - build a repository db file from a set of packages
#
# Author: Michael Towers (gradgrind) <mt.42@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
#
#----------------------------------------------------------------------------
#
# Version 1.5 // 7th July 2007
import os
import os.path
import sys
import tarfile
from types import *
import re
from subprocess import check_call
# to add a package:
#check_call(["repo-add", dbfile, pkg, pkg, pkg, ...])
# Regex to remove version comparison from package dependency
onlyname = re.compile("([^=><]+).*")
def create_db(dbname, packagesdir, dep_ignore_list):
os.chdir(packagesdir)
dbfile = dbname + ".db.tar.gz"
if os.path.exists(dbfile):
os.remove(dbfile)
# Get a list of packages
packages = filter(lambda s: s.endswith(".pkg.tar.gz"), os.listdir("."))
packages.sort()
# Use 'repo-add' to build the repo
check_call(["repo-add", dbfile] + packages)
# Make a dict for keeping track of dependencies
dep_dict = {}
for p in packages:
pkg_dict = get_pkg_info(p)
pkg_name = pkg_dict["pkgname"]
pkg_dbname = pkg_name + "-" + pkg_dict["pkgver"]
# 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 ...
dm = onlyname.match(d)
if not dm:
if d:
print "DEBUG: package %s, dependency = '%s'" % (pkg_name, d)
continue
d = dm.group(1)
if not dep_dict.has_key(d):
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 dep_dict.has_key(p):
dep_dict[p][0] = True
else:
dep_dict[p] = [True]
# Mark packages in ignore list
for p in dep_ignore_list:
if dep_dict.has_key(p):
dep_dict[p][0] = True
# Now display unsatisfied 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.items():
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,
# from here they are optional, and can occur more than once
"depend" : [],
"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("")
key, eq, value = split3
if not pkg_dict.has_key(key): 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()
return pkg_dict
def cat(path):
"""Python version of 'cat'"""
fp = open(path, "r")
op = ""
for l in fp:
op += l
fp.close()
return op
def usage():
print """
gen_repo 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 len(sys.argv) < 2:
usage()
if os.getuid() != 0:
print "Must be root to run this"
sys.exit(1)
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)
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("(.+)-[^-]+?-[0-9]+")
ignore_list = []
for f in l:
m = re1.match(f)
if m:
ignore_list.append(m.group(1))
else:
# the directory contains just the package names (like abs)
ignore_list.append(m)
else:
print "!!! Invalid ignore-list"
usage()
create_db(dbname, pkgdir, ignore_list)