11# vim: tabstop=4 shiftwidth=4 softtabstop=4
22
33# Copyright 2011 OpenStack LLC.
4+ # Copyright 2012-2013 Hewlett-Packard Development Company, L.P.
45# All Rights Reserved.
56#
67# Licensed under the Apache License, Version 2.0 (the "License"); you may
1920Utilities with minimum-depends for use in setup.py
2021"""
2122
22- import datetime
23+ import email
2324import os
2425import re
2526import subprocess
@@ -33,20 +34,21 @@ def parse_mailmap(mailmap='.mailmap'):
3334 if os .path .exists (mailmap ):
3435 with open (mailmap , 'r' ) as fp :
3536 for l in fp :
36- l = l .strip ()
37- if not l .startswith ('#' ) and ' ' in l :
38- canonical_email , alias = [x for x in l .split (' ' )
39- if x .startswith ('<' )]
40- mapping [alias ] = canonical_email
37+ try :
38+ canonical_email , alias = re .match (
39+ r'[^#]*?(<.+>).*(<.+>).*' , l ).groups ()
40+ except AttributeError :
41+ continue
42+ mapping [alias ] = canonical_email
4143 return mapping
4244
4345
4446def canonicalize_emails (changelog , mapping ):
4547 """Takes in a string and an email alias mapping and replaces all
4648 instances of the aliases in the string with their real email.
4749 """
48- for alias , email in mapping .iteritems ():
49- changelog = changelog .replace (alias , email )
50+ for alias , email_address in mapping .iteritems ():
51+ changelog = changelog .replace (alias , email_address )
5052 return changelog
5153
5254
@@ -78,6 +80,10 @@ def parse_requirements(requirements_files=['requirements.txt',
7880 # -f lines are for index locations, and don't get used here
7981 elif re .match (r'\s*-f\s+' , line ):
8082 pass
83+ # argparse is part of the standard library starting with 2.7
84+ # adding it to the requirements list screws distro installs
85+ elif line == 'argparse' and sys .version_info >= (2 , 7 ):
86+ pass
8187 else :
8288 requirements .append (line )
8389
@@ -102,23 +108,17 @@ def parse_dependency_links(requirements_files=['requirements.txt',
102108 return dependency_links
103109
104110
105- def write_requirements ():
106- venv = os .environ .get ('VIRTUAL_ENV' , None )
107- if venv is not None :
108- with open ("requirements.txt" , "w" ) as req_file :
109- output = subprocess .Popen (["pip" , "-E" , venv , "freeze" , "-l" ],
110- stdout = subprocess .PIPE )
111- requirements = output .communicate ()[0 ].strip ()
112- req_file .write (requirements )
113-
114-
115- def _run_shell_command (cmd ):
111+ def _run_shell_command (cmd , throw_on_error = False ):
116112 if os .name == 'nt' :
117113 output = subprocess .Popen (["cmd.exe" , "/C" , cmd ],
118- stdout = subprocess .PIPE )
114+ stdout = subprocess .PIPE ,
115+ stderr = subprocess .PIPE )
119116 else :
120117 output = subprocess .Popen (["/bin/sh" , "-c" , cmd ],
121- stdout = subprocess .PIPE )
118+ stdout = subprocess .PIPE ,
119+ stderr = subprocess .PIPE )
120+ if output .returncode and throw_on_error :
121+ raise Exception ("%s returned %d" % cmd , output .returncode )
122122 out = output .communicate ()
123123 if len (out ) == 0 :
124124 return None
@@ -127,57 +127,6 @@ def _run_shell_command(cmd):
127127 return out [0 ].strip ()
128128
129129
130- def _get_git_next_version_suffix (branch_name ):
131- datestamp = datetime .datetime .now ().strftime ('%Y%m%d' )
132- if branch_name == 'milestone-proposed' :
133- revno_prefix = "r"
134- else :
135- revno_prefix = ""
136- _run_shell_command ("git fetch origin +refs/meta/*:refs/remotes/meta/*" )
137- milestone_cmd = "git show meta/openstack/release:%s" % branch_name
138- milestonever = _run_shell_command (milestone_cmd )
139- if milestonever :
140- first_half = "%s~%s" % (milestonever , datestamp )
141- else :
142- first_half = datestamp
143-
144- post_version = _get_git_post_version ()
145- # post version should look like:
146- # 0.1.1.4.gcc9e28a
147- # where the bit after the last . is the short sha, and the bit between
148- # the last and second to last is the revno count
149- (revno , sha ) = post_version .split ("." )[- 2 :]
150- second_half = "%s%s.%s" % (revno_prefix , revno , sha )
151- return "." .join ((first_half , second_half ))
152-
153-
154- def _get_git_current_tag ():
155- return _run_shell_command ("git tag --contains HEAD" )
156-
157-
158- def _get_git_tag_info ():
159- return _run_shell_command ("git describe --tags" )
160-
161-
162- def _get_git_post_version ():
163- current_tag = _get_git_current_tag ()
164- if current_tag is not None :
165- return current_tag
166- else :
167- tag_info = _get_git_tag_info ()
168- if tag_info is None :
169- base_version = "0.0"
170- cmd = "git --no-pager log --oneline"
171- out = _run_shell_command (cmd )
172- revno = len (out .split ("\n " ))
173- sha = _run_shell_command ("git describe --always" )
174- else :
175- tag_infos = tag_info .split ("-" )
176- base_version = "-" .join (tag_infos [:- 2 ])
177- (revno , sha ) = tag_infos [- 2 :]
178- return "%s.%s.%s" % (base_version , revno , sha )
179-
180-
181130def write_git_changelog ():
182131 """Write a changelog based on the git changelog."""
183132 new_changelog = 'ChangeLog'
@@ -223,26 +172,6 @@ def generate_authors():
223172"""
224173
225174
226- def read_versioninfo (project ):
227- """Read the versioninfo file. If it doesn't exist, we're in a github
228- zipball, and there's really no way to know what version we really
229- are, but that should be ok, because the utility of that should be
230- just about nil if this code path is in use in the first place."""
231- versioninfo_path = os .path .join (project , 'versioninfo' )
232- if os .path .exists (versioninfo_path ):
233- with open (versioninfo_path , 'r' ) as vinfo :
234- version = vinfo .read ().strip ()
235- else :
236- version = "0.0.0"
237- return version
238-
239-
240- def write_versioninfo (project , version ):
241- """Write a simple file containing the version of the package."""
242- with open (os .path .join (project , 'versioninfo' ), 'w' ) as fil :
243- fil .write ("%s\n " % version )
244-
245-
246175def get_cmdclass ():
247176 """Return dict of commands to run from setup.py."""
248177
@@ -272,6 +201,9 @@ def run(self):
272201 from sphinx .setup_command import BuildDoc
273202
274203 class LocalBuildDoc (BuildDoc ):
204+
205+ builders = ['html' , 'man' ]
206+
275207 def generate_autoindex (self ):
276208 print "**Autodocumenting from %s" % os .path .abspath (os .curdir )
277209 modules = {}
@@ -307,56 +239,83 @@ def run(self):
307239 if not os .getenv ('SPHINX_DEBUG' ):
308240 self .generate_autoindex ()
309241
310- for builder in [ 'html' , 'man' ] :
242+ for builder in self . builders :
311243 self .builder = builder
312244 self .finalize_options ()
313245 self .project = self .distribution .get_name ()
314246 self .version = self .distribution .get_version ()
315247 self .release = self .distribution .get_version ()
316248 BuildDoc .run (self )
249+
250+ class LocalBuildLatex (LocalBuildDoc ):
251+ builders = ['latex' ]
252+
317253 cmdclass ['build_sphinx' ] = LocalBuildDoc
254+ cmdclass ['build_sphinx_latex' ] = LocalBuildLatex
318255 except ImportError :
319256 pass
320257
321258 return cmdclass
322259
323260
324- def get_git_branchname ():
325- for branch in _run_shell_command ("git branch --color=never" ).split ("\n " ):
326- if branch .startswith ('*' ):
327- _branch_name = branch .split ()[1 ].strip ()
328- if _branch_name == "(no" :
329- _branch_name = "no-branch"
330- return _branch_name
331-
261+ def get_version_from_git (pre_version ):
262+ """Return a version which is equal to the tag that's on the current
263+ revision if there is one, or tag plus number of additional revisions
264+ if the current revision has no tag."""
332265
333- def get_pre_version (projectname , base_version ):
334- """Return a version which is leading up to a version that will
335- be released in the future."""
336266 if os .path .isdir ('.git' ):
337- current_tag = _get_git_current_tag ()
338- if current_tag is not None :
339- version = current_tag
267+ if pre_version :
268+ try :
269+ return _run_shell_command (
270+ "git describe --exact-match" ,
271+ throw_on_error = True ).replace ('-' , '.' )
272+ except Exception :
273+ sha = _run_shell_command ("git log -n1 --pretty=format:%h" )
274+ describe = _run_shell_command ("git describe --always" )
275+ revno = describe .rsplit ("-" , 2 )[- 2 ]
276+ return "%s.a%s.g%s" % (pre_version , revno , sha )
340277 else :
341- branch_name = os .getenv ('BRANCHNAME' ,
342- os .getenv ('GERRIT_REFNAME' ,
343- get_git_branchname ()))
344- version_suffix = _get_git_next_version_suffix (branch_name )
345- version = "%s~%s" % (base_version , version_suffix )
346- write_versioninfo (projectname , version )
347- return version
348- else :
349- version = read_versioninfo (projectname )
350- return version
278+ return _run_shell_command (
279+ "git describe --always" ).replace ('-' , '.' )
280+ return None
351281
352282
353- def get_post_version (projectname ):
354- """Return a version which is equal to the tag that's on the current
355- revision if there is one, or tag plus number of additional revisions
356- if the current revision has no tag."""
283+ def get_version_from_pkg_info (package_name ):
284+ """Get the version from PKG-INFO file if we can."""
285+ try :
286+ pkg_info_file = open ('PKG-INFO' , 'r' )
287+ except (IOError , OSError ):
288+ return None
289+ try :
290+ pkg_info = email .message_from_file (pkg_info_file )
291+ except email .MessageError :
292+ return None
293+ # Check to make sure we're in our own dir
294+ if pkg_info .get ('Name' , None ) != package_name :
295+ return None
296+ return pkg_info .get ('Version' , None )
357297
358- if os .path .isdir ('.git' ):
359- version = _get_git_post_version ()
360- write_versioninfo (projectname , version )
298+
299+ def get_version (package_name , pre_version = None ):
300+ """Get the version of the project. First, try getting it from PKG-INFO, if
301+ it exists. If it does, that means we're in a distribution tarball or that
302+ install has happened. Otherwise, if there is no PKG-INFO file, pull the
303+ version from git.
304+
305+ We do not support setup.py version sanity in git archive tarballs, nor do
306+ we support packagers directly sucking our git repo into theirs. We expect
307+ that a source tarball be made from our git repo - or that if someone wants
308+ to make a source tarball from a fork of our repo with additional tags in it
309+ that they understand and desire the results of doing that.
310+ """
311+ version = os .environ .get ("OSLO_PACKAGE_VERSION" , None )
312+ if version :
313+ return version
314+ version = get_version_from_pkg_info (package_name )
315+ if version :
316+ return version
317+ version = get_version_from_git (pre_version )
318+ if version :
361319 return version
362- return read_versioninfo (projectname )
320+ raise Exception ("Versioning for this project requires either an sdist"
321+ " tarball, or access to an upstream git repository." )
0 commit comments