1 # Copyright (C) 2009, Thomas Leonard
2 # See the README file for details, or visit http://0install.net.
4 import tempfile
, shutil
, os
, sys
6 from logging
import info
7 from zeroinstall
.support
import basedir
12 def __init__(self
, options
, src_feed_name
):
13 self
.src_feed_name
= src_feed_name
14 self
.src_feed
= support
.load_feed(src_feed_name
)
15 self
.archive_dir_public_url
= options
.archive_dir_public_url
16 assert options
.archive_dir_public_url
18 self
.config
= ConfigParser
.RawConfigParser()
20 # Start with a default configuration
21 self
.config
.add_section('global')
22 self
.config
.set('global', 'builders', 'host')
24 self
.config
.add_section('builder-host')
25 #self.config.set('builder-host', 'build', '0launch --not-before 0.10 http://0install.net/2007/interfaces/0release.xml --build-slave "$@"')
26 self
.config
.set('builder-host', 'build', '0launch --command=build-slave http://0install.net/2007/interfaces/0release.xml "$@"')
28 self
.src_impl
= support
.get_singleton_impl(self
.src_feed
)
29 if self
.src_impl
.arch
and self
.src_impl
.arch
.endswith('-src'):
30 path
= basedir
.load_first_config('0install.net', '0release', 'builders.conf')
32 info("Loading configuration file '%s'", path
)
33 self
.config
.read(path
)
35 info("No builders.conf configuration; will build a binary for this host only")
37 if options
.builders
is not None:
38 builders
= options
.builders
40 builders
= self
.config
.get('global', 'builders').strip()
42 self
.targets
= [x
.strip() for x
in builders
.split(',')]
43 info("%d build targets configured: %s", len(self
.targets
), self
.targets
)
46 info("No builders set; no binaries will be built")
50 # We run the build in a sub-process. The idea is that the build may need to run
51 # on a different machine.
52 def build_binaries(self
):
53 if not self
.targets
: return
55 print "Source package, so generating binaries..."
57 archive_file
= support
.get_archive_basename(self
.src_impl
)
59 for target
in self
.targets
:
60 start
= self
.get('builder-' + target
, 'start', None)
61 command
= self
.config
.get('builder-' + target
, 'build')
62 stop
= self
.get('builder-' + target
, 'stop', None)
64 binary_feed
= 'binary-' + target
+ '.xml'
65 if os
.path
.exists(binary_feed
):
66 print "Feed %s already exists; not rebuilding" % binary_feed
68 print "\nBuilding binary with builder '%s' ...\n" % target
70 if start
: support
.show_and_run(start
, [])
72 support
.show_and_run(command
, [os
.path
.basename(self
.src_feed_name
), archive_file
, self
.archive_dir_public_url
, binary_feed
+ '.new'])
74 if stop
: support
.show_and_run(stop
, [])
76 bin_feed
= support
.load_feed(binary_feed
+ '.new')
77 bin_impl
= support
.get_singleton_impl(bin_feed
)
78 bin_archive_file
= support
.get_archive_basename(bin_impl
)
79 bin_size
= bin_impl
.download_sources
[0].size
81 assert os
.path
.exists(bin_archive_file
), "Compiled binary '%s' not found!" % os
.path
.abspath(bin_archive_file
)
82 assert os
.path
.getsize(bin_archive_file
) == bin_size
, "Compiled binary '%s' has wrong size!" % os
.path
.abspath(bin_archive_file
)
84 os
.rename(binary_feed
+ '.new', binary_feed
)
86 def get_binary_feeds(self
):
87 return ['binary-%s.xml' % target
for target
in self
.targets
]
89 def get(self
, section
, option
, default
):
91 return self
.config
.get(section
, option
)
92 except ConfigParser
.NoOptionError
:
95 # This is the actual build process, running on the build machine
96 def build_slave(src_feed
, archive_file
, archive_dir_public_url
, target_feed
):
98 COMPILE
= [os
.environ
['0COMPILE']]
100 print >>sys
.stdout
, ("\n\n*****\n"
101 "Please update your ~/.config/0install.net/0release/builders.conf file to use --command=build-slave."
103 COMPILE
= ['0launch', '--not-before=0.30', 'http://0install.net/2006/interfaces/0compile.xml']
105 feed
= support
.load_feed(src_feed
)
107 src_feed
= os
.path
.abspath(src_feed
)
108 archive_file
= os
.path
.abspath(archive_file
)
109 target_feed
= os
.path
.abspath(target_feed
)
111 impl
, = feed
.implementations
.values()
113 tmpdir
= tempfile
.mkdtemp(prefix
= '0release-')
116 depdir
= os
.path
.join(tmpdir
, 'dependencies')
119 support
.unpack_tarball(archive_file
)
120 os
.rename(impl
.download_sources
[0].extract
, os
.path
.join(depdir
, impl
.id))
122 config
= ConfigParser
.RawConfigParser()
123 config
.add_section('compile')
124 config
.set('compile', 'download-base-url', archive_dir_public_url
)
125 config
.set('compile', 'version-modifier', '')
126 config
.set('compile', 'interface', src_feed
)
127 config
.set('compile', 'selections', '')
128 config
.set('compile', 'metadir', '0install')
129 stream
= open(os
.path
.join(tmpdir
, '0compile.properties'), 'w')
135 support
.check_call(COMPILE
+ ['build'], cwd
= tmpdir
)
136 support
.check_call(COMPILE
+ ['publish', '--target-feed', target_feed
], cwd
= tmpdir
)
138 # TODO: run unit-tests
140 feed
= support
.load_feed(target_feed
)
141 impl
= support
.get_singleton_impl(feed
)
142 archive_file
= support
.get_archive_basename(impl
)
144 shutil
.move(archive_file
, os
.path
.join(os
.path
.dirname(target_feed
), archive_file
))
146 print "\nLeaving temporary directory %s for inspection...\n" % tmpdir
149 shutil
.rmtree(tmpdir
)