vcs Subpackage

vcs Package

anybox.recipe.openerp.vcs.get_update(vcs_type, target_dir, url, revision, **options)[source]

General entry point.

anybox.recipe.openerp.vcs.repo(vcs_type, target_dir, url, **options)[source]

base Module

class anybox.recipe.openerp.vcs.base.BaseRepo(target_dir, url, clear_retry=False, offline=False, clear_locks=False, **options)[source]

Bases: object

The common interface that all repository classes implement.

Parameters:
  • target_dir – the local directory which will serve as a working tree
  • offline – if True, the repository instance will perform no network operation, and will fail instead if a non available revision is required.
  • clear_locks – Some VCS systems can leave locks after some failures and provide a separate way to break them. If True, the repo will break any locks prior to operations (mostly useful for automated agents, such as CI robots)
  • clear_retry – if True failed updates by calling the instance are cleared (see clear_target()) and retried once. This is intended for brittle VCSes from CI robots.

Other options depend on the concrete repository class.

Repository instances are callable. For each of them:

repo(rev)

will take all the steps necessary so that its local directory is a clone of the remote source, at the specified revision. If needed and possible The revision format depends on the concrete class, but it is passed as a str.

archive(target_path)[source]
clean()[source]

Remove unwanted untracked files.

This default implementation removes Python object files and (resulting) empty directories. Subclasses are supposed to implement better vcs-specific behaviours. It is important for release-related options that this cleaning does not appear as a local modification.

clear_target()[source]

Entirely remove the target directory.

get_update(revision)[source]

Make it so that the target directory is at the prescribed revision.

The target directory need not to be initialized: this method will “clone” it from the remote source (whatever that means in the considered VCS).

This method can fail under various circumstances, for instance if the wanted revision does not exist locally and offline mode has been selected.

Raises:
  • CloneError – if initial cloning fails
  • UpdateError – if update of existing repository fails

Must be implemented in concrete subclasses

classmethod is_versioned(path)[source]

True if path exists and is versioned under this vcs.

Common implementation based on vcs_control_dir class attribute.

parents(pip_compatible=False)[source]

Return universal identifier for parent nodes, aka current revisions.

There might be more than one with some VCSes (ex: pending merge in hg).

Parameters:pip_compatible – if True, only pip compatible revision specifications are returned, depending on the VCS type.
revert(revision)[source]

Revert any local changes, including pending merges.

uncommitted_changes()[source]

True if we have uncommitted changes.

Must be implemented by concrete subclasses

exception anybox.recipe.openerp.vcs.base.CloneError(returncode, cmd, output=None)[source]

Bases: subprocess.CalledProcessError

Class to easily signal errors in initial cloning.

exception anybox.recipe.openerp.vcs.base.UpdateError(returncode, cmd, output=None)[source]

Bases: subprocess.CalledProcessError

Specific class for errors occurring during updates of existing repos.

anybox.recipe.openerp.vcs.base.clone_check_call(*args, **kwargs)
anybox.recipe.openerp.vcs.base.clone_check_output(*args, **kwargs)
anybox.recipe.openerp.vcs.base.update_check_call(*args, **kwargs)
anybox.recipe.openerp.vcs.base.update_check_output(*args, **kwargs)
anybox.recipe.openerp.vcs.base.wrap_check_call(exc_cls, call_fn)[source]

bzr Module

class anybox.recipe.openerp.vcs.bzr.BzrBranch(*a, **kw)[source]

Bases: anybox.recipe.openerp.vcs.base.BaseRepo

Represent a Bazaar branch tied to a reference branch.

archive(target_path)[source]
clean()[source]
conf_file_path()[source]
get_revid(revision)[source]
get_update(revision)[source]

Ensure that target_dir is a branch of url at specified revision.

If target_dir already exists, does a simple pull. Offline-mode: no branch nor pull, but update. In all cases, an attempt to update is performed before any pull

Special case: if the ‘merge’ option is True, merge revision into current branch.

is_fixed_revision(revstr)[source]

