replace 'heinous copy&paste' with build-time substitution

This commit is contained in:
Mike McLean 2010-10-13 16:41:33 -04:00
parent 5d190c9aeb
commit b16b3304f4
5 changed files with 33 additions and 237 deletions

View file

@ -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"""

View file

@ -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):

View file

@ -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"; \

10
vm/fix_kojikamid.sh Executable file
View file

@ -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

View file

@ -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')