Index: third_party/buildbot_7_12/buildbot/steps/source.py |
diff --git a/third_party/buildbot_7_12/buildbot/steps/source.py b/third_party/buildbot_7_12/buildbot/steps/source.py |
deleted file mode 100644 |
index 61d6df08cd631776761f1bfa2ed41cae78e18439..0000000000000000000000000000000000000000 |
--- a/third_party/buildbot_7_12/buildbot/steps/source.py |
+++ /dev/null |
@@ -1,1193 +0,0 @@ |
-# -*- test-case-name: buildbot.test.test_vc -*- |
- |
-from warnings import warn |
-from email.Utils import formatdate |
-from twisted.python import log |
-from buildbot.process.buildstep import LoggingBuildStep, LoggedRemoteCommand |
-from buildbot.interfaces import BuildSlaveTooOldError |
-from buildbot.status.builder import SKIPPED |
- |
- |
-class Source(LoggingBuildStep): |
- """This is a base class to generate a source tree in the buildslave. |
- Each version control system has a specialized subclass, and is expected |
- to override __init__ and implement computeSourceRevision() and |
- startVC(). The class as a whole builds up the self.args dictionary, then |
- starts a LoggedRemoteCommand with those arguments. |
- """ |
- |
- # if the checkout fails, there's no point in doing anything else |
- haltOnFailure = True |
- flunkOnFailure = True |
- notReally = False |
- |
- branch = None # the default branch, should be set in __init__ |
- |
- def __init__(self, workdir=None, mode='update', alwaysUseLatest=False, |
- timeout=20*60, retry=None, **kwargs): |
- """ |
- @type workdir: string |
- @param workdir: local directory (relative to the Builder's root) |
- where the tree should be placed |
- |
- @type mode: string |
- @param mode: the kind of VC operation that is desired: |
- - 'update': specifies that the checkout/update should be |
- performed directly into the workdir. Each build is performed |
- in the same directory, allowing for incremental builds. This |
- minimizes disk space, bandwidth, and CPU time. However, it |
- may encounter problems if the build process does not handle |
- dependencies properly (if you must sometimes do a 'clean |
- build' to make sure everything gets compiled), or if source |
- files are deleted but generated files can influence test |
- behavior (e.g. python's .pyc files), or when source |
- directories are deleted but generated files prevent CVS from |
- removing them. When used with a patched checkout, from a |
- previous buildbot try for instance, it will try to "revert" |
- the changes first and will do a clobber if it is unable to |
- get a clean checkout. The behavior is SCM-dependent. |
- |
- - 'copy': specifies that the source-controlled workspace |
- should be maintained in a separate directory (called the |
- 'copydir'), using checkout or update as necessary. For each |
- build, a new workdir is created with a copy of the source |
- tree (rm -rf workdir; cp -R -P -p copydir workdir). This |
- doubles the disk space required, but keeps the bandwidth low |
- (update instead of a full checkout). A full 'clean' build |
- is performed each time. This avoids any generated-file |
- build problems, but is still occasionally vulnerable to |
- problems such as a CVS repository being manually rearranged |
- (causing CVS errors on update) which are not an issue with |
- a full checkout. |
- |
- - 'clobber': specifies that the working directory should be |
- deleted each time, necessitating a full checkout for each |
- build. This insures a clean build off a complete checkout, |
- avoiding any of the problems described above, but is |
- bandwidth intensive, as the whole source tree must be |
- pulled down for each build. |
- |
- - 'export': is like 'clobber', except that e.g. the 'cvs |
- export' command is used to create the working directory. |
- This command removes all VC metadata files (the |
- CVS/.svn/{arch} directories) from the tree, which is |
- sometimes useful for creating source tarballs (to avoid |
- including the metadata in the tar file). Not all VC systems |
- support export. |
- |
- @type alwaysUseLatest: boolean |
- @param alwaysUseLatest: whether to always update to the most |
- recent available sources for this build. |
- |
- Normally the Source step asks its Build for a list of all |
- Changes that are supposed to go into the build, then computes a |
- 'source stamp' (revision number or timestamp) that will cause |
- exactly that set of changes to be present in the checked out |
- tree. This is turned into, e.g., 'cvs update -D timestamp', or |
- 'svn update -r revnum'. If alwaysUseLatest=True, bypass this |
- computation and always update to the latest available sources |
- for each build. |
- |
- The source stamp helps avoid a race condition in which someone |
- commits a change after the master has decided to start a build |
- but before the slave finishes checking out the sources. At best |
- this results in a build which contains more changes than the |
- buildmaster thinks it has (possibly resulting in the wrong |
- person taking the blame for any problems that result), at worst |
- is can result in an incoherent set of sources (splitting a |
- non-atomic commit) which may not build at all. |
- |
- @type retry: tuple of ints (delay, repeats) (or None) |
- @param retry: if provided, VC update failures are re-attempted up |
- to REPEATS times, with DELAY seconds between each |
- attempt. Some users have slaves with poor connectivity |
- to their VC repository, and they say that up to 80% of |
- their build failures are due to transient network |
- failures that could be handled by simply retrying a |
- couple times. |
- |
- """ |
- |
- LoggingBuildStep.__init__(self, **kwargs) |
- self.addFactoryArguments(workdir=workdir, |
- mode=mode, |
- alwaysUseLatest=alwaysUseLatest, |
- timeout=timeout, |
- retry=retry, |
- ) |
- |
- assert mode in ("update", "copy", "clobber", "export") |
- if retry: |
- delay, repeats = retry |
- assert isinstance(repeats, int) |
- assert repeats > 0 |
- self.args = {'mode': mode, |
- 'workdir': workdir, |
- 'timeout': timeout, |
- 'retry': retry, |
- 'patch': None, # set during .start |
- } |
- self.alwaysUseLatest = alwaysUseLatest |
- |
- # Compute defaults for descriptions: |
- description = ["updating"] |
- descriptionDone = ["update"] |
- if mode == "clobber": |
- description = ["checkout"] |
- # because checkingouting takes too much space |
- descriptionDone = ["checkout"] |
- elif mode == "export": |
- description = ["exporting"] |
- descriptionDone = ["export"] |
- self.description = description |
- self.descriptionDone = descriptionDone |
- |
- def setStepStatus(self, step_status): |
- LoggingBuildStep.setStepStatus(self, step_status) |
- |
- # start doesn't set text soon enough to capture our description in |
- # the stepStarted status notification. Set text here so it's included. |
- self.step_status.setText(self.describe(False)) |
- |
- def setDefaultWorkdir(self, workdir): |
- self.args['workdir'] = self.args['workdir'] or workdir |
- |
- def describe(self, done=False): |
- if done: |
- return self.descriptionDone |
- return self.description |
- |
- def computeSourceRevision(self, changes): |
- """Each subclass must implement this method to do something more |
- precise than -rHEAD every time. For version control systems that use |
- repository-wide change numbers (SVN, P4), this can simply take the |
- maximum such number from all the changes involved in this build. For |
- systems that do not (CVS), it needs to create a timestamp based upon |
- the latest Change, the Build's treeStableTimer, and an optional |
- self.checkoutDelay value.""" |
- return None |
- |
- def start(self): |
- if self.notReally: |
- log.msg("faking %s checkout/update" % self.name) |
- self.step_status.setText(["fake", self.name, "successful"]) |
- self.addCompleteLog("log", |
- "Faked %s checkout/update 'successful'\n" \ |
- % self.name) |
- return SKIPPED |
- |
- # what source stamp would this build like to use? |
- s = self.build.getSourceStamp() |
- # if branch is None, then use the Step's "default" branch |
- branch = s.branch or self.branch |
- # if revision is None, use the latest sources (-rHEAD) |
- revision = s.revision |
- if not revision and not self.alwaysUseLatest: |
- revision = self.computeSourceRevision(s.changes) |
- # if patch is None, then do not patch the tree after checkout |
- |
- # 'patch' is None or a tuple of (patchlevel, diff, root) |
- # root is optional. |
- patch = s.patch |
- if patch: |
- self.addCompleteLog("patch", patch[1]) |
- |
- if self.alwaysUseLatest: |
- revision = None |
- self.startVC(branch, revision, patch) |
- |
- def commandComplete(self, cmd): |
- if cmd.updates.has_key("got_revision"): |
- got_revision = cmd.updates["got_revision"][-1] |
- if got_revision is not None: |
- self.setProperty("got_revision", str(got_revision), "Source") |
- |
- |
- |
-class CVS(Source): |
- """I do CVS checkout/update operations. |
- |
- Note: if you are doing anonymous/pserver CVS operations, you will need |
- to manually do a 'cvs login' on each buildslave before the slave has any |
- hope of success. XXX: fix then, take a cvs password as an argument and |
- figure out how to do a 'cvs login' on each build |
- """ |
- |
- name = "cvs" |
- |
- #progressMetrics = ('output',) |
- # |
- # additional things to track: update gives one stderr line per directory |
- # (starting with 'cvs server: Updating ') (and is fairly stable if files |
- # is empty), export gives one line per directory (starting with 'cvs |
- # export: Updating ') and another line per file (starting with U). Would |
- # be nice to track these, requires grepping LogFile data for lines, |
- # parsing each line. Might be handy to have a hook in LogFile that gets |
- # called with each complete line. |
- |
- def __init__(self, cvsroot, cvsmodule, |
- global_options=[], branch=None, checkoutDelay=None, |
- checkout_options=[], |
- login=None, |
- **kwargs): |
- |
- """ |
- @type cvsroot: string |
- @param cvsroot: CVS Repository from which the source tree should |
- be obtained. '/home/warner/Repository' for local |
- or NFS-reachable repositories, |
- ':pserver:anon@foo.com:/cvs' for anonymous CVS, |
- 'user@host.com:/cvs' for non-anonymous CVS or |
- CVS over ssh. Lots of possibilities, check the |
- CVS documentation for more. |
- |
- @type cvsmodule: string |
- @param cvsmodule: subdirectory of CVS repository that should be |
- retrieved |
- |
- @type login: string or None |
- @param login: if not None, a string which will be provided as a |
- password to the 'cvs login' command, used when a |
- :pserver: method is used to access the repository. |
- This login is only needed once, but must be run |
- each time (just before the CVS operation) because |
- there is no way for the buildslave to tell whether |
- it was previously performed or not. |
- |
- @type branch: string |
- @param branch: the default branch name, will be used in a '-r' |
- argument to specify which branch of the source tree |
- should be used for this checkout. Defaults to None, |
- which means to use 'HEAD'. |
- |
- @type checkoutDelay: int or None |
- @param checkoutDelay: if not None, the number of seconds to put |
- between the last known Change and the |
- timestamp given to the -D argument. This |
- defaults to exactly half of the parent |
- Build's .treeStableTimer, but it could be |
- set to something else if your CVS change |
- notification has particularly weird |
- latency characteristics. |
- |
- @type global_options: list of strings |
- @param global_options: these arguments are inserted in the cvs |
- command line, before the |
- 'checkout'/'update' command word. See |
- 'cvs --help-options' for a list of what |
- may be accepted here. ['-r'] will make |
- the checked out files read only. ['-r', |
- '-R'] will also assume the repository is |
- read-only (I assume this means it won't |
- use locks to insure atomic access to the |
- ,v files). |
- |
- @type checkout_options: list of strings |
- @param checkout_options: these arguments are inserted in the cvs |
- command line, after 'checkout' but before |
- branch or revision specifiers. |
- """ |
- |
- self.checkoutDelay = checkoutDelay |
- self.branch = branch |
- |
- Source.__init__(self, **kwargs) |
- self.addFactoryArguments(cvsroot=cvsroot, |
- cvsmodule=cvsmodule, |
- global_options=global_options, |
- checkout_options=checkout_options, |
- branch=branch, |
- checkoutDelay=checkoutDelay, |
- login=login, |
- ) |
- |
- self.args.update({'cvsroot': cvsroot, |
- 'cvsmodule': cvsmodule, |
- 'global_options': global_options, |
- 'checkout_options':checkout_options, |
- 'login': login, |
- }) |
- |
- def computeSourceRevision(self, changes): |
- if not changes: |
- return None |
- lastChange = max([c.when for c in changes]) |
- if self.checkoutDelay is not None: |
- when = lastChange + self.checkoutDelay |
- else: |
- lastSubmit = max([r.submittedAt for r in self.build.requests]) |
- when = (lastChange + lastSubmit) / 2 |
- return formatdate(when) |
- |
- def startVC(self, branch, revision, patch): |
- if self.slaveVersionIsOlderThan("cvs", "1.39"): |
- # the slave doesn't know to avoid re-using the same sourcedir |
- # when the branch changes. We have no way of knowing which branch |
- # the last build used, so if we're using a non-default branch and |
- # either 'update' or 'copy' modes, it is safer to refuse to |
- # build, and tell the user they need to upgrade the buildslave. |
- if (branch != self.branch |
- and self.args['mode'] in ("update", "copy")): |
- m = ("This buildslave (%s) does not know about multiple " |
- "branches, and using mode=%s would probably build the " |
- "wrong tree. " |
- "Refusing to build. Please upgrade the buildslave to " |
- "buildbot-0.7.0 or newer." % (self.build.slavename, |
- self.args['mode'])) |
- log.msg(m) |
- raise BuildSlaveTooOldError(m) |
- |
- if branch is None: |
- branch = "HEAD" |
- self.args['branch'] = branch |
- self.args['revision'] = revision |
- self.args['patch'] = patch |
- |
- if self.args['branch'] == "HEAD" and self.args['revision']: |
- # special case. 'cvs update -r HEAD -D today' gives no files |
- # TODO: figure out why, see if it applies to -r BRANCH |
- self.args['branch'] = None |
- |
- # deal with old slaves |
- warnings = [] |
- slavever = self.slaveVersion("cvs", "old") |
- |
- if slavever == "old": |
- # 0.5.0 |
- if self.args['mode'] == "export": |
- self.args['export'] = 1 |
- elif self.args['mode'] == "clobber": |
- self.args['clobber'] = 1 |
- elif self.args['mode'] == "copy": |
- self.args['copydir'] = "source" |
- self.args['tag'] = self.args['branch'] |
- assert not self.args['patch'] # 0.5.0 slave can't do patch |
- |
- cmd = LoggedRemoteCommand("cvs", self.args) |
- self.startCommand(cmd, warnings) |
- |
- |
-class SVN(Source): |
- """I perform Subversion checkout/update operations.""" |
- |
- name = 'svn' |
- |
- def __init__(self, svnurl=None, baseURL=None, defaultBranch=None, |
- directory=None, username=None, password=None, |
- extra_args=None, keep_on_purge=None, ignore_ignores=None, |
- always_purge=None, depth=None, **kwargs): |
- """ |
- @type svnurl: string |
- @param svnurl: the URL which points to the Subversion server, |
- combining the access method (HTTP, ssh, local file), |
- the repository host/port, the repository path, the |
- sub-tree within the repository, and the branch to |
- check out. Using C{svnurl} does not enable builds of |
- alternate branches: use C{baseURL} to enable this. |
- Use exactly one of C{svnurl} and C{baseURL}. |
- |
- @param baseURL: if branches are enabled, this is the base URL to |
- which a branch name will be appended. It should |
- probably end in a slash. Use exactly one of |
- C{svnurl} and C{baseURL}. |
- |
- @param defaultBranch: if branches are enabled, this is the branch |
- to use if the Build does not specify one |
- explicitly. It will simply be appended |
- to C{baseURL} and the result handed to |
- the SVN command. |
- |
- @param username: username to pass to svn's --username |
- @param password: username to pass to svn's --password |
- """ |
- |
- if not kwargs.has_key('workdir') and directory is not None: |
- # deal with old configs |
- warn("Please use workdir=, not directory=", DeprecationWarning) |
- kwargs['workdir'] = directory |
- |
- self.svnurl = svnurl |
- self.baseURL = baseURL |
- self.branch = defaultBranch |
- self.username = username |
- self.password = password |
- self.extra_args = extra_args |
- self.keep_on_purge = keep_on_purge |
- self.ignore_ignores = ignore_ignores |
- self.always_purge = always_purge |
- self.depth = depth |
- |
- Source.__init__(self, **kwargs) |
- self.addFactoryArguments(svnurl=svnurl, |
- baseURL=baseURL, |
- defaultBranch=defaultBranch, |
- directory=directory, |
- username=username, |
- password=password, |
- extra_args=extra_args, |
- keep_on_purge=keep_on_purge, |
- ignore_ignores=ignore_ignores, |
- always_purge=always_purge, |
- depth=depth, |
- ) |
- |
- if not svnurl and not baseURL: |
- raise ValueError("you must use exactly one of svnurl and baseURL") |
- |
- |
- def computeSourceRevision(self, changes): |
- if not changes or None in [c.revision for c in changes]: |
- return None |
- lastChange = max([int(c.revision) for c in changes]) |
- return lastChange |
- |
- def startVC(self, branch, revision, patch): |
- |
- # handle old slaves |
- warnings = [] |
- slavever = self.slaveVersion("svn", "old") |
- if not slavever: |
- m = "slave does not have the 'svn' command" |
- raise BuildSlaveTooOldError(m) |
- |
- if self.slaveVersionIsOlderThan("svn", "1.39"): |
- # the slave doesn't know to avoid re-using the same sourcedir |
- # when the branch changes. We have no way of knowing which branch |
- # the last build used, so if we're using a non-default branch and |
- # either 'update' or 'copy' modes, it is safer to refuse to |
- # build, and tell the user they need to upgrade the buildslave. |
- if (branch != self.branch |
- and self.args['mode'] in ("update", "copy")): |
- m = ("This buildslave (%s) does not know about multiple " |
- "branches, and using mode=%s would probably build the " |
- "wrong tree. " |
- "Refusing to build. Please upgrade the buildslave to " |
- "buildbot-0.7.0 or newer." % (self.build.slavename, |
- self.args['mode'])) |
- raise BuildSlaveTooOldError(m) |
- |
- if slavever == "old": |
- # 0.5.0 compatibility |
- if self.args['mode'] in ("clobber", "copy"): |
- # TODO: use some shell commands to make up for the |
- # deficiency, by blowing away the old directory first (thus |
- # forcing a full checkout) |
- warnings.append("WARNING: this slave can only do SVN updates" |
- ", not mode=%s\n" % self.args['mode']) |
- log.msg("WARNING: this slave only does mode=update") |
- if self.args['mode'] == "export": |
- raise BuildSlaveTooOldError("old slave does not have " |
- "mode=export") |
- self.args['directory'] = self.args['workdir'] |
- if revision is not None: |
- # 0.5.0 can only do HEAD. We have no way of knowing whether |
- # the requested revision is HEAD or not, and for |
- # slowly-changing trees this will probably do the right |
- # thing, so let it pass with a warning |
- m = ("WARNING: old slave can only update to HEAD, not " |
- "revision=%s" % revision) |
- log.msg(m) |
- warnings.append(m + "\n") |
- revision = "HEAD" # interprets this key differently |
- if patch: |
- raise BuildSlaveTooOldError("old slave can't do patch") |
- |
- if self.svnurl: |
- assert not branch # we need baseURL= to use branches |
- self.args['svnurl'] = self.svnurl |
- else: |
- self.args['svnurl'] = self.baseURL + branch |
- self.args['revision'] = revision |
- self.args['patch'] = patch |
- |
- #Set up depth if specified |
- if self.depth is not None: |
- if self.slaveVersionIsOlderThan("svn","2.9"): |
- m = ("This buildslave (%s) does not support svn depth " |
- "arguments. " |
- "Refusing to build. " |
- "Please upgrade the buildslave." % (self.build.slavename)) |
- raise BuildSlaveTooOldError(m) |
- else: |
- self.args['depth'] = self.depth |
- |
- if self.username is not None or self.password is not None: |
- if self.slaveVersionIsOlderThan("svn", "2.8"): |
- m = ("This buildslave (%s) does not support svn usernames " |
- "and passwords. " |
- "Refusing to build. Please upgrade the buildslave to " |
- "buildbot-0.7.10 or newer." % (self.build.slavename,)) |
- raise BuildSlaveTooOldError(m) |
- if self.username is not None: self.args['username'] = self.username |
- if self.password is not None: self.args['password'] = self.password |
- |
- if self.extra_args is not None: |
- self.args['extra_args'] = self.extra_args |
- |
- revstuff = [] |
- if branch is not None and branch != self.branch: |
- revstuff.append("[branch]") |
- if revision is not None: |
- revstuff.append("r%s" % revision) |
- if patch is not None: |
- revstuff.append("[patch]") |
- self.description.extend(revstuff) |
- self.descriptionDone.extend(revstuff) |
- |
- cmd = LoggedRemoteCommand("svn", self.args) |
- self.startCommand(cmd, warnings) |
- |
- |
-class Darcs(Source): |
- """Check out a source tree from a Darcs repository at 'repourl'. |
- |
- Darcs has no concept of file modes. This means the eXecute-bit will be |
- cleared on all source files. As a result, you may need to invoke |
- configuration scripts with something like: |
- |
- C{s(step.Configure, command=['/bin/sh', './configure'])} |
- """ |
- |
- name = "darcs" |
- |
- def __init__(self, repourl=None, baseURL=None, defaultBranch=None, |
- **kwargs): |
- """ |
- @type repourl: string |
- @param repourl: the URL which points at the Darcs repository. This |
- is used as the default branch. Using C{repourl} does |
- not enable builds of alternate branches: use |
- C{baseURL} to enable this. Use either C{repourl} or |
- C{baseURL}, not both. |
- |
- @param baseURL: if branches are enabled, this is the base URL to |
- which a branch name will be appended. It should |
- probably end in a slash. Use exactly one of |
- C{repourl} and C{baseURL}. |
- |
- @param defaultBranch: if branches are enabled, this is the branch |
- to use if the Build does not specify one |
- explicitly. It will simply be appended to |
- C{baseURL} and the result handed to the |
- 'darcs pull' command. |
- """ |
- self.repourl = repourl |
- self.baseURL = baseURL |
- self.branch = defaultBranch |
- Source.__init__(self, **kwargs) |
- self.addFactoryArguments(repourl=repourl, |
- baseURL=baseURL, |
- defaultBranch=defaultBranch, |
- ) |
- assert self.args['mode'] != "export", \ |
- "Darcs does not have an 'export' mode" |
- if (not repourl and not baseURL) or (repourl and baseURL): |
- raise ValueError("you must provide exactly one of repourl and" |
- " baseURL") |
- |
- def startVC(self, branch, revision, patch): |
- slavever = self.slaveVersion("darcs") |
- if not slavever: |
- m = "slave is too old, does not know about darcs" |
- raise BuildSlaveTooOldError(m) |
- |
- if self.slaveVersionIsOlderThan("darcs", "1.39"): |
- if revision: |
- # TODO: revisit this once we implement computeSourceRevision |
- m = "0.6.6 slaves can't handle args['revision']" |
- raise BuildSlaveTooOldError(m) |
- |
- # the slave doesn't know to avoid re-using the same sourcedir |
- # when the branch changes. We have no way of knowing which branch |
- # the last build used, so if we're using a non-default branch and |
- # either 'update' or 'copy' modes, it is safer to refuse to |
- # build, and tell the user they need to upgrade the buildslave. |
- if (branch != self.branch |
- and self.args['mode'] in ("update", "copy")): |
- m = ("This buildslave (%s) does not know about multiple " |
- "branches, and using mode=%s would probably build the " |
- "wrong tree. " |
- "Refusing to build. Please upgrade the buildslave to " |
- "buildbot-0.7.0 or newer." % (self.build.slavename, |
- self.args['mode'])) |
- raise BuildSlaveTooOldError(m) |
- |
- if self.repourl: |
- assert not branch # we need baseURL= to use branches |
- self.args['repourl'] = self.repourl |
- else: |
- self.args['repourl'] = self.baseURL + branch |
- self.args['revision'] = revision |
- self.args['patch'] = patch |
- |
- revstuff = [] |
- if branch is not None and branch != self.branch: |
- revstuff.append("[branch]") |
- self.description.extend(revstuff) |
- self.descriptionDone.extend(revstuff) |
- |
- cmd = LoggedRemoteCommand("darcs", self.args) |
- self.startCommand(cmd) |
- |
- |
-class Git(Source): |
- """Check out a source tree from a git repository 'repourl'.""" |
- |
- name = "git" |
- |
- def __init__(self, repourl, |
- branch="master", |
- submodules=False, |
- ignore_ignores=None, |
- **kwargs): |
- """ |
- @type repourl: string |
- @param repourl: the URL which points at the git repository |
- |
- @type branch: string |
- @param branch: The branch or tag to check out by default. If |
- a build specifies a different branch, it will |
- be used instead of this. |
- |
- @type submodules: boolean |
- @param submodules: Whether or not to update (and initialize) |
- git submodules. |
- |
- """ |
- Source.__init__(self, **kwargs) |
- self.addFactoryArguments(repourl=repourl, |
- branch=branch, |
- submodules=submodules, |
- ignore_ignores=ignore_ignores, |
- ) |
- self.args.update({'repourl': repourl, |
- 'branch': branch, |
- 'submodules': submodules, |
- 'ignore_ignores': ignore_ignores, |
- }) |
- |
- def computeSourceRevision(self, changes): |
- if not changes: |
- return None |
- return changes[-1].revision |
- |
- def startVC(self, branch, revision, patch): |
- if branch is not None: |
- self.args['branch'] = branch |
- |
- self.args['revision'] = revision |
- self.args['patch'] = patch |
- slavever = self.slaveVersion("git") |
- if not slavever: |
- raise BuildSlaveTooOldError("slave is too old, does not know " |
- "about git") |
- cmd = LoggedRemoteCommand("git", self.args) |
- self.startCommand(cmd) |
- |
- |
-class Arch(Source): |
- """Check out a source tree from an Arch repository named 'archive' |
- available at 'url'. 'version' specifies which version number (development |
- line) will be used for the checkout: this is mostly equivalent to a |
- branch name. This version uses the 'tla' tool to do the checkout, to use |
- 'baz' see L{Bazaar} instead. |
- """ |
- |
- name = "arch" |
- # TODO: slaves >0.6.6 will accept args['build-config'], so use it |
- |
- def __init__(self, url, version, archive=None, **kwargs): |
- """ |
- @type url: string |
- @param url: the Arch coordinates of the repository. This is |
- typically an http:// URL, but could also be the absolute |
- pathname of a local directory instead. |
- |
- @type version: string |
- @param version: the category--branch--version to check out. This is |
- the default branch. If a build specifies a different |
- branch, it will be used instead of this. |
- |
- @type archive: string |
- @param archive: The archive name. If provided, it must match the one |
- that comes from the repository. If not, the |
- repository's default will be used. |
- """ |
- self.branch = version |
- Source.__init__(self, **kwargs) |
- self.addFactoryArguments(url=url, |
- version=version, |
- archive=archive, |
- ) |
- self.args.update({'url': url, |
- 'archive': archive, |
- }) |
- |
- def computeSourceRevision(self, changes): |
- # in Arch, fully-qualified revision numbers look like: |
- # arch@buildbot.sourceforge.net--2004/buildbot--dev--0--patch-104 |
- # For any given builder, all of this is fixed except the patch-104. |
- # The Change might have any part of the fully-qualified string, so we |
- # just look for the last part. We return the "patch-NN" string. |
- if not changes: |
- return None |
- lastChange = None |
- for c in changes: |
- if not c.revision: |
- continue |
- if c.revision.endswith("--base-0"): |
- rev = 0 |
- else: |
- i = c.revision.rindex("patch") |
- rev = int(c.revision[i+len("patch-"):]) |
- lastChange = max(lastChange, rev) |
- if lastChange is None: |
- return None |
- if lastChange == 0: |
- return "base-0" |
- return "patch-%d" % lastChange |
- |
- def checkSlaveVersion(self, cmd, branch): |
- warnings = [] |
- slavever = self.slaveVersion(cmd) |
- if not slavever: |
- m = "slave is too old, does not know about %s" % cmd |
- raise BuildSlaveTooOldError(m) |
- |
- # slave 1.28 and later understand 'revision' |
- if self.slaveVersionIsOlderThan(cmd, "1.28"): |
- if not self.alwaysUseLatest: |
- # we don't know whether our requested revision is the latest |
- # or not. If the tree does not change very quickly, this will |
- # probably build the right thing, so emit a warning rather |
- # than refuse to build at all |
- m = "WARNING, buildslave is too old to use a revision" |
- log.msg(m) |
- warnings.append(m + "\n") |
- |
- if self.slaveVersionIsOlderThan(cmd, "1.39"): |
- # the slave doesn't know to avoid re-using the same sourcedir |
- # when the branch changes. We have no way of knowing which branch |
- # the last build used, so if we're using a non-default branch and |
- # either 'update' or 'copy' modes, it is safer to refuse to |
- # build, and tell the user they need to upgrade the buildslave. |
- if (branch != self.branch |
- and self.args['mode'] in ("update", "copy")): |
- m = ("This buildslave (%s) does not know about multiple " |
- "branches, and using mode=%s would probably build the " |
- "wrong tree. " |
- "Refusing to build. Please upgrade the buildslave to " |
- "buildbot-0.7.0 or newer." % (self.build.slavename, |
- self.args['mode'])) |
- log.msg(m) |
- raise BuildSlaveTooOldError(m) |
- |
- return warnings |
- |
- def startVC(self, branch, revision, patch): |
- self.args['version'] = branch |
- self.args['revision'] = revision |
- self.args['patch'] = patch |
- warnings = self.checkSlaveVersion("arch", branch) |
- |
- revstuff = [] |
- if branch is not None and branch != self.branch: |
- revstuff.append("[branch]") |
- if revision is not None: |
- revstuff.append("patch%s" % revision) |
- self.description.extend(revstuff) |
- self.descriptionDone.extend(revstuff) |
- |
- cmd = LoggedRemoteCommand("arch", self.args) |
- self.startCommand(cmd, warnings) |
- |
- |
-class Bazaar(Arch): |
- """Bazaar is an alternative client for Arch repositories. baz is mostly |
- compatible with tla, but archive registration is slightly different.""" |
- |
- # TODO: slaves >0.6.6 will accept args['build-config'], so use it |
- |
- def __init__(self, url, version, archive, **kwargs): |
- """ |
- @type url: string |
- @param url: the Arch coordinates of the repository. This is |
- typically an http:// URL, but could also be the absolute |
- pathname of a local directory instead. |
- |
- @type version: string |
- @param version: the category--branch--version to check out |
- |
- @type archive: string |
- @param archive: The archive name (required). This must always match |
- the one that comes from the repository, otherwise the |
- buildslave will attempt to get sources from the wrong |
- archive. |
- """ |
- self.branch = version |
- Source.__init__(self, **kwargs) |
- self.addFactoryArguments(url=url, |
- version=version, |
- archive=archive, |
- ) |
- self.args.update({'url': url, |
- 'archive': archive, |
- }) |
- |
- def startVC(self, branch, revision, patch): |
- self.args['version'] = branch |
- self.args['revision'] = revision |
- self.args['patch'] = patch |
- warnings = self.checkSlaveVersion("bazaar", branch) |
- |
- revstuff = [] |
- if branch is not None and branch != self.branch: |
- revstuff.append("[branch]") |
- if revision is not None: |
- revstuff.append("patch%s" % revision) |
- self.description.extend(revstuff) |
- self.descriptionDone.extend(revstuff) |
- |
- cmd = LoggedRemoteCommand("bazaar", self.args) |
- self.startCommand(cmd, warnings) |
- |
-class Bzr(Source): |
- """Check out a source tree from a bzr (Bazaar) repository at 'repourl'. |
- |
- """ |
- |
- name = "bzr" |
- |
- def __init__(self, repourl=None, baseURL=None, defaultBranch=None, |
- forceSharedRepo=None, |
- **kwargs): |
- """ |
- @type repourl: string |
- @param repourl: the URL which points at the bzr repository. This |
- is used as the default branch. Using C{repourl} does |
- not enable builds of alternate branches: use |
- C{baseURL} to enable this. Use either C{repourl} or |
- C{baseURL}, not both. |
- |
- @param baseURL: if branches are enabled, this is the base URL to |
- which a branch name will be appended. It should |
- probably end in a slash. Use exactly one of |
- C{repourl} and C{baseURL}. |
- |
- @param defaultBranch: if branches are enabled, this is the branch |
- to use if the Build does not specify one |
- explicitly. It will simply be appended to |
- C{baseURL} and the result handed to the |
- 'bzr checkout pull' command. |
- |
- |
- @param forceSharedRepo: Boolean, defaults to False. If set to True, |
- the working directory will be made into a |
- bzr shared repository if it is not already. |
- Shared repository greatly reduces the amount |
- of history data that needs to be downloaded |
- if not using update/copy mode, or if using |
- update/copy mode with multiple branches. |
- """ |
- self.repourl = repourl |
- self.baseURL = baseURL |
- self.branch = defaultBranch |
- Source.__init__(self, **kwargs) |
- self.addFactoryArguments(repourl=repourl, |
- baseURL=baseURL, |
- defaultBranch=defaultBranch, |
- forceSharedRepo=forceSharedRepo |
- ) |
- self.args.update({'forceSharedRepo': forceSharedRepo}) |
- if (not repourl and not baseURL) or (repourl and baseURL): |
- raise ValueError("you must provide exactly one of repourl and" |
- " baseURL") |
- |
- def computeSourceRevision(self, changes): |
- if not changes: |
- return None |
- lastChange = max([int(c.revision) for c in changes]) |
- return lastChange |
- |
- def startVC(self, branch, revision, patch): |
- slavever = self.slaveVersion("bzr") |
- if not slavever: |
- m = "slave is too old, does not know about bzr" |
- raise BuildSlaveTooOldError(m) |
- |
- if self.repourl: |
- assert not branch # we need baseURL= to use branches |
- self.args['repourl'] = self.repourl |
- else: |
- self.args['repourl'] = self.baseURL + branch |
- self.args['revision'] = revision |
- self.args['patch'] = patch |
- |
- revstuff = [] |
- if branch is not None and branch != self.branch: |
- revstuff.append("[" + branch + "]") |
- if revision is not None: |
- revstuff.append("r%s" % revision) |
- self.description.extend(revstuff) |
- self.descriptionDone.extend(revstuff) |
- |
- cmd = LoggedRemoteCommand("bzr", self.args) |
- self.startCommand(cmd) |
- |
- |
-class Mercurial(Source): |
- """Check out a source tree from a mercurial repository 'repourl'.""" |
- |
- name = "hg" |
- |
- def __init__(self, repourl=None, baseURL=None, defaultBranch=None, |
- branchType='dirname', clobberOnBranchChange=True, **kwargs): |
- """ |
- @type repourl: string |
- @param repourl: the URL which points at the Mercurial repository. |
- This uses the 'default' branch unless defaultBranch is |
- specified below and the C{branchType} is set to |
- 'inrepo'. It is an error to specify a branch without |
- setting the C{branchType} to 'inrepo'. |
- |
- @param baseURL: if 'dirname' branches are enabled, this is the base URL |
- to which a branch name will be appended. It should |
- probably end in a slash. Use exactly one of C{repourl} |
- and C{baseURL}. |
- |
- @param defaultBranch: if branches are enabled, this is the branch |
- to use if the Build does not specify one |
- explicitly. |
- For 'dirname' branches, It will simply be |
- appended to C{baseURL} and the result handed to |
- the 'hg update' command. |
- For 'inrepo' branches, this specifies the named |
- revision to which the tree will update after a |
- clone. |
- |
- @param branchType: either 'dirname' or 'inrepo' depending on whether |
- the branch name should be appended to the C{baseURL} |
- or the branch is a mercurial named branch and can be |
- found within the C{repourl} |
- |
- @param clobberOnBranchChange: boolean, defaults to True. If set and |
- using inrepos branches, clobber the tree |
- at each branch change. Otherwise, just |
- update to the branch. |
- """ |
- self.repourl = repourl |
- self.baseURL = baseURL |
- self.branch = defaultBranch |
- self.branchType = branchType |
- self.clobberOnBranchChange = clobberOnBranchChange |
- Source.__init__(self, **kwargs) |
- self.addFactoryArguments(repourl=repourl, |
- baseURL=baseURL, |
- defaultBranch=defaultBranch, |
- branchType=branchType, |
- clobberOnBranchChange=clobberOnBranchChange, |
- ) |
- if (not repourl and not baseURL) or (repourl and baseURL): |
- raise ValueError("you must provide exactly one of repourl and" |
- " baseURL") |
- |
- def startVC(self, branch, revision, patch): |
- slavever = self.slaveVersion("hg") |
- if not slavever: |
- raise BuildSlaveTooOldError("slave is too old, does not know " |
- "about hg") |
- |
- if self.repourl: |
- # we need baseURL= to use dirname branches |
- assert self.branchType == 'inrepo' or not branch |
- self.args['repourl'] = self.repourl |
- if branch: |
- self.args['branch'] = branch |
- else: |
- self.args['repourl'] = self.baseURL + (branch or '') |
- self.args['revision'] = revision |
- self.args['patch'] = patch |
- self.args['clobberOnBranchChange'] = self.clobberOnBranchChange |
- self.args['branchType'] = self.branchType |
- |
- revstuff = [] |
- if branch is not None and branch != self.branch: |
- revstuff.append("[branch]") |
- self.description.extend(revstuff) |
- self.descriptionDone.extend(revstuff) |
- |
- cmd = LoggedRemoteCommand("hg", self.args) |
- self.startCommand(cmd) |
- |
- def computeSourceRevision(self, changes): |
- if not changes: |
- return None |
- # without knowing the revision ancestry graph, we can't sort the |
- # changes at all. So for now, assume they were given to us in sorted |
- # order, and just pay attention to the last one. See ticket #103 for |
- # more details. |
- if len(changes) > 1: |
- log.msg("Mercurial.computeSourceRevision: warning: " |
- "there are %d changes here, assuming the last one is " |
- "the most recent" % len(changes)) |
- return changes[-1].revision |
- |
- |
-class P4(Source): |
- """ P4 is a class for accessing perforce revision control""" |
- name = "p4" |
- |
- def __init__(self, p4base, defaultBranch=None, p4port=None, p4user=None, |
- p4passwd=None, p4extra_views=[], |
- p4client='buildbot_%(slave)s_%(builder)s', **kwargs): |
- """ |
- @type p4base: string |
- @param p4base: A view into a perforce depot, typically |
- "//depot/proj/" |
- |
- @type defaultBranch: string |
- @param defaultBranch: Identify a branch to build by default. Perforce |
- is a view based branching system. So, the branch |
- is normally the name after the base. For example, |
- branch=1.0 is view=//depot/proj/1.0/... |
- branch=1.1 is view=//depot/proj/1.1/... |
- |
- @type p4port: string |
- @param p4port: Specify the perforce server to connection in the format |
- <host>:<port>. Example "perforce.example.com:1666" |
- |
- @type p4user: string |
- @param p4user: The perforce user to run the command as. |
- |
- @type p4passwd: string |
- @param p4passwd: The password for the perforce user. |
- |
- @type p4extra_views: list of tuples |
- @param p4extra_views: Extra views to be added to |
- the client that is being used. |
- |
- @type p4client: string |
- @param p4client: The perforce client to use for this buildslave. |
- """ |
- |
- self.branch = defaultBranch |
- Source.__init__(self, **kwargs) |
- self.addFactoryArguments(p4base=p4base, |
- defaultBranch=defaultBranch, |
- p4port=p4port, |
- p4user=p4user, |
- p4passwd=p4passwd, |
- p4extra_views=p4extra_views, |
- p4client=p4client, |
- ) |
- self.args['p4port'] = p4port |
- self.args['p4user'] = p4user |
- self.args['p4passwd'] = p4passwd |
- self.args['p4base'] = p4base |
- self.args['p4extra_views'] = p4extra_views |
- self.p4client = p4client |
- |
- def setBuild(self, build): |
- Source.setBuild(self, build) |
- self.args['p4client'] = self.p4client % { |
- 'slave': build.slavename, |
- 'builder': build.builder.name, |
- } |
- |
- def computeSourceRevision(self, changes): |
- if not changes: |
- return None |
- lastChange = max([int(c.revision) for c in changes]) |
- return lastChange |
- |
- def startVC(self, branch, revision, patch): |
- slavever = self.slaveVersion("p4") |
- assert slavever, "slave is too old, does not know about p4" |
- args = dict(self.args) |
- args['branch'] = branch or self.branch |
- args['revision'] = revision |
- args['patch'] = patch |
- cmd = LoggedRemoteCommand("p4", args) |
- self.startCommand(cmd) |
- |
-class P4Sync(Source): |
- """This is a partial solution for using a P4 source repository. You are |
- required to manually set up each build slave with a useful P4 |
- environment, which means setting various per-slave environment variables, |
- and creating a P4 client specification which maps the right files into |
- the slave's working directory. Once you have done that, this step merely |
- performs a 'p4 sync' to update that workspace with the newest files. |
- |
- Each slave needs the following environment: |
- |
- - PATH: the 'p4' binary must be on the slave's PATH |
- - P4USER: each slave needs a distinct user account |
- - P4CLIENT: each slave needs a distinct client specification |
- |
- You should use 'p4 client' (?) to set up a client view spec which maps |
- the desired files into $SLAVEBASE/$BUILDERBASE/source . |
- """ |
- |
- name = "p4sync" |
- |
- def __init__(self, p4port, p4user, p4passwd, p4client, **kwargs): |
- assert kwargs['mode'] == "copy", "P4Sync can only be used in mode=copy" |
- self.branch = None |
- Source.__init__(self, **kwargs) |
- self.addFactoryArguments(p4port=p4port, |
- p4user=p4user, |
- p4passwd=p4passwd, |
- p4client=p4client, |
- ) |
- self.args['p4port'] = p4port |
- self.args['p4user'] = p4user |
- self.args['p4passwd'] = p4passwd |
- self.args['p4client'] = p4client |
- |
- def computeSourceRevision(self, changes): |
- if not changes: |
- return None |
- lastChange = max([int(c.revision) for c in changes]) |
- return lastChange |
- |
- def startVC(self, branch, revision, patch): |
- slavever = self.slaveVersion("p4sync") |
- assert slavever, "slave is too old, does not know about p4" |
- cmd = LoggedRemoteCommand("p4sync", self.args) |
- self.startCommand(cmd) |
- |
-class Monotone(Source): |
- """Check out a revision from a monotone server at 'server_addr', |
- branch 'branch'. 'revision' specifies which revision id to check |
- out. |
- |
- This step will first create a local database, if necessary, and then pull |
- the contents of the server into the database. Then it will do the |
- checkout/update from this database.""" |
- |
- name = "monotone" |
- |
- def __init__(self, server_addr, branch, db_path="monotone.db", |
- monotone="monotone", |
- **kwargs): |
- Source.__init__(self, **kwargs) |
- self.addFactoryArguments(server_addr=server_addr, |
- branch=branch, |
- db_path=db_path, |
- monotone=monotone, |
- ) |
- self.args.update({"server_addr": server_addr, |
- "branch": branch, |
- "db_path": db_path, |
- "monotone": monotone}) |
- |
- def computeSourceRevision(self, changes): |
- if not changes: |
- return None |
- return changes[-1].revision |
- |
- def startVC(self): |
- slavever = self.slaveVersion("monotone") |
- assert slavever, "slave is too old, does not know about monotone" |
- cmd = LoggedRemoteCommand("monotone", self.args) |
- self.startCommand(cmd) |