summaryrefslogtreecommitdiffstats
path: root/build_tools/clarch/larch/run/gen_repo
blob: 86e7b85b71615eca087cd7c6e450c5d5b49b6270 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
#!/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)