- pull changelog entries directly from the file on the filesystem
- don't populate the changelogs table
This commit is contained in:
parent
f1a36d48b5
commit
48a49e650d
3 changed files with 104 additions and 108 deletions
|
|
@ -1656,7 +1656,6 @@ class BuildTask(BaseTaskHandler):
|
|||
if not self.opts.get('scratch'):
|
||||
#scratch builds do not get imported
|
||||
build_id = session.host.initBuild(data)
|
||||
session.host.importChangelog(build_id, srpm)
|
||||
#(initBuild raises an exception if there is a conflict)
|
||||
try:
|
||||
srpm,rpms,brmap,logs = self.runBuilds(srpm,build_tag,archlist,repo_info['id'])
|
||||
|
|
|
|||
186
hub/kojihub.py
186
hub/kojihub.py
|
|
@ -22,6 +22,7 @@
|
|||
# Cristian Balint <cbalint@redhat.com>
|
||||
|
||||
import base64
|
||||
import calendar
|
||||
import koji
|
||||
import koji.auth
|
||||
import koji.db
|
||||
|
|
@ -3010,47 +3011,6 @@ def list_channels(hostID=None):
|
|||
WHERE host_channels.host_id = %(hostID)i"""
|
||||
return _multiRow(query, locals(), fields)
|
||||
|
||||
def get_changelog_entries(buildID, author=None, before=None, after=None, queryOpts=None):
|
||||
"""Get changelog entries for the build with the given ID.
|
||||
|
||||
- author: only return changelogs with a matching author
|
||||
- before: only return changelogs from before the given date
|
||||
(a datetime object or a string in the 'YYYY-MM-DD HH24:MI:SS format)
|
||||
- after: only return changelogs from after the given date
|
||||
(a datetime object or a string in the 'YYYY-MM-DD HH24:MI:SS format)
|
||||
- queryOpts: query options used by the QueryProcessor
|
||||
|
||||
If "order" is not specified in queryOpts, results will be returned in reverse chronological
|
||||
order.
|
||||
|
||||
Results will be returned as a list of maps with 'date', 'author', and 'text' keys.
|
||||
If there are no results, an empty list will be returned.
|
||||
"""
|
||||
fields = ('id', 'date', 'author', 'text')
|
||||
|
||||
if not queryOpts:
|
||||
queryOpts = {}
|
||||
if not queryOpts.has_key('order'):
|
||||
# newest entries will be inserted first, because of
|
||||
# the way entries are sorted in the spec file
|
||||
queryOpts['order'] = 'id'
|
||||
|
||||
clauses = ['changelogs.build_id = %(buildID)i']
|
||||
if author:
|
||||
clauses.append('changelogs.author = %(author)s')
|
||||
if before:
|
||||
if isinstance(before, datetime.datetime):
|
||||
before = str(before)
|
||||
clauses.append('changelogs.date < %(before)s')
|
||||
if after:
|
||||
if isinstance(after, datetime.datetime):
|
||||
after = str(after)
|
||||
clauses.append('changelogs.date > %(after)s')
|
||||
|
||||
query = QueryProcessor(columns=fields, tables=('changelogs',),
|
||||
clauses=clauses, values=locals(), opts=queryOpts)
|
||||
return query.execute()
|
||||
|
||||
def new_package(name,strict=True):
|
||||
c = context.cnx.cursor()
|
||||
# TODO - table lock?
|
||||
|
|
@ -3111,9 +3071,6 @@ def new_build(data):
|
|||
WHERE id = %(id)i"""
|
||||
data['id'] = id
|
||||
_dml(update, data)
|
||||
# delete any now-obsolete changelogs
|
||||
delete = """DELETE FROM changelogs WHERE build_id=%(id)i"""
|
||||
_dml(delete, data)
|
||||
return id
|
||||
raise koji.GenericError, "Build already exists (id=%d, state=%s): %r" \
|
||||
% (id, st_desc, data)
|
||||
|
|
@ -3296,9 +3253,6 @@ def import_rpm(fn,buildinfo=None,brootid=None):
|
|||
"""
|
||||
_dml(q, locals())
|
||||
|
||||
# - add changelog entries, if not already present
|
||||
import_changelog(buildinfo, fn)
|
||||
|
||||
rpminfo['id'] = rpminfo_id
|
||||
return rpminfo
|
||||
|
||||
|
|
@ -3367,38 +3321,6 @@ def add_external_rpm(rpminfo, external_repo, strict=True):
|
|||
|
||||
return get_rpm(rpminfo['id'])
|
||||
|
||||
def import_changelog(buildinfo, rpmfile, replace=False):
|
||||
"""Import the changelog from the given rpm into the build with the
|
||||
given ID. If the build already has changelog info and replace is True,
|
||||
the existing info is cleared and the changelog info from the rpm is imported.
|
||||
If replace is False, nothing is done."""
|
||||
hdr = koji.get_rpm_header(rpmfile)
|
||||
|
||||
build_id = buildinfo['id']
|
||||
|
||||
if len(get_changelog_entries(buildID=build_id)) != 0:
|
||||
# the changelog for this build has already been imported
|
||||
if replace:
|
||||
delete = """DELETE FROM changelogs WHERE build_id=%(build_id)i"""
|
||||
_dml(delete, locals())
|
||||
else:
|
||||
return
|
||||
|
||||
cltimelist = hdr['CHANGELOGTIME']
|
||||
# If there is exactly one changelog entry, CHANGELOGTIME is returned as
|
||||
# an int, instead of a list.
|
||||
if isinstance(cltimelist, int):
|
||||
cltimelist = [cltimelist]
|
||||
for cltime, clauthor, cltext in zip(cltimelist, hdr['CHANGELOGNAME'],
|
||||
hdr['CHANGELOGTEXT']):
|
||||
cltime = datetime.datetime.fromtimestamp(cltime).isoformat(' ')
|
||||
clauthor = koji.fixEncoding(clauthor)
|
||||
cltext = koji.fixEncoding(cltext)
|
||||
q = """INSERT INTO changelogs (build_id, date, author, text) VALUES
|
||||
(%(build_id)d, %(cltime)s, %(clauthor)s, %(cltext)s)
|
||||
"""
|
||||
_dml(q, locals())
|
||||
|
||||
def import_build_log(fn, buildinfo, subdir=None):
|
||||
"""Move a logfile related to a build to the right place"""
|
||||
logdir = koji.pathinfo.build_logs(buildinfo)
|
||||
|
|
@ -3851,7 +3773,6 @@ def _delete_build(binfo):
|
|||
# build-related data:
|
||||
# build KEEP (marked deleted)
|
||||
# task ??
|
||||
# changelogs DELETE
|
||||
# tag_listing REVOKE (versioned) (but should ideally be empty anyway)
|
||||
# rpminfo KEEP
|
||||
# buildroot_listing KEEP (but should ideally be empty anyway)
|
||||
|
|
@ -3869,8 +3790,6 @@ def _delete_build(binfo):
|
|||
_dml(delete, locals())
|
||||
delete = """DELETE FROM rpmsigs WHERE rpm_id=%(rpm_id)i"""
|
||||
_dml(delete, locals())
|
||||
delete = """DELETE FROM changelogs WHERE build_id=%(build_id)i"""
|
||||
_dml(delete, locals())
|
||||
event_id = _singleValue("SELECT get_event()")
|
||||
update = """UPDATE tag_listing SET revoke_event=%(event_id)i, active=NULL
|
||||
WHERE active = TRUE AND build_id=%(build_id)i"""
|
||||
|
|
@ -3918,8 +3837,6 @@ def reset_build(build):
|
|||
_dml(delete, locals())
|
||||
delete = """DELETE FROM rpminfo WHERE build_id=%(id)i"""
|
||||
_dml(delete, binfo)
|
||||
delete = """DELETE FROM changelogs WHERE build_id=%(id)i"""
|
||||
_dml(delete, binfo)
|
||||
binfo['state'] = koji.BUILD_STATES['CANCELED']
|
||||
update = """UPDATE build SET state=%(state)i, task_id=NULL WHERE id=%(id)i"""
|
||||
_dml(update, binfo)
|
||||
|
|
@ -5193,7 +5110,84 @@ class RootExports(object):
|
|||
return query.execute()
|
||||
|
||||
getBuild = staticmethod(get_build)
|
||||
getChangelogEntries = staticmethod(get_changelog_entries)
|
||||
|
||||
def getChangelogEntries(self, buildID, author=None, before=None, after=None, queryOpts=None):
|
||||
"""Get changelog entries for the build with the given ID.
|
||||
|
||||
- author: only return changelogs with a matching author
|
||||
- before: only return changelogs from before the given date (in UTC)
|
||||
(a datetime object, a string in the 'YYYY-MM-DD HH24:MI:SS format, or integer seconds
|
||||
since the epoch)
|
||||
- after: only return changelogs from after the given date (in UTC)
|
||||
(a datetime object, a string in the 'YYYY-MM-DD HH24:MI:SS format, or integer seconds
|
||||
since the epoch)
|
||||
- queryOpts: query options used by the QueryProcessor
|
||||
|
||||
If "order" is not specified in queryOpts, results will be returned in reverse chronological
|
||||
order.
|
||||
|
||||
Results will be returned as a list of maps with 'date', 'author', and 'text' keys.
|
||||
If there are no results, an empty list will be returned.
|
||||
"""
|
||||
if queryOpts is None:
|
||||
queryOpts = {}
|
||||
if queryOpts.get('order') in ('date', '-date'):
|
||||
# use a numeric sort on the timestamp instead of an alphabetic sort on the
|
||||
# date string
|
||||
queryOpts['order'] = queryOpts['order'].replace('date', 'date_ts')
|
||||
build_info = get_build(buildID)
|
||||
if not build_info:
|
||||
return _applyQueryOpts([], queryOpts)
|
||||
srpms = self.listRPMs(buildID=build_info['id'], arches='src')
|
||||
if not srpms:
|
||||
return _applyQueryOpts([], queryOpts)
|
||||
srpm_info = srpms[0]
|
||||
srpm_path = os.path.join(koji.pathinfo.build(build_info), koji.pathinfo.rpm(srpm_info))
|
||||
if not os.path.exists(srpm_path):
|
||||
return _applyQueryOpts([], queryOpts)
|
||||
|
||||
if before:
|
||||
if isinstance(before, datetime.datetime):
|
||||
before = calendar.timegm(before.utctimetuple())
|
||||
elif isinstance(before, (str, unicode)):
|
||||
before = koji.util.parseTime(before)
|
||||
elif isinstance(before, (int, long)):
|
||||
pass
|
||||
else:
|
||||
raise koji.GenericError, 'invalid type for before: %s' % type(before)
|
||||
|
||||
if after:
|
||||
if isinstance(after, datetime.datetime):
|
||||
after = calendar.timegm(after.utctimetuple())
|
||||
elif isinstance(after, (str, unicode)):
|
||||
after = koji.util.parseTime(after)
|
||||
elif isinstance(after, (int, long)):
|
||||
pass
|
||||
else:
|
||||
raise koji.GenericError, 'invalid type for after: %s' % type(after)
|
||||
|
||||
results = []
|
||||
|
||||
fields = koji.get_header_fields(srpm_path, ['changelogtime', 'changelogname', 'changelogtext'])
|
||||
for (cltime, clname, cltext) in zip(fields['changelogtime'], fields['changelogname'],
|
||||
fields['changelogtext']):
|
||||
cldate = datetime.datetime.fromtimestamp(cltime).isoformat(' ')
|
||||
clname = koji.fixEncoding(clname)
|
||||
cltext = koji.fixEncoding(cltext)
|
||||
|
||||
if author and author != clname:
|
||||
continue
|
||||
if before and not cltime < before:
|
||||
continue
|
||||
if after and not cltime > after:
|
||||
continue
|
||||
|
||||
if queryOpts.get('asList'):
|
||||
results.append([cldate, clname, cltext])
|
||||
else:
|
||||
results.append({'date': cldate, 'date_ts': cltime, 'author': clname, 'text': cltext})
|
||||
|
||||
return _applyQueryOpts(results, queryOpts)
|
||||
|
||||
def cancelBuild(self, buildID):
|
||||
"""Cancel the build with the given buildID
|
||||
|
|
@ -7073,28 +7067,6 @@ class HostExports(object):
|
|||
host.verify()
|
||||
tag_notification(is_successful, tag_id, from_id, build_id, user_id, ignore_success, failure_msg)
|
||||
|
||||
def importChangelog(self, buildID, rpmfile):
|
||||
"""Import the changelog for the given build
|
||||
|
||||
The changelog data is pulled from the rpm provided.
|
||||
rpmfile must be a path relative to the 'work' dir.
|
||||
If the build already has changelog information, the existing
|
||||
changelog information is cleared and the changelog from the
|
||||
given rpm is imported."""
|
||||
host = Host()
|
||||
host.verify()
|
||||
|
||||
build = get_build(buildID, strict=True)
|
||||
taskID = build['task_id']
|
||||
if not taskID:
|
||||
raise koji.GenericError, 'no task for build %i' % build['id']
|
||||
|
||||
task = Task(taskID)
|
||||
task.assertHost(host.id)
|
||||
|
||||
rpmfile = '%s/%s' % (koji.pathinfo.work(), rpmfile)
|
||||
import_changelog(build, rpmfile, replace=True)
|
||||
|
||||
def checkPolicy(self, name, data, default='deny', strict=False):
|
||||
host = Host()
|
||||
host.verify()
|
||||
|
|
|
|||
25
koji/util.py
25
koji/util.py
|
|
@ -14,6 +14,8 @@
|
|||
# License along with this software; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
import calendar
|
||||
import re
|
||||
import time
|
||||
import koji
|
||||
|
||||
|
|
@ -32,6 +34,29 @@ def formatChangelog(entries):
|
|||
|
||||
return result
|
||||
|
||||
DATE_RE = re.compile(r'(\d+)-(\d+)-(\d+)')
|
||||
TIME_RE = re.compile(r'(\d+):(\d+):(\d+)')
|
||||
|
||||
def parseTime(val):
|
||||
"""
|
||||
Parse a string time in either "YYYY-MM-DD HH24:MI:SS" or "YYYY-MM-DD"
|
||||
format into floating-point seconds since the epoch. If the time portion
|
||||
is not specified, it will be padded with zeros. The string time is treated
|
||||
as UTC. If the time string cannot be parsed into a valid date, None will be
|
||||
returned.
|
||||
"""
|
||||
result = DATE_RE.search(val)
|
||||
if not result:
|
||||
return None
|
||||
else:
|
||||
date = [int(r) for r in result.groups()]
|
||||
time = [0, 0, 0]
|
||||
rest = val[result.end():].strip()
|
||||
result = TIME_RE.search(rest)
|
||||
if result:
|
||||
time = [int(r) for r in result.groups()]
|
||||
return calendar.timegm(date + time + [0, 0, 0])
|
||||
|
||||
def checkForBuilds(session, tag, builds, event):
|
||||
"""Check that the builds existed in tag at the time of the event."""
|
||||
for build in builds:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue