From e9b5ca869a57155bdd69d8e0c24f6898d2ecd6cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20Schr=C3=B6ter?= Date: Wed, 19 May 2010 18:36:38 +0200 Subject: [PATCH] support source validators as pre-checkin check --- NEWS | 1 + osc/commandline.py | 29 +++++++++++++++++++++++++---- osc/conf.py | 5 +++++ osc/core.py | 14 ++++++++++---- osc/oscerr.py | 7 +++++++ 5 files changed, 48 insertions(+), 8 deletions(-) diff --git a/NEWS b/NEWS index 78d033cc..7e5f817f 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,7 @@ - fix creation of package link, when target project has the package via linked project - add "osc rq approvenew $PROJECT" command to show and accept all request in new state. This makes sense esp. for projects which work with default reviewers before. + - support external source validator script before commiting # # Features which require OBS 2.0 # diff --git a/osc/commandline.py b/osc/commandline.py index 40ebd3f9..cb829862 100644 --- a/osc/commandline.py +++ b/osc/commandline.py @@ -2370,6 +2370,8 @@ Please submit there instead, or use --nodevelproject to force direct submission. help='read log message from FILE') @cmdln.option('-f', '--force', default=False, action="store_true", help='force commit - do not tests a file list') + @cmdln.option('--skip-validator', default=False, action="store_true", + help='Skip the source validator') def do_commit(self, subcmd, opts, *args): """${cmd_name}: Upload content to the repository server @@ -2398,6 +2400,13 @@ Please submit there instead, or use --nodevelproject to force direct submission. args = parseargs(args) msg = '' + validator = conf.config['source_validator'] + if opts.skip_validator: + validator = None + elif not os.path.exists(validator): + print "WARNING: validator", validator, "configured, but not existing. Skipping ..." + validator = None + if opts.message: msg = opts.message elif opts.file: @@ -2409,9 +2418,13 @@ Please submit there instead, or use --nodevelproject to force direct submission. arg_list = args[:] for arg in arg_list: if conf.config['do_package_tracking'] and is_project_dir(arg): - Project(arg).commit(msg=msg) if not msg: msg = edit_message() + try: + Project(arg).commit(msg=msg, validator=validator) + except oscerr.RuntimeError, e: + print >>sys.stderr, "ERROR: source_validator failed", e + return 1 args.remove(arg) pacs = findpacs(args) @@ -2458,12 +2471,20 @@ Please submit there instead, or use --nodevelproject to force direct submission. else: single_paths.append(pac.dir) for prj, packages in prj_paths.iteritems(): - Project(prj).commit(tuple(packages), msg, files) + try: + Project(prj).commit(tuple(packages), msg, files, validator=validator) + except oscerr.RuntimeError, e: + print >>sys.stderr, "ERROR: source_validator failed", e + return 1 for pac in single_paths: - Package(pac).commit(msg) + try: + Package(pac).commit(msg, validator=validator) + except oscerr.RuntimeError, e: + print >>sys.stderr, "ERROR: source_validator failed", e + return 1 else: for p in pacs: - p.commit(msg) + p.commit(msg, validator=validator) store_unlink_file(os.path.abspath('.'), '_commit_msg') diff --git a/osc/conf.py b/osc/conf.py index 0528959d..a9450461 100644 --- a/osc/conf.py +++ b/osc/conf.py @@ -112,6 +112,8 @@ DEFAULTS = { 'apiurl': 'https://api.opensuse.org', 'request_list_days': 30, # check for unversioned/removed files before commit 'check_filelist': '1', + # External script to validate sources, esp before commit + 'source_validator': '/usr/lib/osc/source_validator', # check for pending requests after executing an action (e.g. checkout, update, commit) 'check_for_request_on_action': '0', # what to do with the source package if the submitrequest has been accepted @@ -251,6 +253,9 @@ apiurl = %(apiurl)s #review requests interactively (default: off) #request_show_review = 1 +# Executable to validate sources, esp before committing +#source_validator = /usr/lib/osc/source_validator + [%(apiurl)s] user = %(user)s pass = %(pass)s diff --git a/osc/core.py b/osc/core.py index 7fcfb88a..9b755844 100644 --- a/osc/core.py +++ b/osc/core.py @@ -624,7 +624,7 @@ class Project: finally: self.write_packages() - def commit(self, pacs = (), msg = '', files = {}): + def commit(self, pacs = (), msg = '', files = {}, validator = None): if len(pacs): try: for pac in pacs: @@ -643,7 +643,7 @@ class Project: else: p = Package(os.path.join(self.dir, pac)) p.todo = todo - p.commit(msg) + p.commit(msg, validator=validator) elif pac in self.pacs_unvers and not is_package_dir(os.path.join(self.dir, pac)): print 'osc: \'%s\' is not under version control' % pac elif pac in self.pacs_broken: @@ -663,7 +663,7 @@ class Project: state = self.get_state(pac) if state == ' ': # do a simple commit - Package(os.path.join(self.dir, pac)).commit(msg) + Package(os.path.join(self.dir, pac)).commit(msg, validator=validator) elif state == 'D': self.commitDelPackage(pac) elif state == 'A': @@ -896,7 +896,7 @@ class Package: shutil.copyfile(os.path.join(self.dir, n), os.path.join(self.storedir, n)) - def commit(self, msg=''): + def commit(self, msg='', validator=None): # commit only if the upstream revision is the same as the working copy's upstream_rev = self.latest_rev() if self.rev != upstream_rev: @@ -907,6 +907,12 @@ class Package: pathn = getTransActPath(self.dir) + if validator: + import subprocess + p = subprocess.Popen([validator], close_fds=True) + if p.wait() != 0: + raise oscerr.RuntimeError(p.stdout, validator ) + have_conflicts = False for filename in self.todo: if not filename.startswith('_service:') and not filename.startswith('_service_'): diff --git a/osc/oscerr.py b/osc/oscerr.py index f2b6e2a0..2822daaa 100644 --- a/osc/oscerr.py +++ b/osc/oscerr.py @@ -41,6 +41,13 @@ class NoConfigfile(OscBaseError): self.file = fname self.msg = msg +class RuntimeError(OscBaseError): + """Exception raised when there is a runtime error of an external tool""" + def __init__(self, msg, fname): + OscBaseError.__init__(self) + self.msg = msg + self.file = fname + class WrongArgs(OscBaseError): """Exception raised by the cli for wrong arguments usage"""