source: trunk/packages/invirt-dev/python/invirt/builder.py @ 3030

Last change on this file since 3030 was 3028, checked in by gdb, 14 years ago

Make invirtibuilder work

File size: 4.9 KB
Line 
1"""Invirt build utilities.
2
3This module contains utility functions used by both the invirtibuilder
4and the remctl submission scripts that insert items into its queue.
5"""
6
7
8import os
9
10from debian_bundle import changelog
11from debian_bundle import deb822
12
13import invirt.common as c
14from invirt.config import structs as config
15
16
17_QUEUE_DIR = '/var/lib/invirt-dev/queue'
18_REPO_DIR = '/srv/git'
19_LOG_DIR = '/var/log/invirt/builds'
20_HOOKS_DIR = '/usr/share/invirt-dev/build.d'
21
22
23class InvalidBuild(ValueError):
24    pass
25
26
27def getRepo(package):
28    """Return the path to the git repo for a given package."""
29    return os.path.join(_REPO_DIR, 'invirt/packages', '%s.git' % package)
30
31def ensureValidRepo(package):
32    """Perform some basic sanity checks that the requested repo is in a
33    subdirectory of _REPO_DIR/invirt/packages.  This prevents weirdness
34    such as submitting a package like '../prod/...git'.  Also ensures that
35    the repo exists."""
36    # TODO: this might be easier just to regex
37    repo = os.path.abspath(getRepo(package))
38    parent_dir = os.path.dirname(repo)
39    prefix = os.path.join(_REPO_DIR, 'invirt/packages')
40    if not parent_dir.startswith(prefix):
41        raise InvalidBuild('Invalid package name %s' % package)
42    elif not os.path.exists(repo):
43        raise InvalidBuild('Nonexisting package %s' % package)
44
45def pocketToGit(pocket):
46    """Map a pocket in the configuration to a git branch."""
47    return getattr(getattr(config.build.pockets, pocket), 'git', pocket)
48
49
50def pocketToApt(pocket):
51    """Map a pocket in the configuration to an apt repo pocket."""
52    return getattr(getattr(config.build.pockets, pocket), 'apt', pocket)
53
54
55def getGitFile(package, ref, path):
56    """Return the contents of a path from a git ref in a package."""
57    return c.captureOutput(['git', 'cat-file', 'blob', '%s:%s' % (ref, path)],
58                           cwd=getRepo(package))
59
60
61def getChangelog(package, ref):
62    """Get a changelog object for a given ref in a given package.
63
64    This returns a debian_bundle.changelog.Changelog object for a
65    given ref of a given package.
66    """
67    return changelog.Changelog(getGitFile(package, ref, 'debian/changelog'))
68
69
70def getVersion(package, ref):
71    """Get the version of a given package at a particular ref."""
72    return getChangelog(package, ref).get_version()
73
74
75def validateBuild(pocket, package, commit):
76    """Given the parameters of a new build, validate that build.
77
78    The checks this function performs vary based on whether or not the
79    pocket is configured with allow_backtracking.
80
81    A build of a pocket without allow_backtracking set must be a
82    fast-forward of the previous revision, and the most recent version
83    in the changelog most be strictly greater than the version
84    currently in the repository.
85
86    In all cases, this revision of the package can only have the same
87    version number as any other revision currently in the apt
88    repository if they have the same commit ID.
89
90    If it's unspecified, it is assumed that pocket do not
91    allow_backtracking.
92
93    If this build request fails validation, this function will raise a
94    InvalidBuild exception, with information about why the validation
95    failed.
96
97    If this build request can be satisfied by copying the package from
98    another pocket, then this function returns that pocket. Otherwise,
99    it returns True.
100    """
101    ensureValidRepo(package)
102    package_repo = getRepo(package)
103    new_version = getVersion(package, commit)
104
105    ret = True
106
107    for p in config.build.pockets:
108        if p == pocket:
109            continue
110
111        b = pocketToGit(p)
112        current_commit = c.captureOutput(['git', 'rev-parse', b],
113                                         cwd=package_repo).strip()
114        current_version = getVersion(package, b)
115
116        if current_version == new_version:
117            if current_commit == commit:
118                ret = p
119            else:
120                raise InvalidBuild('Version %s of %s already available is in '
121                                   'pocket %s from commit %s' %
122                                   (new_version, package, p, current_commit))
123
124    if not config.build.pockets[pocket].get('allow_backtracking', False):
125        branch = pocketToGit(pocket)
126        current_version = getVersion(package, branch)
127        if new_version <= current_version:
128            raise InvalidBuild('New version %s of %s is not newer than '
129                               'version %s currently in pocket %s' %
130                               (new_version, package, current_version, pocket))
131
132        # Almost by definition, A is a fast-forward of B if B..A is
133        # empty
134        if not c.captureOutput(['git', 'rev-list', '%s..%s' % (commit, branch)]):
135            raise InvalidBuild('New commit %s of %s is not a fast-forward of'
136                               'commit currently in pocket %s' %
137                               (commit, package, pocket))
138
139    return ret
Note: See TracBrowser for help on using the repository browser.