+ full_path = ''
+ for p in norm_path.split('/')[1:]:
+ full_path += '/' + p
+ result.append((p, full_path))
+ return result
+
+
+def stripped_path_components(path, strip_prefixes):
+ """Strip any prefix in strip_prefixes from path and return a list
+ of path components where each component is (name,
+ none_or_full_fs_path_to_name). Assume path startswith('/').
+ See thelpers.py for examples."""
+ normalized_path = os.path.abspath(path)
+ sorted_strip_prefixes = sorted(strip_prefixes, key=len, reverse=True)
+ for bp in sorted_strip_prefixes:
+ normalized_bp = os.path.abspath(bp)
+ if normalized_bp == '/':
+ continue
+ if normalized_path.startswith(normalized_bp):
+ prefix = normalized_path[:len(normalized_bp)]
+ result = []
+ for p in normalized_path[len(normalized_bp):].split('/'):
+ if p: # not root
+ prefix += '/'
+ prefix += p
+ result.append((p, prefix))
+ return result
+ # Nothing to strip.
+ return path_components(path)
+
+
+def grafted_path_components(graft_points, path):
+ # Create a result that consists of some number of faked graft
+ # directories before the graft point, followed by all of the real
+ # directories from path that are after the graft point. Arrange
+ # for the directory at the graft point in the result to correspond
+ # to the "orig" directory in --graft orig=new. See t/thelpers.py
+ # for some examples.
+
+ # Note that given --graft orig=new, orig and new have *nothing* to
+ # do with each other, even if some of their component names
+ # match. i.e. --graft /foo/bar/baz=/foo/bar/bax is semantically
+ # equivalent to --graft /foo/bar/baz=/x/y/z, or even
+ # /foo/bar/baz=/x.
+
+ # FIXME: This can't be the best solution...
+ clean_path = os.path.abspath(path)
+ for graft_point in graft_points:
+ old_prefix, new_prefix = graft_point
+ # Expand prefixes iff not absolute paths.
+ old_prefix = os.path.normpath(old_prefix)
+ new_prefix = os.path.normpath(new_prefix)
+ if clean_path.startswith(old_prefix):
+ escaped_prefix = re.escape(old_prefix)
+ grafted_path = re.sub(r'^' + escaped_prefix, new_prefix, clean_path)
+ # Handle /foo=/ (at least) -- which produces //whatever.
+ grafted_path = '/' + grafted_path.lstrip('/')
+ clean_path_components = path_components(clean_path)
+ # Count the components that were stripped.
+ strip_count = 0 if old_prefix == '/' else old_prefix.count('/')
+ new_prefix_parts = new_prefix.split('/')
+ result_prefix = grafted_path.split('/')[:new_prefix.count('/')]
+ result = [(p, None) for p in result_prefix] \
+ + clean_path_components[strip_count:]
+ # Now set the graft point name to match the end of new_prefix.
+ graft_point = len(result_prefix)
+ result[graft_point] = \
+ (new_prefix_parts[-1], clean_path_components[strip_count][1])
+ if new_prefix == '/': # --graft ...=/ is a special case.
+ return result[1:]
+ return result
+ return path_components(clean_path)
+
+
+Sha1 = hashlib.sha1
+
+
+_localtime = getattr(_helpers, 'localtime', None)
+
+if _localtime:
+ bup_time = namedtuple('bup_time', ['tm_year', 'tm_mon', 'tm_mday',
+ 'tm_hour', 'tm_min', 'tm_sec',
+ 'tm_wday', 'tm_yday',
+ 'tm_isdst', 'tm_gmtoff', 'tm_zone'])
+
+# Define a localtime() that returns bup_time when possible. Note:
+# this means that any helpers.localtime() results may need to be
+# passed through to_py_time() before being passed to python's time
+# module, which doesn't appear willing to ignore the extra items.
+if _localtime:
+ def localtime(time):
+ return bup_time(*_helpers.localtime(time))
+ def utc_offset_str(t):
+ """Return the local offset from UTC as "+hhmm" or "-hhmm" for time t.
+ If the current UTC offset does not represent an integer number
+ of minutes, the fractional component will be truncated."""
+ off = localtime(t).tm_gmtoff
+ # Note: // doesn't truncate like C for negative values, it rounds down.
+ offmin = abs(off) // 60
+ m = offmin % 60
+ h = (offmin - m) // 60
+ return "%+03d%02d" % (-h if off < 0 else h, m)
+ def to_py_time(x):
+ if isinstance(x, time.struct_time):
+ return x
+ return time.struct_time(x[:9])