Statistics
| Branch: | Tag: | Revision:

root / devflow / versioning.py @ 9b0839dd

History | View | Annotate | Download (14.5 kB)

1 55775645 Vangelis Koukis
#!/usr/bin/env python
2 55775645 Vangelis Koukis
#
3 8df4ab84 Vangelis Koukis
# Copyright (C) 2012, 2013 GRNET S.A. All rights reserved.
4 55775645 Vangelis Koukis
#
5 55775645 Vangelis Koukis
# Redistribution and use in source and binary forms, with or
6 55775645 Vangelis Koukis
# without modification, are permitted provided that the following
7 55775645 Vangelis Koukis
# conditions are met:
8 55775645 Vangelis Koukis
#
9 55775645 Vangelis Koukis
#   1. Redistributions of source code must retain the above
10 55775645 Vangelis Koukis
#      copyright notice, this list of conditions and the following
11 55775645 Vangelis Koukis
#      disclaimer.
12 55775645 Vangelis Koukis
#
13 55775645 Vangelis Koukis
#   2. Redistributions in binary form must reproduce the above
14 55775645 Vangelis Koukis
#      copyright notice, this list of conditions and the following
15 55775645 Vangelis Koukis
#      disclaimer in the documentation and/or other materials
16 55775645 Vangelis Koukis
#      provided with the distribution.
17 55775645 Vangelis Koukis
#
18 55775645 Vangelis Koukis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
19 55775645 Vangelis Koukis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 55775645 Vangelis Koukis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 55775645 Vangelis Koukis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
22 55775645 Vangelis Koukis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 55775645 Vangelis Koukis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 55775645 Vangelis Koukis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
25 55775645 Vangelis Koukis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 55775645 Vangelis Koukis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 55775645 Vangelis Koukis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28 55775645 Vangelis Koukis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 55775645 Vangelis Koukis
# POSSIBILITY OF SUCH DAMAGE.
30 55775645 Vangelis Koukis
#
31 55775645 Vangelis Koukis
# The views and conclusions contained in the software and
32 55775645 Vangelis Koukis
# documentation are those of the authors and should not be
33 55775645 Vangelis Koukis
# interpreted as representing official policies, either expressed
34 55775645 Vangelis Koukis
# or implied, of GRNET S.A.
35 55775645 Vangelis Koukis
36 4a45f70c Christos Stavrakakis
"""Helper functions for automatic version computation.
37 4a45f70c Christos Stavrakakis

38 4a45f70c Christos Stavrakakis
This module contains helper functions for extracting information
39 4a45f70c Christos Stavrakakis
from a Git repository, and computing the python and debian version
40 4a45f70c Christos Stavrakakis
of the repository code.
41 4a45f70c Christos Stavrakakis

42 4a45f70c Christos Stavrakakis
"""
43 55775645 Vangelis Koukis
44 55775645 Vangelis Koukis
import os
45 55775645 Vangelis Koukis
import re
46 55775645 Vangelis Koukis
import sys
47 55775645 Vangelis Koukis
48 871bd65d Chris Stavrakakis
from distutils import log  # pylint: disable=E0611
49 55775645 Vangelis Koukis
50 1b3aeefd Christos Stavrakakis
from devflow import BRANCH_TYPES, BASE_VERSION_FILE, VERSION_RE
51 9fe1ecd8 Christos Stavrakakis
from devflow import utils
52 55775645 Vangelis Koukis
53 55775645 Vangelis Koukis
54 595d480a Christos Stavrakakis
DEFAULT_VERSION_FILE = """
55 595d480a Christos Stavrakakis
__version__ = "%(DEVFLOW_VERSION)s"
56 3a137edf Christos Stavrakakis
__version_vcs_info__ = {
57 3a137edf Christos Stavrakakis
    'branch': '%(DEVFLOW_BRANCH)s',
58 3a137edf Christos Stavrakakis
    'revid': '%(DEVFLOW_REVISION_ID)s',
59 3a137edf Christos Stavrakakis
    'revno': %(DEVFLOW_REVISION_NUMBER)s}
60 3a137edf Christos Stavrakakis
__version_user_email__ = "%(DEVFLOW_USER_EMAIL)s"
61 3a137edf Christos Stavrakakis
__version_user_name__ = "%(DEVFLOW_USER_NAME)s"
62 3a137edf Christos Stavrakakis
"""
63 3a137edf Christos Stavrakakis
64 3a137edf Christos Stavrakakis
65 4a45f70c Christos Stavrakakis
def get_base_version(vcs_info):
66 55775645 Vangelis Koukis
    """Determine the base version from a file in the repository"""
