123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185 |
- #!/usr/bin/env python
- from __future__ import absolute_import
- import errno
- import os
- import re
- import shlex
- import subprocess
- import sys
- from contextlib import contextmanager
- from tempfile import NamedTemporaryFile
- str_t = str if sys.version_info[0] >= 3 else basestring
- def rq(s):
- return s.strip("\"'")
- def cmd(*args):
- return subprocess.Popen(args, stdout=subprocess.PIPE).communicate()[0]
- @contextmanager
- def no_enoent():
- try:
- yield
- except OSError as exc:
- if exc.errno != errno.ENOENT:
- raise
- class StringVersion(object):
- def decode(self, s):
- s = rq(s)
- text = ""
- major, minor, release = s.split(".")
- if not release.isdigit():
- pos = release.index(re.split("\d+", release)[1][0])
- release, text = release[:pos], release[pos:]
- return int(major), int(minor), int(release), text
- def encode(self, v):
- return ".".join(map(str, v[:3])) + v[3]
- to_str = StringVersion().encode
- from_str = StringVersion().decode
- class TupleVersion(object):
- def decode(self, s):
- v = list(map(rq, s.split(", ")))
- return (tuple(map(int, v[0:3])) +
- tuple(["".join(v[3:])]))
- def encode(self, v):
- v = list(v)
- def quote(lit):
- if isinstance(lit, str_t):
- return '"{0}"'.format(lit)
- return str(lit)
- if not v[-1]:
- v.pop()
- return ", ".join(map(quote, v))
- class VersionFile(object):
- def __init__(self, filename):
- self.filename = filename
- self._kept = None
- def _as_orig(self, version):
- return self.wb.format(version=self.type.encode(version),
- kept=self._kept)
- def write(self, version):
- pattern = self.regex
- with no_enoent():
- with NamedTemporaryFile() as dest:
- with open(self.filename) as orig:
- for line in orig:
- if pattern.match(line):
- dest.write(self._as_orig(version))
- else:
- dest.write(line)
- os.rename(dest.name, self.filename)
- def parse(self):
- pattern = self.regex
- gpos = 0
- with open(self.filename) as fh:
- for line in fh:
- m = pattern.match(line)
- if m:
- if "?P<keep>" in pattern.pattern:
- self._kept, gpos = m.groupdict()["keep"], 1
- return self.type.decode(m.groups()[gpos])
- class PyVersion(VersionFile):
- regex = re.compile(r'^VERSION\s*=\s*\((.+?)\)')
- wb = "VERSION = ({version})\n"
- type = TupleVersion()
- class SphinxVersion(VersionFile):
- regex = re.compile(r'^:[Vv]ersion:\s*(.+?)$')
- wb = ':Version: {version}\n'
- type = StringVersion()
- class CPPVersion(VersionFile):
- regex = re.compile(r'^\#\s*define\s*(?P<keep>\w*)VERSION\s+(.+)')
- wb = '#define {kept}VERSION "{version}"\n'
- type = StringVersion()
- _filetype_to_type = {"py": PyVersion,
- "rst": SphinxVersion,
- "txt": SphinxVersion,
- "c": CPPVersion,
- "h": CPPVersion}
- def filetype_to_type(filename):
- _, _, suffix = filename.rpartition(".")
- return _filetype_to_type[suffix](filename)
- def bump(*files, **kwargs):
- version = kwargs.get("version")
- before_commit = kwargs.get("before_commit")
- files = [filetype_to_type(f) for f in files]
- versions = [v.parse() for v in files]
- current = list(reversed(sorted(versions)))[0] # find highest
- current = current.split()[0] # only first sentence
- if version:
- next = from_str(version)
- else:
- major, minor, release, text = current
- if text:
- raise Exception("Can't bump alpha releases")
- next = (major, minor, release + 1, text)
- print("Bump version from {0} -> {1}".format(to_str(current), to_str(next)))
- for v in files:
- print(" writing {0.filename!r}...".format(v))
- v.write(next)
- if before_commit:
- cmd(*shlex.split(before_commit))
- print(cmd("git", "commit", "-m", "Bumps version to {0}".format(
- to_str(next)), *[f.filename for f in files]))
- print(cmd("git", "tag", "v{0}".format(to_str(next))))
- def main(argv=sys.argv, version=None, before_commit=None):
- if not len(argv) > 1:
- print("Usage: distdir [docfile] -- <custom version>")
- sys.exit(0)
- args = []
- for arg in argv:
- if arg.startswith("--before-commit="):
- _, before_commit = arg.split('=')
- else:
- args.append(arg)
- if "--" in args:
- c = args.index('--')
- version = args[c + 1]
- argv = args[:c]
- bump(*args[1:], version=version, before_commit=before_commit)
- if __name__ == "__main__":
- main()
|