replace 'heinous copy&paste' with build-time substitution
This commit is contained in:
parent
5d190c9aeb
commit
b16b3304f4
5 changed files with 33 additions and 237 deletions
|
|
@ -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"""
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
||||
|
|
|
|||
|
|
@ -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
10
vm/fix_kojikamid.sh
Executable 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
|
||||
236
vm/kojikamid.py
236
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')
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue