[PATCH] Perforce support for koji

Paul B Schroeder paul.schroeder at bluecoat.com
Mon Sep 8 22:32:28 UTC 2008


On Mon, 2008-09-08 at 17:33 -0400, Dan Williams wrote:
> The patch is linewrapped; any chance you could repost and make sure to
> use the "preformat" setting or something in your mail client?
Sure can..  Sorry about that.  Also, quickly, this version fixes the previous patch
in that the scm_tuple can handle when you specify use_common with an allowed_csm:
allowed_scms=perforcetx.bluecoat.com:1999:/koji/sandbox/paul.schroeder/skeletor
allowed_scms=perforcetx.bluecoat.com:1999:/koji/sandbox/paul.schroeder/skeletor:false
allowed_scms=perforcetx.bluecoat.com:1999:/koji/sandbox/paul.schroeder/skeletor:true

Cheers...Paul...


diff --git a/builder/kojid b/builder/kojid
index 1a7afbf..8f510f6 100755
--- a/builder/kojid
+++ b/builder/kojid
@@ -1830,14 +1830,19 @@ class BuildSRPMFromSCMTask(BaseTaskHandler):
         use_common = True
 
         for allowed_scm in options.allowed_scms.split():
-            scm_tuple = allowed_scm.split(':')
-            if len(scm_tuple) in (2, 3):
+            scm_tuple = allowed_scm.rsplit(':', 1)
+            # check if we specify a value for use_common
+            if scm_tuple[1].lower() in ('false', 'no', '0'):
+                use_common = False
+                scm_tuple = scm_tuple[0].rsplit(':', 1)
+            elif scm_tuple[1].lower() in ('true', 'yes', '1'):
+                use_common = True
+                scm_tuple = scm_tuple[0].rsplit(':', 1)
+            else:
+                use_common = True
+            if len(scm_tuple) == 2:
                 if fnmatch(scm.host, scm_tuple[0]) and fnmatch(scm.repository, scm_tuple[1]):
                     # SCM host:repository is in the allowed list
-                    # check if we specify a value for use_common
-                    if len(scm_tuple) == 3:
-                        if scm_tuple[2].lower() in ('false', 'no', '0'):
-                            use_common = False
                     break
             else:
                 self.logger.warn('Ignoring incorrectly formatted SCM host:repository: %s' % allowed_scm)
@@ -2325,7 +2330,8 @@ class SCM(object):
               'GIT': ('git://', 'git+http://', 'git+https://', 'git+rsync://'),
               'GIT+SSH': ('git+ssh://',),
               'SVN': ('svn://', 'svn+http://', 'svn+https://'),
-              'SVN+SSH': ('svn+ssh://',) }
+              'SVN+SSH': ('svn+ssh://',),
+              'P4': ('p4://',) }
 
     def is_scm_url(url):
         """
@@ -2362,10 +2368,11 @@ class SCM(object):
             raise koji.GenericError, 'Invalid SCM URL: %s' % url
 
         self.url = url
-        scheme, user, host, path, query, fragment = self._parse_url()
+        scheme, user, password, host, path, query, fragment = self._parse_url()
 
         self.scheme = scheme
         self.user = user
+        self.password = password
         self.host = host
         self.repository = path
         self.module = query
@@ -2384,9 +2391,9 @@ class SCM(object):
         Parse the SCM url into usable components.
         Return the following tuple:
 
-        (scheme, user, host, path, query, fragment)
+        (scheme, user, password, host, path, query, fragment)
 
-        user may be None, everything else will have a value
+        user and password may be None, everything else will have a value
         """
         # get the url's scheme
         scheme = self.url.split('://')[0] + '://'
@@ -2396,14 +2403,21 @@ class SCM(object):
         dummyscheme, netloc, path, params, query, fragment = urlparse.urlparse(dummyurl)
 
         user = None
+        password = None
         userhost = netloc.split('@')
         if len(userhost) == 2:
-            user = userhost[0]
+            userpass = userhost[0].split(':')
+            user = userpass[0]
+            if len(userpass) == 2:
+                password = userpass[1]
+            elif len(userpass) > 2:
+                raise koji.GenericError, 'Invalid username:password specified: %s' % netloc
             if not user:
                 # Don't return an empty string
                 user = None
-            elif ':' in user:
-                raise koji.GenericError, 'username:password format not supported: %s' % user
+            if not password:
+                # Don't return an empty string
+                password = None
             netloc = userhost[1]
         elif len(userhost) > 2:
             raise koji.GenericError, 'Invalid username at hostname specified: %s' % netloc
@@ -2419,7 +2433,7 @@ class SCM(object):
             raise koji.GenericError, 'Unable to parse SCM URL: %s' % self.url
 
         # return parsed values
-        return (scheme, user, netloc, path, query, fragment)
+        return (scheme, user, password, netloc, path, query, fragment)
 
     def checkout(self, scmdir, uploadpath, logfile, use_common=False):
         """
@@ -2514,6 +2528,39 @@ class SCM(object):
             module_checkout_cmd = ['svn', 'checkout', '-r', self.revision, '%s/%s' % (svnserver, self.module), self.module]
             common_checkout_cmd = ['svn', 'checkout', '%s/common' % svnserver]
 
+        elif self.scmtype == 'P4':
+            if not self.user:
+                raise koji.BuildError, 'No user specified for repository access scheme: %s' % self.scheme
+            # P4 URL:
+            #  p4://user:pass at p4port/p4client/p4depot?path/to/module#changelist
+
+            # Perforce uses a "client workspace"
+            # Before first slash is the p4 client, after is the p4 depot
+            (p4client, p4depot) = self.repository[1:].split('/', 1)
+
+            p4client_root = None
+            p4info = os.popen('p4 -p ' + self.host + ' -c ' + p4client + ' info')
+            for line in p4info:
+                if line.startswith('Client root:'):
+                    p4client_root = line.split()[-1]
+                    break
+            p4info.close()
+            if not p4client_root:
+                raise koji.BuildError, 'Could not find perforce client root'
+
+            # Perforce cannot checkout to a random dir (in this case scmdir).
+            # It will only checkout to the p4client_root, so we override scmdir
+            # with the p4client_root
+            scmdir = '%s/%s' % (p4client_root, p4depot)
+
+            # When HEAD is given as the revision, we assume we want the latest
+            p4revision = ''
+            if self.revision.upper() != 'HEAD':
+                p4revision = '@%s' % self.revision
+
+            module_checkout_cmd = ['p4', '-p', self.host, '-u', self.user, '-P', self.password, '-c', p4client, 'sync', '-f', '//%s/%s/...%s' % (p4depot, self.module, p4revision)]
+            common_checkout_cmd = ['p4', '-p', self.host, '-u', self.user, '-P', self.password, '-c', p4client, 'sync', '-f', '//%s/common/...' % p4depot]
+
         else:
             raise koji.BuildError, 'Unknown SCM type: %s' % self.scmtype
 
@@ -2521,6 +2568,10 @@ class SCM(object):
         if log_output(module_checkout_cmd[0], module_checkout_cmd, logfile, uploadpath, cwd=scmdir, logerror=1, env=env):
             raise koji.BuildError, 'Error running %s checkout command "%s", see %s for details' % \
                 (self.scmtype, ' '.join(module_checkout_cmd), os.path.basename(logfile))
+        # Perforce checks out to the client root listed for the perforce client.
+        # Need to move checked out source into sourcedir.
+        if not os.path.exists(sourcedir):
+            os.rename('%s/%s' % (scmdir, self.module), sourcedir)
 
         if update_checkout_cmd:
             # Currently only required for GIT checkouts





More information about the Fedora-buildsys-list mailing list