changeset 1858:06e13ae616cf

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
author Goffi <goffi@goffi.org>
date Sun, 28 Feb 2016 13:42:31 +0100
parents 2d2617930f97
children ac2ac7fe8a9b
files src/tools/utils.py
diffstat 1 files changed, 60 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- 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'