# HG changeset patch # User Goffi # Date 1456663351 -3600 # Node ID 06e13ae616cf0caa9638c5ea983742de2496e4cb # Parent 2d2617930f97eddc59a0ff5fef38eed34adf4112 tools (utils): improved repository version detection: - getRepositoryData has 2 new option: is_path to give absolute path instead of module name, and save_dir_path to save the repository data in a pickled dictionnary - if "hg" executable doesn't work, a .hg_data dictionnary is checked if present in module root path diff -r 2d2617930f97 -r 06e13ae616cf src/tools/utils.py --- a/src/tools/utils.py Sun Feb 28 01:57:51 2016 +0100 +++ b/src/tools/utils.py Sun Feb 28 13:42:31 2016 +0100 @@ -53,11 +53,22 @@ return datetime.datetime.utcfromtimestamp(time.time() if timestamp is None else timestamp).strftime(template) -def getRepositoryData(module, as_string=True): +def getRepositoryData(module, as_string=True, is_path=False, save_dir_path=None): """Retrieve info on current mecurial repository - @param module: module to look for (e.g. sat, libervia) + Data is gotten by using the following methods, in order: + - using "hg" executable + - looking for a ".hg_data" file in the root of the module + this file must contain the data dictionnary serialized with pickle + - looking for a .hg/dirstate in parent directory of module (or in module/.hg if + is_path is True), and parse dirstate file to get revision + @param module(unicode): module to look for (e.g. sat, libervia) + module can be a path if is_path is True (see below) @param as_string(bool): if True return a string, else return a dictionary + @param is_path(bool): if True "module" is not handled as a module name, but as an + absolute path to the parent of a ".hg" directory + @param save_path(str, None): if not None, the value will be saved to given path as a pickled dict + /!\\ the .hg_data file in the given directory will be overwritten @return (unicode, dictionary): retrieved info in a nice string, or a dictionary with retrieved data (key is not present if data is not found), key can be: @@ -69,7 +80,13 @@ from distutils.spawn import find_executable import subprocess KEYS=("node", "node_short", "branch", "date", "tag") - repos_root = os.path.dirname(module.__file__) + ori_cwd = os.getcwd() + + if is_path: + repos_root = module + else: + repos_root = os.path.dirname(module.__file__) + hg_path = find_executable('hg') if hg_path is not None: @@ -88,8 +105,27 @@ hg_data = {} if not hg_data: - log.debug(u"Mercurial not available or working, trying to get data from dirstate") - os.chdir(os.path.relpath('..', repos_root)) + # .hg_data pickle method + log.debug(u"Mercurial not available or working, trying other methods") + if save_dir_path is None: + log.debug(u"trying .hg_data method") + + try: + with open(os.path.join(repos_root, '.hg_data')) as f: + import cPickle as pickle + hg_data = pickle.load(f) + except IOError as e: + log.debug(u"Can't access .hg_data file: {}".format(e)) + except pickle.UnpicklingError: + log.warning(u"Error while reading {}, can't get repos data".format(f.name)) + + if not hg_data: + # .hg/dirstate method + log.debug(u"trying dirstate method") + if is_path: + os.chdir(repos_root) + else: + os.chdir(os.path.relpath('..', repos_root)) try: with open('.hg/dirstate') as hg_dirstate: hg_data['node'] = hg_dirstate.read(20).encode('hex') @@ -97,6 +133,25 @@ except IOError: log.warning(u"Can't access repository data") + # we restore original working dir + os.chdir(ori_cwd) + + # data saving + if save_dir_path is not None and hg_data: + if not os.path.isdir(save_dir_path): + log.warning(u"Given path is not a directory, can't save data") + else: + import cPickle as pickle + dest_path = os.path.join(save_dir_path, ".hg_data") + try: + with open(dest_path, 'w') as f: + pickle.dump(hg_data, f, 2) + except IOError as e: + log.warning(u"Can't save file to {path}: {reason}".format( + path=dest_path, reason=e)) + else: + log.debug(u"repository data saved to {}".format(dest_path)) + if as_string: if not hg_data: return u'repository data unknown'