1#!/usr/local/bin/python
2#
3# This script generates a master INDEX file for the CD images built by the
4# FreeBSD release engineers.  Each disc is given a list of desired packages.
5# Dependencies of these packages are placed on either the same disc or an
6# earlier disc.  The resulting master INDEX file is then written out.
7#
8# Usage: package-split.py <INDEX> <master INDEX>
9#
10# $FreeBSD: stable/9/release/scripts/package-split.py 253613 2013-07-24 13:43:09Z gjb $
11
12import os
13import sys
14
15try:
16    arch = os.environ["PKG_ARCH"]
17except:
18    arch = os.uname()[4]
19print "Using arch %s" % (arch)
20
21if 'PKG_VERBOSE' in os.environ:
22    verbose = 1
23else:
24    verbose = 0
25
26# List of packages for dvd1.
27def dvd1_packages():
28    pkgs = ['archivers/unzip',
29	    'devel/subversion',
30	    'devel/subversion-static',
31	    'emulators/linux_base-f10',
32	    'lang/perl5.14',
33	    'misc/freebsd-doc-all',
34	    'net/mpd5',
35	    'net/rsync',
36	    'ports-mgmt/portaudit',
37	    'ports-mgmt/portmaster',
38	    'shells/bash',
39	    'shells/zsh',
40	    'security/sudo',
41	    'sysutils/screen',
42	    'www/firefox',
43	    'www/links',
44	    'x11-drivers/xf86-video-vmware',
45	    'x11/gnome2',
46	    'x11/kde4',
47	    'x11/xorg'];
48    return pkgs
49
50# The list of desired packages
51def desired_packages():
52    dvd1 = dvd1_packages()
53    return [dvd1]
54
55# Suck the entire INDEX file into a two different dictionaries.  The first
56# dictionary maps port names (origins) to package names.  The second
57# dictionary maps a package name to a list of its dependent packages.
58PACKAGE_COL=0
59ORIGIN_COL=1
60DEPENDS_COL=8
61
62def load_index(index):
63    deps = {}
64    pkgs = {}
65    line_num = 1
66    for line in index:
67        fields = line.split('|')
68        name = fields[PACKAGE_COL]
69        if name in deps:
70            sys.stderr.write('%d: Duplicate package %s\n' % (line_num, name))
71            sys.exit(1)
72        origin = fields[ORIGIN_COL].replace('/usr/ports/', '', 1)
73        if origin in pkgs:
74            sys.stderr.write('%d: Duplicate port %s\n' % (line_num, origin))
75            sys.exit(1)
76        deps[name] = fields[DEPENDS_COL].split()
77        pkgs[origin] = name
78        line_num = line_num + 1
79    return (deps, pkgs)
80
81# Layout the packages on the various CD images.  Here's how it works.  We walk
82# each disc in the list of discs.  Within each disc we walk the list of ports.
83# For each port, we add the package name to a dictionary with the value being
84# the current disc number.  We also add all of the dependent packages.  If
85# a package is already in the dictionary when we go to add it, we just leave
86# the dictionary as it is.  This means that each package ends up on the first
87# disc that either lists it or contains it as a dependency.
88def layout_discs(discs, pkgs, deps):
89    disc_num = 1
90    layout = {}
91    for disc in discs:
92        for port in disc:
93            if port not in pkgs:
94                sys.stderr.write('Disc %d: Unable to find package for %s\n' %
95                                 (disc_num, port))
96                continue
97            pkg = pkgs[port]
98            pkg_list = [pkg] + deps[pkg]
99            for pkg in pkg_list:
100                if pkg not in layout:
101                    if verbose:
102                        print "--> Adding %s to Disc %d" % (pkg, disc_num)
103                    layout[pkg] = disc_num
104        disc_num = disc_num + 1
105    return layout
106
107# Generate a master INDEX file based on the generated layout.  The way this
108# works is that for each INDEX line, we check to see if the package is in the
109# layout.  If it is, we put that INDEX line into the master INDEX and append
110# a new field with the disc number to the line.
111def generate_index(index, layout, master_index):
112    for line in index:
113        pkg = line.split('|')[PACKAGE_COL]
114        if pkg in layout:
115            new_line = '%s|%d\n' % (line.splitlines()[0], layout[pkg])
116            master_index.write(new_line)
117
118# Verify the command line arguments
119if len(sys.argv) != 3:
120    sys.stderr.write('Invalid number of arguments\n')
121    sys.stderr.write('Usage: package-split.py <source INDEX> <master INDEX>\n')
122    sys.exit(1)
123
124print "Loading %s..." % (sys.argv[1])
125index = file(sys.argv[1])
126(deps, pkgs) = load_index(index)
127discs = desired_packages()
128layout = layout_discs(discs, pkgs, deps)
129index.seek(0)
130print "Generating %s..." % (sys.argv[2])
131master_index = file(sys.argv[2], 'w')
132generate_index(index, layout, master_index)
133index.close()
134master_index.close()
135