True iff the given revision string is for a fixed revision.

is_revno(revspec, fixed=False)[source]

True iff revspec is a fixed revision number.

Valid revision numbers are integers separated by dots.

Parameters:fixed – if True, it is further checked that integers are positive.
parents(as_revno=False, pip_compatible=False)[source]

Return current revision.

Parameters:
  • as_revno – if True, the revno will be returned. By default, a full revision id is issued (see revision_id())
  • pip_compatible – currently, setting this to True forces as_revno to True (pip URL syntax for bzr does not allow revids, because of the @ in bzr revids)

This method will not detect pending merges, but uncommitted_changes() will, and that is enough for freeze/extract features.

parse_conf(from_file=None)[source]

Return a dict of paths from standard conf (or the given file-like)

Reference: http://doc.bazaar.canonical.com/bzr.0.18/configuration.htm

>>> from pprint import pprint
>>> branch = BzrBranch('', '')
>>> pprint(branch.parse_conf(StringIO(os.linesep.join([
...        "parent_location = /some/path",
...        "submit_location = /other/path"]))))
{'parent_location': '/some/path', 'submit_location': '/other/path'}
revert(revision)[source]
revision_id(revspec)[source]

Convert revision number (revno) to globally unique revision id.

Parameters:revspec (str) – any revision specification
Returns str:revision id specification (directly usable as -r argument)
rollback_conf()[source]

Reset branch.conf to state before latest update_conf changes.

Only changes done through the same instance are taken into account.

uncommitted_changes()[source]

True if we have uncommitted changes.

update_conf()[source]

Update branch.conf.

Return bool:True if parent URL has changed (see lp:1320198)
vcs_control_dir = '.bzr'
vcs_official_name = 'Bazaar'
write_conf(conf, to_file=None)[source]

Write counterpart to read_conf()

git Module

class anybox.recipe.openerp.vcs.git.GitRepo(*args, **kwargs)[source]

Bases: anybox.recipe.openerp.vcs.base.BaseRepo

Represent a Git clone tied to a reference branch/commit/tag.

archive(target_path)[source]
clean()[source]
dangerous_revisions = ('FETCH_HEAD', 'ORIG_HEAD', 'MERGE_HEAD', 'CHERRY_PICK_HEAD', 'REVERT_HEAD')
fetch_remote_sha(sha)[source]

Fetch a precise SHA from remote if necessary.

SHA pinning is suboptimal, can’t be guaranteed to work (see the warnings emitted in code for explanations). Still, many users people depend on it, for not having enough privileges to add tags.

get_current_remote_fetch()[source]
get_update(revision)[source]

Make it so that the target directory is at the prescribed revision.

Special case: if the ‘merge’ option is True, merge revision into current branch.

git_version[source]
has_commit(sha)[source]

Return true if repo has specified commit

classmethod init_git_version(v_str)[source]

Parse git version string and store the resulting tuple on self.

Returns:the parsed version tuple

Only the first 3 digits are kept. This is good enough for the few version dependent cases we need, and coarse enough to avoid more complicated parsing.

Some real-life examples:

>>> GitRepo.init_git_version('git version 1.8.5.3')
(1, 8, 5)
>>> GitRepo.init_git_version('git version 1.7.2.5')
(1, 7, 2)

Seen on MacOSX (not on MacPorts):

>>> GitRepo.init_git_version('git version 1.8.5.2 (Apple Git-48)')
(1, 8, 5)

Seen on Windows (Tortoise Git):

>>> GitRepo.init_git_version('git version 1.8.4.msysgit.0')
(1, 8, 4)

A compiled version:

>>> GitRepo.init_git_version('git version 2.0.3.2.g996b0fd')
(2, 0, 3)

Rewrapped by hub, it has two lines:

>>> GitRepo.init_git_version('git version 1.7.9\nhub version 1.11.0')
(1, 7, 9)

This one does not exist, allowing us to prove that this method actually governs the git_version property

