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

Last change on this file since 2834 was 2834, checked in by broder, 14 years ago

When validating builds, return True if the build validates, and don't
let an apt copy prevent the fast-forward and increasing-version-number
checks from running.

File size: 4.2 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
31
32def pocketToGit(pocket):
33    """Map a pocket in the configuration to a git branch."""
34    return getattr(getattr(config.build.pockets, pocket), 'git', pocket)
35
36
37def pocketToApt(pocket):
38    """Map a pocket in the configuration to an apt repo pocket."""
39    return getattr(getattr(config.build.pockets, pocket), 'apt', pocket)
40
41
42def getGitFile(package, ref, path):
43    """Return the contents of a path from a git ref in a package."""
44    return c.captureOutput(['git', 'cat-file', 'blob', '%s:%s' % (ref, path)],
45                         cwd=getRepo(package))
46
47
48def getChangelog(package, ref):
49    """Get a changelog object for a given ref in a given package.
50
51    This returns a debian_bundle.changelog.Changelog object for a
52    given ref of a given package.
53    """
54    return changelog.Changelog(getGitFile(package, ref, 'debian/changelog'))
55
56
57def getVersion(package, ref):
58    """Get the version of a given package at a particular ref."""
59    return getChangelog(package, ref).get_version()
60
61
62def validateBuild(pocket, package, commit):
63    """Given the parameters of a new build, validate that build.
64
65    The checks this function performs vary based on whether or not the
66    pocket is configured with allow_backtracking.
67
68    A build of a pocket without allow_backtracking set must be a
69    fast-forward of the previous revision, and the most recent version
70    in the changelog most be strictly greater than the version
71    currently in the repository.
72
73    In all cases, this revision of the package can only have the same
74    version number as any other revision currently in the apt
75    repository if they have the same commit ID.
76
77    If it's unspecified, it is assumed that pocket do not
78    allow_backtracking.
79
80    If this build request fails validation, this function will raise a
81    InvalidBuild exception, with information about why the validation
82    failed.
83
84    If this build request can be satisfied by copying the package from
85    another pocket, then this function returns that pocket. Otherwise,
86    it returns True.
87    """
88    package_repo = getRepo(package)
89    new_version = getVersion(package, commit)
90
91    ret = True
92
93    for p in config.build.pockets:
94        if p == pocket:
95            continue
96
97        b = pocketToGit(p)
98        current_commit = c.captureOutput(['git', 'rev-parse', b],
99                                       cwd=package_repo)
100        current_version = getVersion(package, b)
101
102        if current_version == new_version:
103            if current_commit == commit:
104                ret = p
105            else:
106                raise InvalidBuild('Version %s of %s already available in '
107                                   'pocket %s from commit %s' %
108                                   (new_version, package, p, current_commit))
109
110    if config.build.pockets[pocket].get('allow_backtracking', False):
111        branch = pocketToGit(pocket)
112        current_version = getVersion(package, branch)
113        if new_version <= current_version:
114            raise InvalidBuild('New version %s of %s is not newer than '
115                               'version %s currently in pocket %s' %
116                               (new_version, package, current_version, pocket))
117
118        # Almost by definition, A is a fast-forward of B if B..A is
119        # empty
120        if not c.captureOutput(['git', 'rev-list', '%s..%s' % (commit, branch)]):
121            raise InvalidBuild('New commit %s of %s is not a fast-forward of'
122                               'commit currently in pocket %s' %
123                               (commit, package, pocket))
124
125    return ret
Note: See TracBrowser for help on using the repository browser.