67 55775645 Vangelis Koukis
68 55775645 Vangelis Koukis
    f = open(os.path.join(vcs_info.toplevel, BASE_VERSION_FILE))
69 55775645 Vangelis Koukis
    lines = [l.strip() for l in f.readlines()]
70 4a45f70c Christos Stavrakakis
    lines = [l for l in lines if not l.startswith("#")]
71 4a45f70c Christos Stavrakakis
    if len(lines) != 1:
72 55775645 Vangelis Koukis
        raise ValueError("File '%s' should contain a single non-comment line.")
73 fe584cc4 Christos Stavrakakis
    f.close()
74 4a45f70c Christos Stavrakakis
    return lines[0]
75 55775645 Vangelis Koukis
76 9b0839dd Filippos Giannakos
def validate_version(base_version, vcs_info):
77 9b0839dd Filippos Giannakos
    branch = vcs_info.branch
78 9b0839dd Filippos Giannakos
79 9b0839dd Filippos Giannakos
    brnorm = utils.normalize_branch_name(branch)
80 9b0839dd Filippos Giannakos
    btypestr = utils.get_branch_type(branch)
81 9b0839dd Filippos Giannakos
82 9b0839dd Filippos Giannakos
    try:
83 9b0839dd Filippos Giannakos
        btype = BRANCH_TYPES[btypestr]
84 9b0839dd Filippos Giannakos
    except KeyError:
85 9b0839dd Filippos Giannakos
        allowed_branches = ", ".join(x for x in BRANCH_TYPES.keys())
86 9b0839dd Filippos Giannakos
        raise ValueError("Malformed branch name '%s', cannot classify as one "
87 9b0839dd Filippos Giannakos
                         "of %s" % (btypestr, allowed_branches))
88 9b0839dd Filippos Giannakos
89 9b0839dd Filippos Giannakos
    if btype.versioned:
90 9b0839dd Filippos Giannakos
        try:
91 9b0839dd Filippos Giannakos
            bverstr = brnorm.split("-")[1]
92 9b0839dd Filippos Giannakos
        except IndexError:
93 9b0839dd Filippos Giannakos
            # No version
94 9b0839dd Filippos Giannakos
            raise ValueError("Branch name '%s' should contain version" %
95 9b0839dd Filippos Giannakos
                             branch)
96 9b0839dd Filippos Giannakos
97 9b0839dd Filippos Giannakos
        # Check that version is well-formed
98 9b0839dd Filippos Giannakos
        if not re.match(VERSION_RE, bverstr):
99 9b0839dd Filippos Giannakos
            raise ValueError("Malformed version '%s' in branch name '%s'" %
100 9b0839dd Filippos Giannakos
                             (bverstr, branch))
101 9b0839dd Filippos Giannakos
102 9b0839dd Filippos Giannakos
    m = re.match(btype.allowed_version_re, base_version)
103 9b0839dd Filippos Giannakos
    if not m or (btype.versioned and m.groupdict()["bverstr"] != bverstr):
104 9b0839dd Filippos Giannakos
        raise ValueError("Base version '%s' unsuitable for branch name '%s'" %
105 9b0839dd Filippos Giannakos
                         (base_version, branch))
106 55775645 Vangelis Koukis
107 55775645 Vangelis Koukis
def python_version(base_version, vcs_info, mode):
108 55775645 Vangelis Koukis
    """Generate a Python distribution version following devtools conventions.
109 55775645 Vangelis Koukis

110 55775645 Vangelis Koukis
    This helper generates a Python distribution version from a repository
111 55775645 Vangelis Koukis
    commit, following devtools conventions. The input data are:
112 55775645 Vangelis Koukis
        * base_version: a base version number, presumably stored in text file
113 55775645 Vangelis Koukis
          inside the repository, e.g., /version
114 55775645 Vangelis Koukis
        * vcs_info: vcs information: current branch name and revision no
115 55775645 Vangelis Koukis
        * mode: "snapshot", or "release"
116 55775645 Vangelis Koukis

117 55775645 Vangelis Koukis
    This helper assumes a git branching model following:
118 55775645 Vangelis Koukis
    http://nvie.com/posts/a-successful-git-branching-model/
119 55775645 Vangelis Koukis

120 55775645 Vangelis Koukis
    with 'master', 'develop', 'release-X', 'hotfix-X' and 'feature-X' branches.
121 55775645 Vangelis Koukis

122 55775645 Vangelis Koukis
    General rules:
123 55775645 Vangelis Koukis
    a) any repository commit can get as a Python version
124 55775645 Vangelis Koukis
    b) a version is generated either in 'release' or in 'snapshot' mode
125 55775645 Vangelis Koukis
    c) the choice of mode depends on the branch, see following table.
126 55775645 Vangelis Koukis

127 55775645 Vangelis Koukis
    A python version is of the form A_NNN,
128 55775645 Vangelis Koukis
    where A: X.Y.Z{,next,rcW} and NNN: a revision number for the commit,
129 55775645 Vangelis Koukis
    as returned by vcs_info().
130 55775645 Vangelis Koukis

131 55775645 Vangelis Koukis
    For every combination of branch and mode, releases are numbered as follows:
132 55775645 Vangelis Koukis

133 55775645 Vangelis Koukis
    BRANCH:  /  MODE: snapshot        release
134 55775645 Vangelis Koukis
    --------          ------------------------------
135 55775645 Vangelis Koukis
    feature           0.14next_150    N/A
136 55775645 Vangelis Koukis
    develop           0.14next_151    N/A
137 55775645 Vangelis Koukis
    release           0.14rc2_249     0.14rc2
138 55775645 Vangelis Koukis
    master            N/A             0.14
139 55775645 Vangelis Koukis
    hotfix            0.14.1rc6_121   0.14.1rc6
140 55775645 Vangelis Koukis
                      N/A             0.14.1
141 55775645 Vangelis Koukis

142 55775645 Vangelis Koukis
    The suffix 'next' in a version name is used to denote the upcoming version,
143 55775645 Vangelis Koukis
    the one being under development in the develop and release branches.
144 55775645 Vangelis Koukis
    Version '0.14next' is the version following 0.14, and only lives on the
145 55775645 Vangelis Koukis
    develop and feature branches.
146 55775645 Vangelis Koukis

147 55775645 Vangelis Koukis
    The suffix 'rc' is used to denote release candidates. 'rc' versions live
148 55775645 Vangelis Koukis
    only in release and hotfix branches.
149 55775645 Vangelis Koukis

150 55775645 Vangelis Koukis
    Suffixes 'next' and 'rc' have been chosen to ensure proper ordering
151 55775645 Vangelis Koukis
    according to setuptools rules:
152 55775645 Vangelis Koukis

153 55775645 Vangelis Koukis
        http://www.python.org/dev/peps/pep-0386/#setuptools
154 55775645 Vangelis Koukis

155 55775645 Vangelis Koukis
    Every branch uses a value for A so that all releases are ordered based
156 55775645 Vangelis Koukis
    on the branch they came from, so:
157 55775645 Vangelis Koukis

158 55775645 Vangelis Koukis
    So
159 55775645 Vangelis Koukis
        0.13next < 0.14rcW < 0.14 < 0.14next < 0.14.1
160 55775645 Vangelis Koukis

161 55775645 Vangelis Koukis
    and
162 55775645 Vangelis Koukis

163 55775645 Vangelis Koukis
    >>> V("0.14next") > V("0.14")
164 55775645 Vangelis Koukis
    True
165 55775645 Vangelis Koukis
    >>> V("0.14next") > V("0.14rc7")
166 55775645 Vangelis Koukis
    True
167 55775645 Vangelis Koukis
    >>> V("0.14next") > V("0.14.1")
168 55775645 Vangelis Koukis
    False
169 55775645 Vangelis Koukis
    >>> V("0.14rc6") > V("0.14")
170 55775645 Vangelis Koukis
    False
171 55775645 Vangelis Koukis
    >>> V("0.14.2rc6") > V("0.14.1")
172 55775645 Vangelis Koukis
    True
173 55775645 Vangelis Koukis

174 55775645 Vangelis Koukis
    The value for _NNN is chosen based of the revision number of the specific
175 55775645 Vangelis Koukis
    commit. It is used to ensure ascending ordering of consecutive releases
176 55775645 Vangelis Koukis
    from the same branch. Every version of the form A_NNN comes *before*
177 55775645 Vangelis Koukis
    than A: All snapshots are ordered so they come before the corresponding
178 55775645 Vangelis Koukis
    release.
179 55775645 Vangelis Koukis

180 55775645 Vangelis Koukis
    So
181 55775645 Vangelis Koukis
        0.14next_* < 0.14
182 55775645 Vangelis Koukis
        0.14.1_* < 0.14.1
183 55775645 Vangelis Koukis
        etc
184 55775645 Vangelis Koukis

185 55775645 Vangelis Koukis
    and
186 55775645 Vangelis Koukis

187 55775645 Vangelis Koukis
    >>> V("0.14next_150") < V("0.14next")
188 55775645 Vangelis Koukis
    True
189 55775645 Vangelis Koukis
    >>> V("0.14.1next_150") < V("0.14.1next")
190 55775645 Vangelis Koukis
    True
191 55775645 Vangelis Koukis
    >>> V("0.14.1_149") < V("0.14.1")
192 55775645 Vangelis Koukis
    True
193 55775645 Vangelis Koukis
    >>> V("0.14.1_149") < V("0.14.1_150")
194 55775645 Vangelis Koukis
    True
195 55775645 Vangelis Koukis

196 55775645 Vangelis Koukis
    Combining both of the above, we get
197 55775645 Vangelis Koukis
       0.13next_* < 0.13next < 0.14rcW_* < 0.14rcW < 0.14_* < 0.14
198 55775645 Vangelis Koukis
       < 0.14next_* < 0.14next < 0.14.1_* < 0.14.1
199 55775645 Vangelis Koukis

200 55775645 Vangelis Koukis
    and
201 55775645 Vangelis Koukis

202 55775645 Vangelis Koukis
    >>> V("0.13next_102") < V("0.13next")
203 55775645 Vangelis Koukis
    True
204 55775645 Vangelis Koukis
    >>> V("0.13next") < V("0.14rc5_120")
205 55775645 Vangelis Koukis
    True
206 55775645 Vangelis Koukis
    >>> V("0.14rc3_120") < V("0.14rc3")
207 55775645 Vangelis Koukis
    True
208 55775645 Vangelis Koukis
    >>> V("0.14rc3") < V("0.14_1")
209 55775645 Vangelis Koukis
    True
210 55775645 Vangelis Koukis
    >>> V("0.14_120") < V("0.14")
211 55775645 Vangelis Koukis
    True
212 55775645 Vangelis Koukis
    >>> V("0.14") < V("0.14next_20")
213 55775645 Vangelis Koukis
    True
214 55775645 Vangelis Koukis
    >>> V("0.14next_20") < V("0.14next")
215 55775645 Vangelis Koukis
    True
216 55775645 Vangelis Koukis

217 55775645 Vangelis Koukis
    Note: one of the tests above fails because of constraints in the way
218 55775645 Vangelis Koukis
    setuptools parses version numbers. It does not affect us because the
219 55775645 Vangelis Koukis
    specific version format that triggers the problem is not contained in the
220 55775645 Vangelis Koukis
    table showing allowed branch / mode combinations, above.
221 55775645 Vangelis Koukis

222 55775645 Vangelis Koukis

223 55775645 Vangelis Koukis
    """
224 9b0839dd Filippos Giannakos
    validate_version(base_version, vcs_info)
225 55775645 Vangelis Koukis
    branch = vcs_info.branch
226 4f36685f Christos Stavrakakis
    btypestr = utils.get_branch_type(branch)
227 9b0839dd Filippos Giannakos
    #this cannot fail
228 9b0839dd Filippos Giannakos
    btype = BRANCH_TYPES[btypestr]
229 55775645 Vangelis Koukis
230 55775645 Vangelis Koukis
    if mode not in ["snapshot", "release"]:
231 55775645 Vangelis Koukis
        raise ValueError("Specified mode '%s' should be one of 'snapshot' or "
232 55775645 Vangelis Koukis
                         "'release'" % mode)
233 55775645 Vangelis Koukis
    snap = (mode == "snapshot")
234 55775645 Vangelis Koukis
235 595d480a Christos Stavrakakis
    if (snap and not btype.builds_snapshot) or\
236 595d480a Christos Stavrakakis
       (not snap and not btype.builds_release):  # nopep8
237 445f53a7 Christos Stavrakakis
        raise ValueError("Invalid mode '%s' in branch type '%s'" %
238 445f53a7 Christos Stavrakakis
                         (mode, btypestr))
239 55775645 Vangelis Koukis
240 55775645 Vangelis Koukis
    if snap:
