move more logic into the WindowsBuild class
This commit is contained in:
parent
39f1c9d355
commit
c0d859ffd6
1 changed files with 96 additions and 88 deletions
184
vm/kojikamid
184
vm/kojikamid
|
|
@ -275,16 +275,83 @@ class SCM(object):
|
||||||
# End heinous copy and paste
|
# End heinous copy and paste
|
||||||
############################
|
############################
|
||||||
|
|
||||||
|
def ensuredir(path):
|
||||||
|
if not os.path.isdir(path):
|
||||||
|
os.makedirs(path)
|
||||||
|
return path
|
||||||
|
|
||||||
class WindowsBuild(object):
|
class WindowsBuild(object):
|
||||||
|
|
||||||
def __init__(self, specpath, build_tag, workdir, opts, logfile):
|
def __init__(self, server, logfile):
|
||||||
"""constructor: check ini spec file syntax, set build properties"""
|
"""constructor: check ini spec file syntax, set build properties"""
|
||||||
self.build_tag = build_tag
|
self.server = server
|
||||||
self.opts = opts
|
info = server.getTaskInfo()
|
||||||
self.workdir = workdir
|
self.source_url = info[0]
|
||||||
|
self.build_tag = info[1]
|
||||||
|
if len(info) > 2:
|
||||||
|
self.task_opts = info[2]
|
||||||
|
else:
|
||||||
|
self.task_opts = {}
|
||||||
|
self.workdir = '/tmp/build'
|
||||||
|
ensuredir(self.workdir)
|
||||||
|
self.source_dir = None
|
||||||
|
self.spec_dir = None
|
||||||
self.logfile = logfile
|
self.logfile = logfile
|
||||||
|
|
||||||
|
# we initialize these here for clarity, but they are populated in loadConfig()
|
||||||
|
self.name = None
|
||||||
|
self.version = None
|
||||||
|
self.release = None
|
||||||
|
self.description = None
|
||||||
|
self.platform = None
|
||||||
|
self.buildrequires = []
|
||||||
|
self.provides = []
|
||||||
|
self.execute = []
|
||||||
|
self.output = {}
|
||||||
|
self.logs = []
|
||||||
|
|
||||||
|
def checkEnv(self):
|
||||||
|
"""Is this environment fit to build in, based on the spec file?"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def checkout(self):
|
||||||
|
"""Checkout sources, specfile, and patches, and apply patches"""
|
||||||
|
src_scm = SCM(self.source_url)
|
||||||
|
self.source_dir = src_scm.checkout(ensuredir(os.path.join(self.workdir, 'source')), self.logfile)
|
||||||
|
if 'specfile' in self.task_opts:
|
||||||
|
spec_scm = SCM(self.task_opts['specfile'])
|
||||||
|
self.spec_dir = spec_scm.checkout(ensuredir(os.path.join(self.workdir, 'spec')), self.logfile)
|
||||||
|
else:
|
||||||
|
self.spec_dir = self.source_dir
|
||||||
|
if 'patches' in self.task_opts:
|
||||||
|
patch_scm = SCM(self.task_opts['patches'])
|
||||||
|
patch_dir = patch_scm.checkout(ensuredir(os.path.join(self.workdir, 'patches')), self.logfile)
|
||||||
|
self.applyPatches(self.source_dir, patch_dir)
|
||||||
|
|
||||||
|
def applyPatches(self, sourcedir, patchdir):
|
||||||
|
"""Apply patches in patchdir to files in sourcedir)"""
|
||||||
|
patches = [patch for patch in os.listdir(patchdir) if \
|
||||||
|
os.path.isfile(os.path.join(patchdir, patch)) and \
|
||||||
|
not patch.startswith('.')]
|
||||||
|
if not patches:
|
||||||
|
raise BuildError, 'no patches found at %s' % patchdir
|
||||||
|
patches.sort()
|
||||||
|
for patch in patches:
|
||||||
|
cmd = ['/usr/bin/patch', '--verbose', '-d', sourcedir, '-p1', '-i', os.path.join(patchdir, patch)]
|
||||||
|
ret, output = run(cmd, logfile=self.logfile)
|
||||||
|
if ret:
|
||||||
|
raise BuildError, 'error applying patches, output was: %s' % output
|
||||||
|
|
||||||
|
def loadConfig(self):
|
||||||
|
"""Load build configuration from the spec file."""
|
||||||
|
specfiles = [spec for spec in os.listdir(self.spec_dir) if spec.endswith('.ini')]
|
||||||
|
if len(specfiles) == 0:
|
||||||
|
raise BuildError, 'No .ini file found'
|
||||||
|
elif len(specfiles) > 1:
|
||||||
|
raise BuildError, 'Multiple .ini files found'
|
||||||
|
|
||||||
conf = ConfigParser()
|
conf = ConfigParser()
|
||||||
conf.read(specpath)
|
conf.read(os.path.join(self.spec_dir, specfiles[0]))
|
||||||
|
|
||||||
# [naming] section
|
# [naming] section
|
||||||
for entry in ('name', 'version', 'release', 'description'):
|
for entry in ('name', 'version', 'release', 'description'):
|
||||||
|
|
@ -294,12 +361,11 @@ class WindowsBuild(object):
|
||||||
self.platform = conf.get('building', 'platform')
|
self.platform = conf.get('building', 'platform')
|
||||||
# buildrequires and provides are multi-valued (space-separated)
|
# buildrequires and provides are multi-valued (space-separated)
|
||||||
for entry in ('buildrequires', 'provides'):
|
for entry in ('buildrequires', 'provides'):
|
||||||
setattr(self, entry, [e for e in conf.get('building', entry).split() if e])
|
getattr(self, entry).extend([e for e in conf.get('building', entry).split() if e])
|
||||||
# execute is multi-valued (newline-separated)
|
# execute is multi-valued (newline-separated)
|
||||||
self.execute = [e.strip() for e in conf.get('building', 'execute').split('\n') if e]
|
self.execute.extend([e.strip() for e in conf.get('building', 'execute').split('\n') if e])
|
||||||
|
|
||||||
# [files] section
|
# [files] section
|
||||||
self.output = {}
|
|
||||||
for entry in conf.get('files', 'output').split('\n'):
|
for entry in conf.get('files', 'output').split('\n'):
|
||||||
if not entry:
|
if not entry:
|
||||||
continue
|
continue
|
||||||
|
|
@ -312,15 +378,12 @@ class WindowsBuild(object):
|
||||||
else:
|
else:
|
||||||
metadata['flags'] = []
|
metadata['flags'] = []
|
||||||
self.output[filename] = metadata
|
self.output[filename] = metadata
|
||||||
self.logs = [e.strip() for e in conf.get('files', 'logs').split('\n') if e]
|
self.logs.extend([e.strip() for e in conf.get('files', 'logs').split('\n') if e])
|
||||||
|
|
||||||
def checkEnv(self):
|
|
||||||
"""Is this environment fit to build in, based on the spec file?"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
def fetchBuildReqs(self):
|
def fetchBuildReqs(self):
|
||||||
"""Retrieve buildrequires listed in the spec file"""
|
"""Retrieve buildrequires listed in the spec file"""
|
||||||
pass
|
for br in self.buildrequires:
|
||||||
|
pass
|
||||||
|
|
||||||
def build(self):
|
def build(self):
|
||||||
"""Do the build: run the execute line(s)"""
|
"""Do the build: run the execute line(s)"""
|
||||||
|
|
@ -331,25 +394,27 @@ class WindowsBuild(object):
|
||||||
script.write('\n')
|
script.write('\n')
|
||||||
script.close()
|
script.close()
|
||||||
cmd = ['/bin/bash', '-e', '-x', tmpname]
|
cmd = ['/bin/bash', '-e', '-x', tmpname]
|
||||||
ret, output = run(cmd, chdir=self.workdir, logfile=self.logfile)
|
ret, output = run(cmd, chdir=self.source_dir, logfile=self.logfile)
|
||||||
if ret:
|
if ret:
|
||||||
raise BuildError, 'Build command failed, see %s for details' % \
|
raise BuildError, 'Build command failed, see %s for details' % \
|
||||||
os.path.basename(self.logfile.name)
|
os.path.basename(self.logfile.name)
|
||||||
|
|
||||||
def virusCheck(self):
|
def virusCheck(self):
|
||||||
"""check the build output for viruses"""
|
"""Check the build output for viruses"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def gatherResults(self):
|
def gatherResults(self):
|
||||||
"""gather information about the output from the build, return it"""
|
"""Gather information about the output from the build, return it"""
|
||||||
return {'name': self.name, 'version': self.version, 'release': self.release,
|
return {'name': self.name, 'version': self.version, 'release': self.release,
|
||||||
'description': self.description, 'platform': self.platform,
|
'description': self.description, 'platform': self.platform,
|
||||||
'provides': self.provides,
|
'provides': self.provides,
|
||||||
'output': self.output, 'logs': self.logs}
|
'output': self.output, 'logs': self.logs}
|
||||||
|
|
||||||
def doAll(self):
|
def run(self):
|
||||||
"""helper function that runs the entire process"""
|
"""Run the entire build process"""
|
||||||
self.checkEnv()
|
self.checkEnv()
|
||||||
|
self.checkout()
|
||||||
|
self.loadConfig()
|
||||||
self.fetchBuildReqs()
|
self.fetchBuildReqs()
|
||||||
self.build()
|
self.build()
|
||||||
self.virusCheck()
|
self.virusCheck()
|
||||||
|
|
@ -430,13 +495,8 @@ def upload_file(server, prefix, path):
|
||||||
fobj.close()
|
fobj.close()
|
||||||
server.verifyChecksum(path, sum.hexdigest(), 'sha1')
|
server.verifyChecksum(path, sum.hexdigest(), 'sha1')
|
||||||
|
|
||||||
def upload_results(server, codir, results):
|
|
||||||
"""upload the results of a build given the results dict"""
|
|
||||||
for filename in results['output'].keys() + results['logs']:
|
|
||||||
upload_file(server, codir, filename)
|
|
||||||
|
|
||||||
def get_mgmt_server():
|
def get_mgmt_server():
|
||||||
"""retrieve scmurls from kojivmd we'll use to build from"""
|
"""Get a ServerProxy object we can use to retrieve task info"""
|
||||||
macaddr, gateway = find_net_info()
|
macaddr, gateway = find_net_info()
|
||||||
while not (macaddr and gateway):
|
while not (macaddr and gateway):
|
||||||
# wait for the network connection to come up and get an address
|
# wait for the network connection to come up and get an address
|
||||||
|
|
@ -461,50 +521,9 @@ def get_options():
|
||||||
parser = OptionParser(usage=usage)
|
parser = OptionParser(usage=usage)
|
||||||
parser.add_option('-i', '--install', action='store_true', help='Install this daemon as a service', default=False)
|
parser.add_option('-i', '--install', action='store_true', help='Install this daemon as a service', default=False)
|
||||||
parser.add_option('-u', '--uninstall', action='store_true', help='Uninstall this daemon if it was installed previously as a service', default=False)
|
parser.add_option('-u', '--uninstall', action='store_true', help='Uninstall this daemon if it was installed previously as a service', default=False)
|
||||||
parser.add_option('-s', '--scmurl', help='Forcibly specify an scmurl to checkout from')
|
|
||||||
(options, args) = parser.parse_args()
|
(options, args) = parser.parse_args()
|
||||||
return options
|
return options
|
||||||
|
|
||||||
def apply_patches(src_dir, patch_dir, logfile):
|
|
||||||
patches = [patch for patch in os.listdir(patch_dir) if \
|
|
||||||
os.path.isfile(os.path.join(patch_dir, patch)) and \
|
|
||||||
not patch.startswith('.')]
|
|
||||||
if not patches:
|
|
||||||
raise BuildError, 'no patches found at %s' % patch_dir
|
|
||||||
patches.sort()
|
|
||||||
for patch in patches:
|
|
||||||
cmd = ['/usr/bin/patch', '--verbose', '-d', src_dir, '-p1', '-i', os.path.join(patch_dir, patch)]
|
|
||||||
ret, output = run(cmd, logfile=logfile)
|
|
||||||
if ret:
|
|
||||||
raise BuildError, 'error applying patches, output was: %s' % output
|
|
||||||
|
|
||||||
def ensuredir(path):
|
|
||||||
if not os.path.isdir(path):
|
|
||||||
os.makedirs(path)
|
|
||||||
return path
|
|
||||||
|
|
||||||
def run_build(workdir, source_url, build_tag, task_opts, logfile):
|
|
||||||
"""run the build"""
|
|
||||||
src_scm = SCM(source_url)
|
|
||||||
src_dir = src_scm.checkout(ensuredir(os.path.join(workdir, 'source')), logfile)
|
|
||||||
if 'specfile' in task_opts:
|
|
||||||
spec_scm = SCM(task_opts['specfile'])
|
|
||||||
spec_dir = spec_scm.checkout(ensuredir(os.path.join(workdir, 'spec')), logfile)
|
|
||||||
else:
|
|
||||||
spec_dir = src_dir
|
|
||||||
if 'patches' in task_opts:
|
|
||||||
patch_scm = SCM(task_opts['patches'])
|
|
||||||
patch_dir = patch_scm.checkout(ensuredir(os.path.join(workdir, 'patches')), logfile)
|
|
||||||
apply_patches(src_dir, patch_dir, logfile)
|
|
||||||
|
|
||||||
specfile = [spec for spec in os.listdir(spec_dir) if spec.endswith('.ini')]
|
|
||||||
if len(specfile) == 0:
|
|
||||||
raise BuildError, 'No .ini file found'
|
|
||||||
elif len(specfile) > 1:
|
|
||||||
raise BuildError, 'Multiple .ini files found'
|
|
||||||
winbld = WindowsBuild(os.path.join(spec_dir, specfile[0]), build_tag, src_dir, task_opts, logfile)
|
|
||||||
return winbld.doAll(), src_dir
|
|
||||||
|
|
||||||
def flunk(server, logfile):
|
def flunk(server, logfile):
|
||||||
"""do the right thing when a build fails"""
|
"""do the right thing when a build fails"""
|
||||||
exc_info = sys.exc_info()
|
exc_info = sys.exc_info()
|
||||||
|
|
@ -544,32 +563,21 @@ if __name__ == '__main__':
|
||||||
else:
|
else:
|
||||||
print 'Successfully removed the %s service' % prog
|
print 'Successfully removed the %s service' % prog
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
server = None
|
server = None
|
||||||
logfile = None
|
logfile = None
|
||||||
try:
|
try:
|
||||||
source_url = None
|
logfile = file('/tmp/build.log', 'w')
|
||||||
task_opts = None
|
server = get_mgmt_server()
|
||||||
if opts.scmurl:
|
build = WindowsBuild(server, logfile)
|
||||||
source_url = opts.scmurl
|
results = build.run()
|
||||||
else:
|
|
||||||
server = get_mgmt_server()
|
|
||||||
info = server.getTaskInfo()
|
|
||||||
source_url = info[0]
|
|
||||||
build_tag = info[1]
|
|
||||||
if len(info) > 2:
|
|
||||||
task_opts = info[2]
|
|
||||||
if not task_opts:
|
|
||||||
task_opts = {}
|
|
||||||
workdir = '/tmp/workdir'
|
|
||||||
os.mkdir(workdir)
|
|
||||||
logfile = file(os.path.join(workdir, 'build.log'), 'w')
|
|
||||||
results, results_dir = run_build(workdir, source_url, build_tag, task_opts, logfile)
|
|
||||||
logfile.close()
|
logfile.close()
|
||||||
if server is not None:
|
|
||||||
upload_file(server, workdir, 'build.log')
|
upload_file(server, '/tmp', 'build.log')
|
||||||
upload_results(server, results_dir, results)
|
for filename in results['output'].keys() + results['logs']:
|
||||||
results['logs'].append('build.log')
|
upload_file(server, build.source_dir, filename)
|
||||||
server.closeTask(results)
|
results['logs'].append('build.log')
|
||||||
|
server.closeTask(results)
|
||||||
log('Build results: %s' % results)
|
log('Build results: %s' % results)
|
||||||
except:
|
except:
|
||||||
flunk(server, logfile)
|
flunk(server, logfile)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue