kojid: make use of --skip-stat configurable

hub: option to disable notifications
koji-shadow: build from original scm
fix boolean opts in kojid
fix notifications for no-target builds
fix some typos
This commit is contained in:
Mike McLean 2008-02-26 19:50:16 -05:00
parent 80b2b869dc
commit fbcc9def02
3 changed files with 109 additions and 35 deletions

View file

@ -1481,7 +1481,7 @@ class BuildTask(BaseTaskHandler):
self.opts = opts
if opts.get('arch_override') and not opts.get('scratch'):
raise koji.BuildError, "arch_override is only allowed for scratch builds"
if opts.has_key(repo_id):
if opts.has_key('repo_id'):
repo_info = session.repoInfo(opts['repo_id'])
repo_state = koji.REPO_STATES[repo_info['state']]
if repo_state not in ('READY', 'EXPIRED'):
@ -1494,7 +1494,9 @@ class BuildTask(BaseTaskHandler):
if not SCM.is_scm_url(src) and not opts.get('scratch') \
and not 'admin' in session.getUserPerms(task_info['owner']):
raise koji.BuildError, "only admins may peform non-scratch builds from srpm"
target_info = session.getBuildTarget(target)
target_info = None
if target:
target_info = session.getBuildTarget(target)
if target_info:
dest_tag = target_info['dest_tag']
build_tag = target_info['build_tag']
@ -1506,7 +1508,7 @@ class BuildTask(BaseTaskHandler):
else:
# if repo_id is specified, we can allow the 'target' arg to simply specify
# the destination tag (since the repo specifies the build tag).
if not opts.has_key(repo_id):
if not opts.has_key('repo_id'):
raise koji.GenericError, 'unknown build target: %s' % target
build_tag = repo_info['tag_id']
if target is None:
@ -2120,8 +2122,10 @@ Build Info: %(weburl)s/buildinfo?buildID=%(build_id)i\r
build_nvr = koji.buildLabel(build)
build_id = build['id']
build_owner = build['owner_name']
# target comes from session.py:_get_build_target()
dest_tag = target['dest_tag_name']
# target comes from session.py:_get_build_target()
dest_tag = None
if target is not None:
dest_tag = target['dest_tag_name']
status = koji.BUILD_STATES[build['state']].lower()
creation_time = koji.formatTimeLong(build['creation_time'])
completion_time = koji.formatTimeLong(build['completion_time'])
@ -2289,7 +2293,8 @@ class CreaterepoTask(BaseTaskHandler):
koji.ensuredir(datadir)
os.system('cp -a %s/* %s' % (olddatadir, datadir))
cmd.append('--update')
cmd.append('--skip-stat')
if options.createrepo_skip_stat:
cmd.append('--skip-stat')
# note: we can't easily use a cachedir because we do not have write
# permission. The good news is that with --update we won't need to
# be scanning many rpms.
@ -2660,6 +2665,7 @@ def get_options():
'max_retries': 120,
'offline_retry': True,
'offline_retry_interval': 120,
'createrepo_skip_stat': True,
'pkgurl': None,
'allowed_scms': '',
'cert': '/etc/kojid/client.crt',
@ -2673,6 +2679,8 @@ def get_options():
defaults[name] = int(value)
except ValueError:
quit("value for %s option must be a valid integer" % name)
elif name in ['offline_retry', 'createrepo_skip_stat']:
defaults[name] = config.getboolean('kojid', name)
elif name in defaults.keys():
defaults[name] = value
else:

View file