241 55775645 Vangelis Koukis
        v = "%s_%d_%s" % (base_version, vcs_info.revno, vcs_info.revid)
242 55775645 Vangelis Koukis
    else:
243 55775645 Vangelis Koukis
        v = base_version
244 55775645 Vangelis Koukis
    return v
245 55775645 Vangelis Koukis
246 55775645 Vangelis Koukis
247 55775645 Vangelis Koukis
def debian_version_from_python_version(pyver):
248 55775645 Vangelis Koukis
    """Generate a debian package version from a Python version.
249 55775645 Vangelis Koukis

250 55775645 Vangelis Koukis
    This helper generates a Debian package version from a Python version,
251 55775645 Vangelis Koukis
    following devtools conventions.
252 55775645 Vangelis Koukis

253 55775645 Vangelis Koukis
    Debian sorts version strings differently compared to setuptools:
254 55775645 Vangelis Koukis
    http://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Version
255 55775645 Vangelis Koukis

256 55775645 Vangelis Koukis
    Initial tests:
257 55775645 Vangelis Koukis

258 55775645 Vangelis Koukis
    >>> debian_version("3") < debian_version("6")
259 55775645 Vangelis Koukis
    True
260 55775645 Vangelis Koukis
    >>> debian_version("3") < debian_version("2")
261 55775645 Vangelis Koukis
    False
262 55775645 Vangelis Koukis
    >>> debian_version("1") == debian_version("1")
263 55775645 Vangelis Koukis
    True
264 55775645 Vangelis Koukis
    >>> debian_version("1") != debian_version("1")
265 55775645 Vangelis Koukis
    False
266 55775645 Vangelis Koukis
    >>> debian_version("1") >= debian_version("1")
267 55775645 Vangelis Koukis
    True
268 55775645 Vangelis Koukis
    >>> debian_version("1") <= debian_version("1")
269 55775645 Vangelis Koukis
    True
270 55775645 Vangelis Koukis

271 55775645 Vangelis Koukis
    This helper defines a 1-1 mapping between Python and Debian versions,
272 55775645 Vangelis Koukis
    with the same ordering.
273 55775645 Vangelis Koukis

274 55775645 Vangelis Koukis
    Debian versions are ordered in the same way as Python versions:
275 55775645 Vangelis Koukis

276 55775645 Vangelis Koukis
    >>> D("0.14next") > D("0.14")
277 55775645 Vangelis Koukis
    True
278 55775645 Vangelis Koukis
    >>> D("0.14next") > D("0.14rc7")
279 55775645 Vangelis Koukis
    True
280 55775645 Vangelis Koukis
    >>> D("0.14next") > D("0.14.1")
281 55775645 Vangelis Koukis
    False
282 55775645 Vangelis Koukis
    >>> D("0.14rc6") > D("0.14")
283 55775645 Vangelis Koukis
    False
284 55775645 Vangelis Koukis
    >>> D("0.14.2rc6") > D("0.14.1")
285 55775645 Vangelis Koukis
    True
286 55775645 Vangelis Koukis

287 55775645 Vangelis Koukis
    and
288 55775645 Vangelis Koukis

289 55775645 Vangelis Koukis
    >>> D("0.14next_150") < D("0.14next")
290 55775645 Vangelis Koukis
    True
291 55775645 Vangelis Koukis
    >>> D("0.14.1next_150") < D("0.14.1next")
292 55775645 Vangelis Koukis
    True
293 55775645 Vangelis Koukis
    >>> D("0.14.1_149") < D("0.14.1")
294 55775645 Vangelis Koukis
    True
295 55775645 Vangelis Koukis
    >>> D("0.14.1_149") < D("0.14.1_150")
296 55775645 Vangelis Koukis
    True
297 55775645 Vangelis Koukis

298 55775645 Vangelis Koukis
    and
299 55775645 Vangelis Koukis

300 55775645 Vangelis Koukis
    >>> D("0.13next_102") < D("0.13next")
301 55775645 Vangelis Koukis
    True
302 55775645 Vangelis Koukis
    >>> D("0.13next") < D("0.14rc5_120")
303 55775645 Vangelis Koukis
    True
304 55775645 Vangelis Koukis
    >>> D("0.14rc3_120") < D("0.14rc3")
305 55775645 Vangelis Koukis
    True
306 55775645 Vangelis Koukis
    >>> D("0.14rc3") < D("0.14_1")
307 55775645 Vangelis Koukis
    True
308 55775645 Vangelis Koukis
    >>> D("0.14_120") < D("0.14")
309 55775645 Vangelis Koukis
    True
310 55775645 Vangelis Koukis
    >>> D("0.14") < D("0.14next_20")
311 55775645 Vangelis Koukis
    True
312 55775645 Vangelis Koukis
    >>> D("0.14next_20") < D("0.14next")
313 55775645 Vangelis Koukis
    True
314 55775645 Vangelis Koukis

315 55775645 Vangelis Koukis
    """
