diff --git a/koji/__init__.py b/koji/__init__.py index df9824a9..95a32bd4 100644 --- a/koji/__init__.py +++ b/koji/__init__.py @@ -211,6 +211,8 @@ BASEDIR = '/mnt/koji' # default task priority PRIO_DEFAULT = 20 +## BEGIN kojikamid dup + #Exceptions class GenericError(Exception): """Base class for our custom exceptions""" @@ -224,6 +226,7 @@ class GenericError(Exception): return str(self.args[0]) except: return str(self.__dict__) +## END kojikamid dup class LockConflictError(GenericError): """Raised when there is a lock conflict""" @@ -241,9 +244,12 @@ class ActionNotAllowed(GenericError): """Raised when the session does not have permission to take some action""" faultCode = 1004 +## BEGIN kojikamid dup + class BuildError(GenericError): """Raised when a build fails""" faultCode = 1005 +## END kojikamid dup class AuthLockError(AuthError): """Raised when a lock prevents authentication""" @@ -304,6 +310,7 @@ class MultiCallInProgress(object): """ pass + #A function to get create an exception from a fault def convertFault(fault): """Convert a fault to the corresponding Exception type, if possible""" @@ -378,12 +385,15 @@ def decode_args2(args, names, strict=True): ret.update(opts) return ret +## BEGIN kojikamid dup + def encode_int(n): """If n is too large for a 32bit signed, convert it to a string""" if n <= 2147483647: return n #else return str(n) +## END kojikamid dup def decode_int(n): """If n is not an integer, attempt to convert it""" @@ -401,6 +411,8 @@ def safe_xmlrpc_loads(s): except Fault, f: return f +## BEGIN kojikamid dup + def ensuredir(directory): """Create directory, if necessary.""" if os.path.isdir(directory): @@ -412,6 +424,7 @@ def ensuredir(directory): if not os.path.isdir(directory): #something else must have gone wrong raise +## END kojikamid dup def daemonize(): """Detach and run in background""" diff --git a/koji/daemon.py b/koji/daemon.py index 7dfad759..be4168ad 100644 --- a/koji/daemon.py +++ b/koji/daemon.py @@ -128,6 +128,9 @@ def log_output(session, path, args, outfile, uploadpath, cwd=None, logerror=0, a outfd.close() return status[1] + +## BEGIN kojikamid dup + class SCM(object): "SCM abstraction class" @@ -411,6 +414,8 @@ class SCM(object): return sourcedir +## END kojikamid dup + class TaskManager(object): diff --git a/vm/Makefile b/vm/Makefile index 6e959562..1dcab17a 100644 --- a/vm/Makefile +++ b/vm/Makefile @@ -6,10 +6,12 @@ _default: @echo "nothing to make. try make install" clean: - rm -f *.o *.so *.pyc *~ + rm -f *.o *.so *.pyc *~ kojikamid +kojikamid: kojikamid.py + bash fix_kojikamid.sh >kojikamid -install: +install: kojikamid @if [ "$(DESTDIR)" = "" ]; then \ echo " "; \ echo "ERROR: A destdir is required"; \ diff --git a/vm/fix_kojikamid.sh b/vm/fix_kojikamid.sh new file mode 100755 index 00000000..5b0f5c17 --- /dev/null +++ b/vm/fix_kojikamid.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +awk '/^## INSERT kojikamid dup/ {exit} {print $0}' kojikamid.py + +for fn in ../koji/__init__.py ../koji/daemon.py +do + awk '/^## END kojikamid dup/ {p=0} p {print $0} /^## BEGIN kojikamid dup/ {p=1}' $fn +done + +awk 'p {print $0} /^## INSERT kojikamid dup/ {p=1}' kojikamid.py diff --git a/vm/kojikamid.py b/vm/kojikamid.py index b089eeed..5c120a39 100755 --- a/vm/kojikamid.py +++ b/vm/kojikamid.py @@ -45,236 +45,8 @@ import glob MANAGER_PORT = 7000 -############################## -# Begin heinous copy and paste -############################## +## INSERT kojikamid dup -class GenericError(Exception): - """Base class for our custom exceptions""" - faultCode = 1000 - fromFault = False - def __str__(self): - try: - return str(self.args[0]['args'][0]) - except: - try: - return str(self.args[0]) - except: - return str(self.__dict__) - -class BuildError(GenericError): - """Raised when a build fails""" - faultCode = 1005 - -class SCM(object): - "SCM abstraction class" - - types = { 'CVS': ('cvs://',), - 'CVS+SSH': ('cvs+ssh://',), - 'GIT': ('git://', 'git+http://', 'git+https://', 'git+rsync://'), - 'GIT+SSH': ('git+ssh://',), - 'SVN': ('svn://', 'svn+http://', 'svn+https://'), - 'SVN+SSH': ('svn+ssh://',) } - - def is_scm_url(url): - """ - Return True if the url appears to be a valid, accessible source location, False otherwise - """ - for schemes in SCM.types.values(): - for scheme in schemes: - if url.startswith(scheme): - return True - else: - return False - is_scm_url = staticmethod(is_scm_url) - - def __init__(self, url): - """ - Initialize the SCM object using the specified url. - The expected url format is: - - scheme://[user@]host/path/to/repo?path/to/module#revision_or_tag_identifier - - The initialized SCM object will have the following attributes: - - url (the unmodified url) - - scheme - - user (may be null) - - host - - repository - - module - - revision - - scmtype - - The exact format of each attribute is SCM-specific, but the structure of the url - must conform to the template above, or an error will be raised. - """ - if not SCM.is_scm_url(url): - raise GenericError, 'Invalid SCM URL: %s' % url - - self.url = url - scheme, user, host, path, query, fragment = self._parse_url() - - self.scheme = scheme - self.user = user - self.host = host - self.repository = path - self.module = query - self.revision = fragment - - for scmtype, schemes in SCM.types.items(): - if self.scheme in schemes: - self.scmtype = scmtype - break - else: - # should never happen - raise GenericError, 'Invalid SCM URL: %s' % url - - def _parse_url(self): - """ - Parse the SCM url into usable components. - Return the following tuple: - - (scheme, user, host, path, query, fragment) - - user may be None, everything else will have a value - """ - # get the url's scheme - scheme = self.url.split('://')[0] + '://' - - # replace the scheme with http:// so that the urlparse works in all cases - dummyurl = self.url.replace(scheme, 'http://', 1) - dummyscheme, netloc, path, params, query, fragment = urlparse.urlparse(dummyurl) - - user = None - userhost = netloc.split('@') - if len(userhost) == 2: - user = userhost[0] - if not user: - # Don't return an empty string - user = None - elif ':' in user: - raise GenericError, 'username:password format not supported: %s' % user - netloc = userhost[1] - elif len(userhost) > 2: - raise GenericError, 'Invalid username@hostname specified: %s' % netloc - - # ensure that path and query do not end in / - if path.endswith('/'): - path = path[:-1] - if query.endswith('/'): - query = query[:-1] - - # check for validity: params should be empty, query may be empty, everything else should be populated - if params or not (scheme and netloc and path and fragment): - raise GenericError, 'Unable to parse SCM URL: %s' % self.url - - # return parsed values - return (scheme, user, netloc, path, query, fragment) - - def checkout(self, scmdir): - """ - Checkout the module from SCM. Accepts the following parameters: - - scmdir: the working directory - - Returns the directory that the module was checked-out into (a subdirectory of scmdir) - """ - # TODO: sanity check arguments - sourcedir = '%s/%s' % (scmdir, self.module) - - update_checkout_cmd = None - update_checkout_dir = None - - if self.scmtype == 'CVS': - pserver = ':pserver:%s@%s:%s' % ((self.user or 'anonymous'), self.host, self.repository) - module_checkout_cmd = ['cvs', '-d', pserver, 'checkout', '-r', self.revision, self.module] - - elif self.scmtype == 'CVS+SSH': - if not self.user: - raise BuildError, 'No user specified for repository access scheme: %s' % self.scheme - - cvsserver = ':ext:%s@%s:%s' % (self.user, self.host, self.repository) - module_checkout_cmd = ['cvs', '-d', cvsserver, 'checkout', '-r', self.revision, self.module] - - elif self.scmtype == 'GIT': - scheme = self.scheme - if '+' in scheme: - scheme = scheme.split('+')[1] - gitrepo = '%s%s%s' % (scheme, self.host, self.repository) - checkout_path = os.path.basename(self.repository) - if self.repository.endswith('/.git'): - checkout_path = os.path.basename(self.repository[:-5]) - elif self.repository.endswith('.git'): - checkout_path = os.path.basename(self.repository[:-4]) - - sourcedir = '%s/%s' % (scmdir, checkout_path) - module_checkout_cmd = ['git', 'clone', '-n', gitrepo, sourcedir] - update_checkout_cmd = ['git', 'reset', '--hard', self.revision] - update_checkout_dir = sourcedir - - # self.module may be empty, in which case the winspec should be in the top-level directory - if self.module: - # Treat the module as a directory inside the git repository - sourcedir = '%s/%s' % (sourcedir, self.module) - - elif self.scmtype == 'GIT+SSH': - if not self.user: - raise BuildError, 'No user specified for repository access scheme: %s' % self.scheme - gitrepo = 'git+ssh://%s@%s%s' % (self.user, self.host, self.repository) - checkout_path = os.path.basename(self.repository) - if self.repository.endswith('/.git'): - checkout_path = os.path.basename(self.repository[:-5]) - elif self.repository.endswith('.git'): - checkout_path = os.path.basename(self.repository[:-4]) - - sourcedir = '%s/%s' % (scmdir, checkout_path) - module_checkout_cmd = ['git', 'clone', '-n', gitrepo, sourcedir] - update_checkout_cmd = ['git', 'reset', '--hard', self.revision] - update_checkout_dir = sourcedir - - # self.module may be empty, in which case the winspec should be in the top-level directory - if self.module: - # Treat the module as a directory inside the git repository - sourcedir = '%s/%s' % (sourcedir, self.module) - - elif self.scmtype == 'SVN': - scheme = self.scheme - if '+' in scheme: - scheme = scheme.split('+')[1] - - svnserver = '%s%s%s' % (scheme, self.host, self.repository) - module_checkout_cmd = ['svn', 'checkout', '-r', self.revision, '%s/%s' % (svnserver, self.module), self.module] - - elif self.scmtype == 'SVN+SSH': - if not self.user: - raise BuildError, 'No user specified for repository access scheme: %s' % self.scheme - - svnserver = 'svn+ssh://%s@%s%s' % (self.user, self.host, self.repository) - module_checkout_cmd = ['svn', 'checkout', '-r', self.revision, '%s/%s' % (svnserver, self.module), self.module] - - else: - raise BuildError, 'Unknown SCM type: %s' % self.scmtype - - # perform checkouts - run(module_checkout_cmd, chdir=scmdir, fatal=True) - - if update_checkout_cmd: - # Currently only required for GIT checkouts - # Run the command in the directory the source was checked out into - if self.scmtype.startswith('GIT'): - run(['git', 'config', 'core.autocrlf', 'true'], chdir=update_checkout_dir, fatal=True) - run(['git', 'config', 'core.safecrlf', 'true'], chdir=update_checkout_dir, fatal=True) - run(update_checkout_cmd, chdir=update_checkout_dir, fatal=True) - - return sourcedir - -############################ -# End heinous copy and paste -############################ - -def ensuredir(path): - if not os.path.isdir(path): - os.makedirs(path) - return path class WindowsBuild(object): @@ -715,12 +487,6 @@ def find_net_info(): gateway = None return macaddr, gateway -def encode_int(n): - """If n is too large for a 32bit signed, convert it to a string""" - if n <= 2147483647: - return n - return str(n) - def upload_file(server, prefix, path): """upload a single file to the vmd""" logger = logging.getLogger('koji.vm')