""" Generate header file with macros defining MicroPython version info. This script works with Python 2.6, 2.7, 3.3 and 3.4. """ from __future__ import print_function import argparse import sys import os import datetime import subprocess # The MicroPython repository tags a release commit as "vX.Y.Z", and the commit # immediately following as "vX.(Y+1).Z-preview". # This function will return: # "vX.Y.Z" -- building at the release commit # "vX.Y.Z-preview" -- building at the first commit in the next cycle # "vX.Y.Z-preview.N.gHASH" -- building at any subsequent commit in the cycle # "vX.Y.Z-preview.N.gHASH.dirty" -- building at any subsequent commit in the cycle # with local changes def get_version_info_from_git(repo_path): # Python 2.6 doesn't have check_output, so check for that try: subprocess.check_output subprocess.check_call except AttributeError: return None # Note: git describe doesn't work if no tag is available try: git_tag = subprocess.check_output( ["git", "describe", "--tags", "--dirty", "--always", "--match", "v[1-9].*"], cwd=repo_path, stderr=subprocess.STDOUT, universal_newlines=True, ).strip() # Turn git-describe's output into semver compatible (dot-separated # identifiers inside the prerelease field). git_tag = git_tag.split("-", 1) if len(git_tag) == 1: return git_tag[0] else: return git_tag[0] + "-" + git_tag[1].replace("-", ".") except subprocess.CalledProcessError: return None except OSError: return None # When building from a source tarball (or any situation where the git repo # isn't available), this function will use the info in mpconfig.h as a # fallback. The release commit sets MICROPY_VERSION_PRERELEASE to 0, and the # commit immediately following increments MICROPY_VERSION_MINOR and sets # MICROPY_VERSION_PRERELEASE back to 1. # This function will return: # "vX.Y.Z" -- building at the release commit # "vX.Y.Z-preview" -- building at any other commit def get_version_info_from_mpconfig(repo_path): print( "makeversionhdr.py: Warning: No git repo or tag info available, falling back to mpconfig.h version info.", file=sys.stderr, ) with open(os.path.join(repo_path, "py", "mpconfig.h")) as f: for line in f: if line.startswith("#define MICROPY_VERSION_MAJOR "): ver_major = int(line.strip().split()[2]) elif line.startswith("#define MICROPY_VERSION_MINOR "): ver_minor = int(line.strip().split()[2]) elif line.startswith("#define MICROPY_VERSION_MICRO "): ver_micro = int(line.strip().split()[2]) elif line.startswith("#define MICROPY_VERSION_PRERELEASE "): ver_prerelease = int(line.strip().split()[2]) git_tag = "v%d.%d.%d%s" % ( ver_major, ver_minor, ver_micro, "-preview" if ver_prerelease else "", ) return git_tag return None def make_version_header(repo_path, filename): git_tag = None if "MICROPY_GIT_TAG" in os.environ: git_tag = os.environ["MICROPY_GIT_TAG"] if git_tag is None: git_tag = get_version_info_from_git(repo_path) if git_tag is None: git_tag = get_version_info_from_mpconfig(repo_path) if not git_tag: print("makeversionhdr.py: Error: No version information available.") sys.exit(1) build_date = datetime.date.today() if "SOURCE_DATE_EPOCH" in os.environ: build_date = datetime.datetime.utcfromtimestamp( int(os.environ["SOURCE_DATE_EPOCH"]) ).date() # Generate the file with the git and version info file_data = """\ // This file was generated by py/makeversionhdr.py #define MICROPY_GIT_TAG "%s" #define MICROPY_BUILD_DATE "%s" """ % ( git_tag, build_date.strftime("%Y-%m-%d"), ) # Check if the file contents changed from last time write_file = True if os.path.isfile(filename): with open(filename, "r") as f: existing_data = f.read() if existing_data == file_data: write_file = False # Only write the file if we need to if write_file: print("GEN %s" % filename) with open(filename, "w") as f: f.write(file_data) def main(): parser = argparse.ArgumentParser() # makeversionheader.py lives in repo/py, so default repo_path to the # parent of sys.argv[0]'s directory. parser.add_argument( "-r", "--repo-path", default=os.path.join(os.path.dirname(sys.argv[0]), ".."), help="path to MicroPython Git repo to query for version", ) parser.add_argument("dest", nargs=1, help="output file path") args = parser.parse_args() make_version_header(args.repo_path, args.dest[0]) if __name__ == "__main__": main()