316 9fe1ecd8 Christos Stavrakakis
    version = pyver.replace("_", "~").replace("rc", "~rc")
317 42868817 Christos Stavrakakis
    codename = utils.get_distribution_codename()
318 36860fc2 Christos Stavrakakis
    minor = str(get_revision(version, codename))
319 42868817 Christos Stavrakakis
    return version + "-" + minor + "~" + codename
320 9fe1ecd8 Christos Stavrakakis
321 9fe1ecd8 Christos Stavrakakis
322 36860fc2 Christos Stavrakakis
def get_revision(version, codename):
323 9fe1ecd8 Christos Stavrakakis
    """Find revision for a debian version"""
324 84a40792 Christos Stavrakakis
    version_tag = utils.version_to_tag(version)
325 9fe1ecd8 Christos Stavrakakis
    repo = utils.get_repository()
326 9fe1ecd8 Christos Stavrakakis
    minor = 1
327 9fe1ecd8 Christos Stavrakakis
    while True:
328 36860fc2 Christos Stavrakakis
        tag = "debian/" + version_tag + "-" + str(minor) + codename
329 9fe1ecd8 Christos Stavrakakis
        if tag in repo.tags:
330 9fe1ecd8 Christos Stavrakakis
            minor += 1
331 9fe1ecd8 Christos Stavrakakis
        else:
332 9fe1ecd8 Christos Stavrakakis
            return minor
333 55775645 Vangelis Koukis
334 55775645 Vangelis Koukis
335 866bb9c1 Christos Stavrakakis
def get_python_version():
336 9fe1ecd8 Christos Stavrakakis
    v = utils.get_vcs_info()
337 4a45f70c Christos Stavrakakis
    b = get_base_version(v)
338 c181882a Christos Stavrakakis
    mode = utils.get_build_mode()
339 866bb9c1 Christos Stavrakakis
    return python_version(b, v, mode)
340 866bb9c1 Christos Stavrakakis
341 866bb9c1 Christos Stavrakakis
342 55775645 Vangelis Koukis
def debian_version(base_version, vcs_info, mode):
343 55775645 Vangelis Koukis
    p = python_version(base_version, vcs_info, mode)
344 55775645 Vangelis Koukis
    return debian_version_from_python_version(p)
345 55775645 Vangelis Koukis
346 55775645 Vangelis Koukis
347 866bb9c1 Christos Stavrakakis
def get_debian_version():
348 9fe1ecd8 Christos Stavrakakis
    v = utils.get_vcs_info()
349 4a45f70c Christos Stavrakakis
    b = get_base_version(v)
350 c181882a Christos Stavrakakis
    mode = utils.get_build_mode()
351 866bb9c1 Christos Stavrakakis
    return debian_version(b, v, mode)
