]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - release/scripts/package-split.py
Add a new package splitting mechanism to replace print-cdrom-packages.sh.
[FreeBSD/FreeBSD.git] / release / scripts / package-split.py
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$
11
12 import os
13 import sys
14
15 try:
16     arch = os.environ["PKG_ARCH"]
17 except:
18     arch = os.uname()[4]
19 print "Using arch %s" % (arch)
20
21 if 'PKG_VERBOSE' in os.environ:
22     verbose = 1
23 else:
24     verbose = 0
25
26 # List of packages for disc1.  This just includes packages sysinstall can
27 # install as a distribution
28 def disc1_packages():
29     # 5.x only
30     pkgs = ['lang/perl5.8']
31     if arch != 'ia64':
32         pkgs.append('x11/xorg')
33     if arch == 'alpha':
34         pkgs.append('emulators/osf1_base')
35     elif arch == 'i386':
36         pkgs.append('emulators/linux_base-8')
37     # 5.x only
38     if arch == 'i386':
39         pkgs.append('misc/compat22')
40         pkgs.append('misc/compat3x')
41         pkgs.append('misc/compat4x')
42     return pkgs
43
44 # List of packages for disc2.  This includes packages that the X desktop
45 # menu depends on (if it still exists) and other "nice to have" packages.
46 # For architectures that use a separate livefs, this is actually disc3.
47 def disc2_packages():
48             # X Desktops
49     pkgs = ['x11/kde3',
50             'x11/gnome2',
51             'x11-wm/afterstep',
52             'x11-wm/windowmaker',
53             'x11-wm/fvwm2',
54             # "Nice to have"
55             'archivers/unzip',
56             'astro/xearth',                 
57             'devel/gmake',
58             'editors/emacs',
59             'editors/vim',
60             'editors/vim-lite',
61             'editors/xemacs',
62             'emulators/mtools',
63             'graphics/png',
64             'graphics/xv',
65             'irc/xchat2',
66             'mail/exim',
67             'mail/fetchmail',
68             'mail/mutt',
69             'mail/pine4',
70             'mail/popd',
71             'mail/xfmail',
72             'mail/postfix',
73             'misc/bsdiff',
74             'net/cvsup',
75             'net/cvsup-without-gui',
76             'net/rsync',
77             'net/samba',
78             'news/slrn',
79             'news/tin',
80             'print/a2ps-letter',
81             'print/apsfilter',
82             'print/ghostscript-gnu-nox11',
83             'print/gv',
84             'print/psutils-letter',
85             'shells/bash2',
86             'shells/pdksh',
87             'shells/zsh',
88             'security/sudo',
89             'sysutils/portsnap',
90             'sysutils/portupgrade',
91             'www/links',
92             'www/lynx',
93             'x11/rxvt',
94             # Formerly on disc3
95             'lang/gnat',
96             'lang/php4',
97             'lang/php5',
98             'print/teTeX',
99             'security/portaudit',
100             'textproc/docproj-jadetex',
101             'www/apache13',
102             'www/apache13-modssl',
103             'www/apache2']
104     if arch == 'i386':
105         pkgs.append('comms/ltmdm')
106         pkgs.append('print/acroread')
107         pkgs.append('www/opera')
108     return pkgs
109
110 # The list of desired packages
111 def desired_packages():
112     disc1 = disc1_packages()
113     disc2 = disc2_packages()
114     return [disc1, disc2]
115
116 # Suck the entire INDEX file into a two different dictionaries.  The first
117 # dictionary maps port names (origins) to package names.  The second
118 # dictionary maps a package name to a list of its dependent packages.
119 PACKAGE_COL=0
120 ORIGIN_COL=1
121 DEPENDS_COL=8
122
123 def load_index(index):
124     deps = {}
125     pkgs = {}
126     line_num = 1
127     for line in index:
128         fields = line.split('|')
129         name = fields[PACKAGE_COL]
130         if name in deps:
131             sys.stderr.write('%d: Duplicate package %s\n' % (line_num, name))
132             sys.exit(1)
133         origin = fields[ORIGIN_COL].replace('/usr/ports/', '', 1)
134         if origin in pkgs:
135             sys.stderr.write('%d: Duplicate port %s\n' % (line_num, origin))
136             sys.exit(1)
137         deps[name] = fields[DEPENDS_COL].split()
138         pkgs[origin] = name
139         line_num = line_num + 1
140     return (deps, pkgs)
141
142 # Layout the packages on the various CD images.  Here's how it works.  We walk
143 # each disc in the list of discs.  Within each disc we walk the list of ports.
144 # For each port, we add the package name to a dictionary with the value being
145 # the current disc number.  We also add all of the dependent packages.  If
146 # a package is already in the dictionary when we go to add it, we just leave
147 # the dictionary as it is.  This means that each package ends up on the first
148 # disc that either lists it or contains it as a dependency.
149 def layout_discs(discs, pkgs, deps):
150     disc_num = 1
151     layout = {}
152     for disc in discs:
153         for port in disc:
154             if port not in pkgs:
155                 sys.stderr.write('Disc %d: Unable to find package for %s\n' %
156                                  (disc_num, port))
157                 continue
158             pkg = pkgs[port]
159             pkg_list = [pkg] + deps[pkg]
160             for pkg in pkg_list:
161                 if pkg not in layout:
162                     if verbose:
163                         print "--> Adding %s to Disc %d" % (pkg, disc_num)
164                     layout[pkg] = disc_num
165         disc_num = disc_num + 1
166     return layout
167
168 # Generate a master INDEX file based on the generated layout.  The way this
169 # works is that for each INDEX line, we check to see if the package is in the
170 # layout.  If it is, we put that INDEX line into the master INDEX and append
171 # a new field with the disc number to the line.
172 def generate_index(index, layout, master_index):
173     for line in index:
174         pkg = line.split('|')[PACKAGE_COL]
175         if pkg in layout:
176             new_line = '%s|%d\n' % (line.splitlines()[0], layout[pkg])
177             master_index.write(new_line)
178
179 # Verify the command line arguments
180 if len(sys.argv) != 3:
181     sys.stderr.write('Invalid number of arguments\n')
182     sys.stderr.write('Usage: package-split.py <source INDEX> <master INDEX>\n')
183     sys.exit(1)
184
185 print "Loading %s..." % (sys.argv[1])
186 index = file(sys.argv[1])
187 (deps, pkgs) = load_index(index)
188 discs = desired_packages()
189 layout = layout_discs(discs, pkgs, deps)
190 index.seek(0)
191 print "Generating %s..." % (sys.argv[2])
192 master_index = file(sys.argv[2], 'w')
193 generate_index(index, layout, master_index)
194 index.close()
195 master_index.close()