@ -3531,7 +3531,11 @@ def _get_build_target(task_id):
task = Task(task_id)
request = task.getRequest()
# request is (path-to-srpm, build-target-name, map-of-other-options)
return get_build_targets(request[1])[0]
ret = get_build_targets(request[1])
if ret:
return ret[0]
else:
return None
def get_notification_recipients(build, tag_id, state):
"""
@ -3545,31 +3549,44 @@ def get_notification_recipients(build, tag_id, state):
for this tag and the user who submitted the build. The list will not contain
duplicates.
"""
package_id = build['package_id']
query = """SELECT email FROM build_notifications
WHERE ((package_id = %(package_id)i OR package_id IS NULL)
AND (tag_id = %(tag_id)i OR tag_id IS NULL))
"""
if state != koji.BUILD_STATES['COMPLETE']:
query += """AND success_only = FALSE
"""
clauses = []
emails = [result[0] for result in _fetchMulti(query, locals())]
if build:
package_id = build['package_id']
clauses.append('package_id = %(package_id)i OR package_id IS NULL')
else:
clauses.append('package_id IS NULL')
if tag_id:
clauses.append('tag_id = %(tag_id)i OR tag_id IS NULL')
else:
clauses.append('tag_id IS NULL')
if state != koji.BUILD_STATES['COMPLETE']:
clauses.append('success_only = FALSE')
query = QueryProcessor(columns=('email',), tables=['build_notifications'],
clauses=clauses, values=locals(),
opts={'asList':True})
emails = [result[0] for result in query.execute()]
email_domain = context.opts['EmailDomain']
# user who submitted the build
emails.append('%s@%s' % (build['owner_name'], email_domain))
packages = readPackageList(pkgID=package_id, tagID=tag_id, inherit=True)
# owner of the package in this tag, following inheritance
emails.append('%s@%s' % (packages[package_id]['owner_name'], email_domain))
if tag_id:
packages = readPackageList(pkgID=package_id, tagID=tag_id, inherit=True)
# owner of the package in this tag, following inheritance
emails.append('%s@%s' % (packages[package_id]['owner_name'], email_domain))
#FIXME - if tag_id is None, we don't have a good way to get the package owner.
# using all package owners from all tags would be way overkill.
emails_uniq = dict(zip(emails, [1] * len(emails))).keys()
return emails_uniq
def tag_notification(is_successful, tag_id, from_id, build_id, user_id, ignore_success=False, failure_msg=''):
if context.opts.get('DisableNotifications', 'no') == 'yes':
return
if is_successful:
state = koji.BUILD_STATES['COMPLETE']
else:
@ -3594,15 +3611,21 @@ def tag_notification(is_successful, tag_id, from_id, build_id, user_id, ignore_s
return None
def build_notification(task_id, build_id):
if context.opts.get('DisableNotifications', 'no') == 'yes':
return
build = get_build(build_id)
target = _get_build_target(task_id)
dest_tag = None
if target:
dest_tag = target['dest_tag']
if build['state'] == koji.BUILD_STATES['BUILDING']:
raise koji.GenericError, 'never send notifications for incomplete builds'
web_url = context.opts.get('KojiWebURL', 'http://localhost/koji')
recipients = get_notification_recipients(build, target['dest_tag'], build['state'])
recipients = get_notification_recipients(build, dest_tag, build['state'])
if len(recipients) > 0:
make_task('buildNotification', [recipients, build, target, web_url])

View file

@ -376,6 +376,23 @@ class TrackedBuild(object):
if self.tracker:
self.tracker.state_idx.setdefault(self.state, {})[self.id] = 1
def getSource(self):
"""Get source from remote"""
task_id = self.info['task_id']
if task_id:
tinfo = remote.getTaskInfo(task_id)
if tinfo['method'] == 'build':
try:
request = remote.getTaskRequest(task_id)
src = request[0]
#XXX - Move SCM class out of kojid and use it to check for scm url
if src.startswith('cvs:'):
return src
except:
pass
#TODO - otherwise we just have to download the srpm
return None #XXX
def addChild(self, child):
self.children[child] = 1
@ -393,6 +410,10 @@ class TrackedBuild(object):
#while we've got the rpm list, let's note the extra arches
#XXX - really should reorganize this a bit
self.setExtraArchesFromRPMs(rpms)
#also, might as well note the src rpm
for rinfo in rpms:
if rinfo['arch'] == 'src':
self.srpm = rinfo
brs = {}
bad = []
for rinfo in rpms:
@ -677,16 +698,29 @@ class BuildTracker(object):
# current latest repo for tag
session.getLastEvent()
results = session.multiCall()
[event_id, event_ts] = results[-1]
[event_id, event_ts] = results[0][-1]
#TODO - verify / check results ?
task_id = session.newRepo(our_tag)
#TODO - upload src
# [?] use remote SCM url (if avail)?
src = "" #XXX
#TODO - wait for repo task
# ...and verify repo
#TODO - kick off build
#task_id = session.build(src, taginfo['name'], opts={'repo_id': repo_id} )
src = build.getSource()
if not src:
print "Couldn't get source for %s" % build.nvr
return None
#wait for repo task
while True:
tinfo = session.getTaskInfo(task_id)
tstate = koji.TASK_STATES[tinfo['state']]
if tstate == 'CLOSED':
break
elif tstate in ('CANCELED', 'FAILED'):
print "Error: failed to generate repo"
return None
#add a timeout?
#TODO ...and verify repo
repo_id, event_id = session.getTaskResult(task_id)
#kick off build
task_id = session.build(src, None, opts={'repo_id': repo_id} )
return task_id
def report(self):
@ -721,9 +755,13 @@ class BuildTracker(object):
while True:
print "available: %i, missing: %i, pending: %i, problem: %i" \
% (len(b_avail), len(b_missing), len(b_pending), len(b_problem))
if not b_pending and not b_missing:
#we're done
break
if not b_missing:
if not b_pending:
#we're done
break
else:
print "Waiting on %i jobs to finish" % len(b_pending)
time.sleep(30)
for build_id, task_id in b_pending.items():
#check pending builds
build = self.builds[build_id]
@ -763,6 +801,11 @@ class BuildTracker(object):
b_problem[build_id] = build
print_builds(problem)
continue
pending = [x for x in build.deps.iterkeys() if b_pending.get(x)]
if pending:
#deps for this build are currently building
print "%s, Waiting on %i deps" % (build.nvr, len(pending))
continue
missing = [x for x in build.deps.iterkeys() if b_missing.get(x)]
if missing:
#this indicates an ordering problem
@ -770,11 +813,6 @@ class BuildTracker(object):
print "Out of order: %s, missing %i deps" % (build.nvr, len(missing))
print_builds(missing)
continue
pending = [x for x in build.deps.iterkeys() if b_pending.get(x)]
if pending:
#deps for this build are currently building
print "%s, Waiting on %i deps" % (build.nvr, len(pending))
continue
not_avail = [x for x in build.deps.iterkeys() if not b_avail.get(x)]
if not_avail:
#In theory this should not happen
@ -789,10 +827,15 @@ class BuildTracker(object):
del b_missing[build_id]
if options.test:
#pretend build is available
b_avail[build_id] = 1
b_avail[build_id] = build
build.state = 'common' #XXX
elif not task_id:
#something went wrong setting up the rebuild
b_problem[build_id] = build
print_builds(problem)
else:
b_pending[build_id] = task_id
time.sleep(15)
print "Rebuilt %i builds" % (len(b_avail) - initial_avail)
def showOrder(self):