352 866bb9c1 Christos Stavrakakis
353 866bb9c1 Christos Stavrakakis
354 bec4bf12 Christos Stavrakakis
def update_version():
355 4a45f70c Christos Stavrakakis
    """Generate or replace version files
356 4a45f70c Christos Stavrakakis

357 4a45f70c Christos Stavrakakis
    Helper function for generating/replacing version files containing version
358 bec4bf12 Christos Stavrakakis
    information.
359 55775645 Vangelis Koukis

360 55775645 Vangelis Koukis
    """
361 55775645 Vangelis Koukis
362 9fe1ecd8 Christos Stavrakakis
    v = utils.get_vcs_info()
363 ffcbf2bb Christos Stavrakakis
    toplevel = v.toplevel
364 c400246b Christos Stavrakakis
365 ffcbf2bb Christos Stavrakakis
    config = utils.get_config()
366 55775645 Vangelis Koukis
    if not v:
367 55775645 Vangelis Koukis
        # Return early if not in development environment
368 bec4bf12 Christos Stavrakakis
        raise RuntimeError("Can not compute version outside of a git"
369 bec4bf12 Christos Stavrakakis
                           " repository.")
370 4a45f70c Christos Stavrakakis
    b = get_base_version(v)
371 c181882a Christos Stavrakakis
    mode = utils.get_build_mode()
372 55775645 Vangelis Koukis
    version = python_version(b, v, mode)
373 595d480a Christos Stavrakakis
    debian_version_ = debian_version_from_python_version(version)
374 3a137edf Christos Stavrakakis
    env = {"DEVFLOW_VERSION": version,
375 595d480a Christos Stavrakakis
           "DEVFLOW_DEBIAN_VERSION": debian_version_,
376 3a137edf Christos Stavrakakis
           "DEVFLOW_BRANCH": v.branch,
377 3a137edf Christos Stavrakakis
           "DEVFLOW_REVISION_ID": v.revid,
378 3a137edf Christos Stavrakakis
           "DEVFLOW_REVISION_NUMBER": v.revno,
379 3a137edf Christos Stavrakakis
           "DEVFLOW_USER_EMAIL": v.email,
380 3a137edf Christos Stavrakakis
           "DEVFLOW_USER_NAME": v.name}
381 55775645 Vangelis Koukis
382 445f53a7 Christos Stavrakakis
    for _pkg_name, pkg_info in config['packages'].items():
383 3a137edf Christos Stavrakakis
        version_filename = pkg_info.get('version_file')
384 3a137edf Christos Stavrakakis
        if not version_filename:
385 3a137edf Christos Stavrakakis
            continue
386 3a137edf Christos Stavrakakis
        version_template = pkg_info.get('version_template')
387 3a137edf Christos Stavrakakis
        if version_template:
388 3a137edf Christos Stavrakakis
            vtemplate_file = os.path.join(toplevel, version_template)
389 3a137edf Christos Stavrakakis
            try:
390 3a137edf Christos Stavrakakis
                with file(vtemplate_file) as f:
391 3a137edf Christos Stavrakakis
                    content = f.read(-1) % env
392 3a137edf Christos Stavrakakis
            except IOError as e:
393 3a137edf Christos Stavrakakis
                if e.errno == 2:
394 3a137edf Christos Stavrakakis
                    raise RuntimeError("devflow.conf contains '%s' as a"
395 3a137edf Christos Stavrakakis
                                       " version template file, but file does"
396 3a137edf Christos Stavrakakis
                                       " not exists!" % vtemplate_file)
397 3a137edf Christos Stavrakakis
                else:
398 3a137edf Christos Stavrakakis
                    raise
399 3a137edf Christos Stavrakakis
        else:
400 3a137edf Christos Stavrakakis
            content = DEFAULT_VERSION_FILE % env
401 3a137edf Christos Stavrakakis
        with file(os.path.join(toplevel, version_filename), 'w+') as f:
402 97b86f46 Christos Stavrakakis
            log.info("Updating version file '%s'" % version_filename)
403 3a137edf Christos Stavrakakis
            f.write(content)
404 55775645 Vangelis Koukis
405 55775645 Vangelis Koukis
406 7c1589db Christos Stavrakakis
def bump_version_main():
407 7c1589db Christos Stavrakakis
    try:
408 7c1589db Christos Stavrakakis
        version = sys.argv[1]
