3 from optparse
import OptionParser
4 import os
, shutil
, tempfile
, commands
, glob
, sys
, re
, subprocess
, shutil
, time
6 usage
= "%prog [options] <list of .debs>"
8 parser
= OptionParser(usage
=usage
)
10 parser
.add_option("-d", "--cd-dir",
11 dest
="cddir", default
=None,
12 help="The directory of the install cd details")
14 parser
.add_option( "-k", "--gpg-key",
15 dest
="gpgkey", default
=None, type="string",
16 help="The GPG key used to sign the packages" )
18 parser
.add_option( "--ubuntu-keyring",
19 dest
="keyring", default
=None, type="string",
20 help="The directory of the ubuntu keyring source. if not provided it will be downloaded." )
22 parser
.add_option( "--indices",
23 dest
="indices", default
=None, type="string",
24 help="The directory of the ubuntu indices" )
26 parser
.add_option( "--passphrase",
27 dest
="passphrase", default
=None, type="string",
28 help="The passphrase for the gpg key" )
30 parser
.add_option( "--dist",
31 dest
="dist", default
=None, type="string",
32 help="Instead of autodetecting the dist, use this" )
34 (options
, orig_debs
) = parser
.parse_args()
36 if not orig_debs
or not options
.cddir
or not options
.gpgkey
or not options
.indices
:
40 assert os
.path
.isdir( options
.indices
)
42 debs
= [os
.path
.abspath( deb
) for deb
in orig_debs
]
44 cddir
= os
.path
.abspath( options
.cddir
)
45 indices
= os
.path
.abspath( options
.indices
)
47 if options
.dist
is None:
48 # see what the name of the distro is, (eg dapper, edgy.. )
49 dists_dir
= [ dir for dir in os
.listdir( os
.path
.join ( cddir
, 'dists' ) ) if dir not in ['stable', 'unstable' ] ]
51 assert len(dists_dir
) == 1
56 dist_name_to_version
= { 'warty':'4.10', 'hoary':'5.04', 'breezy':'5.10',
57 'dapper':'6.06', 'edgy':'6.10', 'feisty':'7.04',
58 'gutsy':'7.10', 'hardy':'8.04', 'intrepid':'8.10' }
60 assert dist
in dist_name_to_version
.keys()
62 def RunCommand(cmd
, msg
=None):
63 print "running : %s" % cmd
64 p
= subprocess
.Popen(cmd
, shell
=True, stdout
=subprocess
.PIPE
, stderr
=subprocess
.PIPE
)
66 print "output : ", p
.stdout
.read()
67 print "stderr: ", p
.stderr
.read()
70 if msg
is not None: print msg
73 def makedir_if_not_exist( *path_parts
):
74 path
= os
.path
.join( *path_parts
)
75 if not os
.path
.exists( path
):
78 makedir_if_not_exist( cddir
, 'dists', dist
, 'extras', 'binary-i386' )
79 makedir_if_not_exist( cddir
, 'pool', 'extras' )
80 makedir_if_not_exist( cddir
, 'isolinux' )
81 makedir_if_not_exist( cddir
, 'preseed' )
83 # Copy all the debs to the extras file
85 print "Copying %s" % deb
86 shutil
.copy( deb
, os
.path
.join( cddir
, "pool", "extras" ) )
88 releases_file
= open( os
.path
.join( cddir
, 'dists', dist
, 'extras', 'binary-i386', 'Release' ), 'w' )
89 releases_file
.write( "Archive: " + dist
+ "\n" )
90 releases_file
.write( "Version: " + dist_name_to_version
[dist
] + "\n" )
91 releases_file
.write( "Component: extras\nOrigin: Ubuntu\nLabel: Ubuntu\nArchitecture: i386\n")
93 print "Wrote the Releases file"
97 temp_dir
= tempfile
.mkdtemp( prefix
="/tmp/camarabuntu-tmp-", dir=old_cwd
)
100 #shutil.copytree( os.path.join( old_cwd, cddir, 'pool', 'main', 'u', 'ubuntu-keyring' ), temp_dir )
104 # TODO different versions of ubuntu-keyring
105 if options
.keyring
is None:
107 print "Downloading the ubuntu-keyring..."
108 cmd
= "apt-get source ubuntu-keyring"
109 msg
= """An error occured when downloading the source of the ubuntu-keyring package
110 This is needed to sign our new packages"""
111 RunCommand(cmd
, msg
=msg
)
113 if options
.keyring
[-1] == '/':
114 # This should be a directory, if there's a / at the end, it'll break os.path.split
115 options
.keyring
= options
.keyring
[0:-1]
116 shutil
.copytree( os
.path
.join( old_cwd
, options
.keyring
), os
.path
.join( temp_dir
, os
.path
.split( options
.keyring
)[1] ) )
119 gpg_keys_filename
= glob
.glob ( os
.path
.join( temp_dir
, 'ubuntu-keyring*/keyrings/ubuntu-archive-keyring.gpg' ) )[0]
120 ubuntu_keyring_dir
= [name
for name
in glob
.glob( os
.path
.join( temp_dir
, 'ubuntu-keyring*' ) ) if os
.path
.isdir(name
)][0]
122 assert os
.path
.isfile( gpg_keys_filename
)
124 print "Adding GPG key %s to the ubuntu-keyring" % options
.gpgkey
126 cmd
= "gpg --import < %s" % gpg_keys_filename
127 # if this fails someone was messing with the code before
130 cmd
= "gpg --export FBB75451 437D05B5 %s > %s" % (options
.gpgkey
, gpg_keys_filename
)
131 # Invalid keys are not detected here, unfortunatly
134 print "\n\nRebuilding the ubuntu-keyring."
135 os
.chdir( ubuntu_keyring_dir
)
136 # Invalid keys are not detected here, unfortunatly
137 cmd
= "dpkg-buildpackage -rfakeroot -k%s" % options
.gpgkey
138 msg
= """Unable to rebuild the ubuntu-keyring
140 (*) The GPG key you gave (%s) is invalid, check available keys with "gpg --list-keys" """ % options
.gpgkey
141 RunCommand(cmd
, msg
=msg
)
142 print "Finished Rebuilding the ubuntu-keyring.\n\n"
144 # Copy these files into the main component
145 shutil
.copy( glob
.glob( os
.path
.join( temp_dir
, "ubuntu-keyring*_all.deb" ) )[0], os
.path
.join( old_cwd
, cddir
, 'pool/main/u/ubuntu-keyring/' ) )
148 # Clean up, remove all this crap
150 shutil
.rmtree( temp_dir
)
153 ## Now create the indices.
154 temp_dir
= tempfile
.mkdtemp( prefix
="/tmp/camarabuntu-tmp-", dir=old_cwd
)
157 ftparchive_deb
= open( os
.path
.join( temp_dir
, 'apt-ftparchive-deb.conf' ), 'w' )
158 ftparchive_deb
.write( """Dir {
159 ArchiveDir "%(cddir)s";
166 BinDirectory "pool/main" {
167 Packages "dists/%(dist)s/main/binary-i386/Packages";
168 BinOverride "%(indices)s/override.%(dist)s.main";
169 ExtraOverride "%(indices)s/override.%(dist)s.extra.main";
172 BinDirectory "pool/restricted" {
173 Packages "dists/%(dist)s/restricted/binary-i386/Packages";
174 BinOverride "%(indices)s/override.%(dist)s.restricted";
187 """ % {'cddir':cddir
, 'dist':dist
, 'indices':indices
} )
189 ftparchive_deb
.close()
191 # generate the extras override. This is converted from the perl version on
192 # https://help.ubuntu.com/community/InstallCDCustomization
194 main_packages
= open( os
.path
.join( old_cwd
, cddir
, 'dists', dist
, 'main/binary-i386/Packages' ) )
195 extra_overrides
= open( os
.path
.join( temp_dir
, "override.%s.extra.main" % dist
), 'w' )
197 for line
in main_packages
:
198 line
= line
.rstrip("\n")
199 line
= line
.rstrip("\r\n")
200 line
= line
.rstrip("\r")
201 if re
.search("^\s", line
):
202 continue # to the next line
203 if line
== "" and task
is not None:
204 extra_overrides
.write("%s Task %s\n" % (package
, task
))
209 key
, value
= line
.split(": ", 1)
216 extra_overrides
.close()
217 main_packages
.close()
219 ftparchive_udeb
= open( os
.path
.join( temp_dir
, "apt-ftparchive-udeb.conf" ), 'w')
220 ftparchive_udeb
.write("""Dir {
221 ArchiveDir "%(cddir)s";
228 BinDirectory "pool/main" {
229 Packages "dists/%(dist)s/main/debian-installer/binary-i386/Packages";
230 BinOverride "%(indices)s/override.%(dist)s.main.debian-installer";
233 BinDirectory "pool/restricted" {
234 Packages "dists/%(dist)s/restricted/debian-installer/binary-i386/Packages";
235 BinOverride "%(indices)s/override.%(dist)s.restricted.debian-installer";
248 """ % {'cddir':cddir
, 'dist':dist
, 'indices':indices
} )
249 ftparchive_udeb
.close()
251 ftparchive_extras
= open( os
.path
.join( temp_dir
, 'apt-ftparchive-extras.conf' ), 'w')
252 ftparchive_extras
.write("""Dir {
253 ArchiveDir "%(cddir)s";
260 BinDirectory "pool/extras" {
261 Packages "dists/%(dist)s/extras/binary-i386/Packages";
274 """ % {'cddir':cddir
, 'dist':dist
, 'indices':indices
} )
275 ftparchive_extras
.close()
277 release_file
= open( os
.path
.join( temp_dir
, "release.conf" ), 'w' )
278 release_file
.write("""
279 APT::FTPArchive::Release::Origin "Ubuntu";
280 APT::FTPArchive::Release::Label "Ubuntu";
281 APT::FTPArchive::Release::Suite "%(dist)s";
282 APT::FTPArchive::Release::Version "%(dist_number)s";
283 APT::FTPArchive::Release::Codename "%(dist)s";
284 APT::FTPArchive::Release::Architectures "i386";
285 APT::FTPArchive::Release::Components "main restricted extras";
286 APT::FTPArchive::Release::Description "Ubuntu %(dist_number)s";
287 """ % {'cddir':cddir
, 'dist':dist
, 'indices':indices
, 'dist_number':dist_name_to_version
[dist
]} )
290 # now build the repository
292 print "Generating the APT repository..."
294 status
, output
= commands
.getstatusoutput("apt-ftparchive -c %(temp_dir)s/release.conf generate %(temp_dir)s/apt-ftparchive-deb.conf" % {'temp_dir':temp_dir
})
299 status
, output
= commands
.getstatusoutput("apt-ftparchive -c %(temp_dir)s/release.conf generate %(temp_dir)s/apt-ftparchive-udeb.conf" % {'temp_dir':temp_dir
})
304 status
, output
= commands
.getstatusoutput("apt-ftparchive -c %(temp_dir)s/release.conf generate %(temp_dir)s/apt-ftparchive-extras.conf"% {'temp_dir':temp_dir
})
309 if os
.path
.isfile( os
.path
.join( cddir
, 'dists', dist
, 'Release.gpg') ):
310 # Otherwise apt-ftparchive will ask to overwrite it, we want this whole process automated
311 os
.remove( os
.path
.join( cddir
, 'dists', dist
, 'Release.gpg' ) )
312 status
, output
= commands
.getstatusoutput("apt-ftparchive -c %(temp_dir)s/release.conf release %(cddir)s/dists/%(dist)s > %(cddir)s/dists/%(dist)s/Release" % {'dist':dist
, 'cddir':cddir
, 'temp_dir':temp_dir
})
317 cmd
= "gpg --default-key \"%(gpgkey)s\" --output %(cddir)s/dists/%(dist)s/Release.gpg -ba %(cddir)s/dists/%(dist)s/Release" % {'cddir':cddir
, 'dist':dist
, 'gpgkey':options
.gpgkey
}
323 shutil
.rmtree( temp_dir
)
326 # Find out the name of all the packages in the repository to add to the preseed file
327 print "Generating a list of all the packages to install"
330 status
, output
= commands
.getstatusoutput( "dpkg --info \"%s\"" % deb
)
332 for line
in output
.split("\n"):
333 line
= line
.rstrip("\n")
334 splits
= line
.split(": ", 1)
338 if key
== " Package":
339 package_names
.append(value
)
341 # now append the d-i directive to the preseed file to install our custom packages
342 preseed_dir
= os
.path
.join(options
.cddir
, 'preseed')
343 camarabuntu_preseeds
= [x
for x
in os
.listdir(preseed_dir
) if x
.startswith('camarabuntu')]
344 print repr(camarabuntu_preseeds
)
345 for preseed_file
in camarabuntu_preseeds
:
346 preseed_file
= os
.path
.join(preseed_dir
, preseed_file
)
347 print 'editing ', preseed_file
348 lines
= open(preseed_file
, 'r').readlines()
351 if line
.startswith("d-i\tpkgsel/install-pattern\tstring ~t^edubuntu-standard$|~t^edubuntu-desktop$|~t^edubuntu-server"):
352 print "Got to the line", line
353 newlines
.append( "# The following line has been automatically added by the camarabuntu scripts\n" )
354 # we need to remove the trailing \n
355 newlines
.append( line
[:-1]+"|"+"|".join( ["~n^%s$" % package_name
for package_name
in package_names
] ) + "\n" )
357 newlines
.append(line
)
359 newlines
.append( "# The following line has been automatically added by the camarabuntu scripts\n" )
360 newlines
.append( "d-i\tpkgsel/include\tstring " + " ".join(package_names
) + "\n" )
362 fd
= open(preseed_file
, "w")
363 fd
.write( "".join( newlines
) )