>>> GitRepo.init_git_version('git version 0.0.666')
(0, 0, 666)
>>> GitRepo('', '').git_version
(0, 0, 666)

Expected exceptions:

>>> try: GitRepo.init_git_version('invalid')
... except ValueError: pass

After playing with it, we must reset it so that tests can run with the proper detected one, if needed:

>>> GitRepo.init_git_version(None)
log_call(cmd, callwith=<function check_call at 0x7f11287e55f0>, log_level=20, **kw)[source]

Wrap a subprocess call with logging

Parameters:meth – the calling method to use.
merge(revision)[source]

Merge revision into current branch

offline_update(revision)[source]
parents(pip_compatible=False)[source]

Return full hash of parent nodes.

Parameters:pip_compatible – ignored, all Git revspecs are pip compatible
query_remote_ref(remote, ref)[source]

Query remote repo about given ref.

Returns:('tag', sha) if ref is a tag in remote ('branch', sha) if ref is branch (aka “head”) in remote (None, ref) if ref does not exist in remote. This happens notably if ref if a commit sha (they can’t be queried)
revert(revision)[source]
uncommitted_changes()[source]

True if we have uncommitted changes.

update_fetched_branch(branch)[source]
vcs_control_dir = '.git'
vcs_official_name = 'Git'
anybox.recipe.openerp.vcs.git.ishex(s)[source]

True iff given string is a valid hexadecimal number.

>>> ishex('deadbeef')
True
>>> ishex('01bn78')
False

hg Module

class anybox.recipe.openerp.vcs.hg.HgRepo(target_dir, url, clear_retry=False, offline=False, clear_locks=False, **options)[source]

Bases: anybox.recipe.openerp.vcs.base.BaseRepo

archive(target_path)[source]
clean()[source]
get_update(revision)[source]

Ensure that target_dir is a clone of url at specified revision.

If target_dir already exists, does a simple pull. Offline-mode: no clone nor pull, but update.

have_fixed_revision(revstr)[source]

True if revstr is a fixed revision that we already have.

Check is done for known tags (except tip) and known nodes identified by a long enough (12 char) prefix of their hexadecimal hash.

Summary of collision cases for hg up:

  • a revision number has precedence over a tag identically named
  • a tag that is a strict prefix of a full hexadecimal node hash wins over that node.
  • a full hexadecimal node hash wins over a tag that would be identically named (someone would need to be really disturbed to do that in real life).
  • a hexadecimal node that coincides with a decimal revision number is not something I can test :-)

In theory, a 12 char hexadecimal node hash could be shadowed by an incoming tag. But also, any tag could be overridden. These are considered to be fixed anyway for convenience in sensible use-cases.

People having CI robots involving tags that do get overridden by a third party upstream should complain to upstream for utterly bad practices.

parents(pip_compatible=False)[source]

Return full hash of parent nodes.

Parameters:pip_compatible – ignored, all Hg revspecs are pip compatible
uncommitted_changes()[source]

True if we have uncommitted changes.

update_hgrc_paths()[source]

Update hgrc paths section if needed.

Old paths are kept in renamed form: buildout_save_%d.

vcs_control_dir = '.hg'
vcs_official_name = 'Mercurial'

svn Module

class anybox.recipe.openerp.vcs.svn.SvnCheckout(target_dir, url, clear_retry=False, offline=False, clear_locks=False, **options)[source]

Bases: anybox.recipe.openerp.vcs.base.BaseRepo

get_update(revision)[source]

Ensure that target_dir is a branch of url at specified revision.

If target_dir already exists, does a simple pull. Offline-mode: no branch nor pull, but update.

vcs_control_dir = '.svn'
vcs_official_name = 'Subversion'

testing Module

class anybox.recipe.openerp.vcs.testing.VcsTestCase(methodName='runTest')[source]

Bases: unittest.case.TestCase

Common fixture

create_src()[source]

Create a source repository to run most tests.

To be implemented in subclasses.

setUp()[source]
tearDown()[source]

Table Of Contents

Previous topic

runtime Subpackage

This Page