409 7c1589db Christos Stavrakakis
        bump_version(version)
410 7c1589db Christos Stavrakakis
    except IndexError:
411 7c1589db Christos Stavrakakis
        sys.stdout.write("Give me a version %s!\n")
412 7c1589db Christos Stavrakakis
        sys.stdout.write("usage: %s version\n" % sys.argv[0])
413 7c1589db Christos Stavrakakis
414 7c1589db Christos Stavrakakis
415 7c1589db Christos Stavrakakis
def bump_version(new_version):
416 7c1589db Christos Stavrakakis
    """Set new base version to base version file and commit"""
417 9fe1ecd8 Christos Stavrakakis
    v = utils.get_vcs_info()
418 c181882a Christos Stavrakakis
    mode = utils.get_build_mode()
419 7c1589db Christos Stavrakakis
420 7c1589db Christos Stavrakakis
    # Check that new base version is valid
421 7c1589db Christos Stavrakakis
    python_version(new_version, v, mode)
422 7c1589db Christos Stavrakakis
423 9fe1ecd8 Christos Stavrakakis
    repo = utils.get_repository()
424 7c1589db Christos Stavrakakis
    toplevel = repo.working_dir
425 7c1589db Christos Stavrakakis
426 4a45f70c Christos Stavrakakis
    old_version = get_base_version(v)
427 7c1589db Christos Stavrakakis
    sys.stdout.write("Current base version is '%s'\n" % old_version)
428 7c1589db Christos Stavrakakis
429 ffcbf2bb Christos Stavrakakis
    version_file = os.path.join(toplevel, "version")
430 7c1589db Christos Stavrakakis
    sys.stdout.write("Updating version file %s from version '%s' to '%s'\n"
431 7c1589db Christos Stavrakakis
                     % (version_file, old_version, new_version))
432 7c1589db Christos Stavrakakis
433 7c1589db Christos Stavrakakis
    f = open(version_file, 'rw+')
434 7c1589db Christos Stavrakakis
    lines = f.readlines()
435 7c1589db Christos Stavrakakis
    for i in range(0, len(lines)):
436 7c1589db Christos Stavrakakis
        if not lines[i].startswith("#"):
437 445f53a7 Christos Stavrakakis
            lines[i] = lines[i].replace(old_version, new_version)
438 7c1589db Christos Stavrakakis
    f.seek(0)
439 a1a26749 Christos Stavrakakis
    f.truncate(0)
440 7c1589db Christos Stavrakakis
    f.writelines(lines)
441 7c1589db Christos Stavrakakis
    f.close()
442 7c1589db Christos Stavrakakis
443 7c1589db Christos Stavrakakis
    repo.git.add(version_file)
444 e87745ef Christos Stavrakakis
    repo.git.commit(m="Bump version to %s" % new_version)
445 7c1589db Christos Stavrakakis
    sys.stdout.write("Update version file and commited\n")
446 7c1589db Christos Stavrakakis
447 7c1589db Christos Stavrakakis
448 866bb9c1 Christos Stavrakakis
def main():
449 9fe1ecd8 Christos Stavrakakis
    v = utils.get_vcs_info()
450 4a45f70c Christos Stavrakakis
    b = get_base_version(v)
451 c181882a Christos Stavrakakis
    mode = utils.get_build_mode()
452 55775645 Vangelis Koukis
453 55775645 Vangelis Koukis
    try:
454 55775645 Vangelis Koukis
        arg = sys.argv[1]
455 55775645 Vangelis Koukis
        assert arg == "python" or arg == "debian"
456 55775645 Vangelis Koukis
    except IndexError:
457 55775645 Vangelis Koukis
        raise ValueError("A single argument, 'python' or 'debian is required")
458 55775645 Vangelis Koukis
459 55775645 Vangelis Koukis
    if arg == "python":
460 55775645 Vangelis Koukis
        print python_version(b, v, mode)
461 55775645 Vangelis Koukis
    elif arg == "debian":
462 55775645 Vangelis Koukis
        print debian_version(b, v, mode)
463 866bb9c1 Christos Stavrakakis
464 866bb9c1 Christos Stavrakakis
if __name__ == "__main__":
465 866bb9c1 Christos Stavrakakis
    sys.exit(main())