- self._subs[name] = File(self, name, mode, sha, bupmode,
- self._repo_dir)
-
- def metadata(self):
- """Return this Dir's Metadata() object, if any."""
- self._populate_metadata()
- return self._metadata
-
- def metadata_file(self):
- """Return this Dir's .bupm File, if any."""
- if not self._subs:
- self._mksubs()
- return self._bupm
-
- def release(self):
- """Release restorable resources held by this node."""
- self._bupm = None
- super(Dir, self).release()
-
-
-class CommitDir(Node):
- """A directory that contains all commits that are reachable by a ref.
-
- Contains a set of subdirectories named after the commits' first byte in
- hexadecimal. Each of those directories contain all commits with hashes that
- start the same as the directory name. The name used for those
- subdirectories is the hash of the commit without the first byte. This
- separation helps us avoid having too much directories on the same level as
- the number of commits grows big.
+ item_gen = tree_items(item.oid, data, names)
+ elif obj_type == 'commit':
+ if want_meta:
+ item_gen = tree_items_with_meta(repo, item.oid, tree_data, names)
+ else:
+ item_gen = tree_items(item.oid, tree_data, names)
+ else:
+ for _ in it: pass
+ raise Exception('unexpected git ' + obj_type)
+ elif item_t == RevList:
+ item_gen = revlist_items(repo, item.oid, names)
+ elif item_t == Root:
+ item_gen = root_items(repo, names, want_meta)
+ elif item_t == Tags:
+ item_gen = tags_items(repo, names)
+ else:
+ raise Exception('unexpected VFS item ' + str(item))
+ for x in item_gen:
+ yield x
+
+def _resolve_path(repo, path, parent=None, want_meta=True, deref=False):
+ def raise_dir_required_but_not_dir(path, parent, past):
+ raise IOError(ENOTDIR,
+ "path %r%s resolves to non-directory %r"
+ % (path,
+ ' (relative to %r)' % parent if parent else '',
+ past),
+ terminus=past)
+ global _root
+ assert repo
+ assert len(path)
+ if parent:
+ for x in parent:
+ assert len(x) == 2
+ assert type(x[0]) in (bytes, str)
+ assert type(x[1]) in item_types
+ assert parent[0][1] == _root
+ if not S_ISDIR(item_mode(parent[-1][1])):
+ raise IOError(ENOTDIR,
+ 'path resolution parent %r is not a directory'
+ % (parent,))
+ is_absolute, must_be_dir, future = _decompose_path(path)
+ if must_be_dir:
+ deref = True
+ if not future: # path was effectively '.' or '/'
+ if is_absolute:
+ return (('', _root),)
+ if parent:
+ return tuple(parent)
+ return [('', _root)]
+ if is_absolute:
+ past = [('', _root)]
+ else:
+ past = list(parent) if parent else [('', _root)]
+ hops = 0
+ while True:
+ if not future:
+ if must_be_dir and not S_ISDIR(item_mode(past[-1][1])):
+ raise_dir_required_but_not_dir(path, parent, past)
+ return tuple(past)
+ segment = future.pop()
+ if segment == '..':
+ assert len(past) > 0
+ if len(past) > 1: # .. from / is /
+ assert S_ISDIR(item_mode(past[-1][1]))
+ past.pop()
+ else:
+ parent_name, parent_item = past[-1]
+ wanted = (segment,) if not want_meta else ('.', segment)
+ items = tuple(contents(repo, parent_item, names=wanted,
+ want_meta=want_meta))
+ if not want_meta:
+ item = items[0][1] if items else None
+ else: # First item will be '.' and have the metadata
+ item = items[1][1] if len(items) == 2 else None
+ dot, dot_item = items[0]
+ assert dot == '.'
+ past[-1] = parent_name, parent_item
+ if not item:
+ past.append((segment, None),)
+ return tuple(past)
+ mode = item_mode(item)
+ if not S_ISLNK(mode):
+ if not S_ISDIR(mode):
+ past.append((segment, item),)
+ if future:
+ raise IOError(ENOTDIR,
+ 'path %r%s ends internally in non-directory here: %r'
+ % (path,
+ ' (relative to %r)' % parent if parent else '',
+ past),
+ terminus=past)
+ if must_be_dir:
+ raise_dir_required_but_not_dir(path, parent, past)
+ return tuple(past)
+ # It's treeish
+ if want_meta and type(item) in real_tree_types:
+ dir_meta = _find_treeish_oid_metadata(repo, item.oid)
+ if dir_meta:
+ item = item._replace(meta=dir_meta)
+ past.append((segment, item))
+ else: # symlink
+ if not future and not deref:
+ past.append((segment, item),)
+ continue
+ if hops > 100:
+ raise IOError(ELOOP,
+ 'too many symlinks encountered while resolving %r%s'
+ % (path, ' relative to %r' % parent if parent else ''),
+ terminus=tuple(past + [(segment, item)]))
+ target = readlink(repo, item)
+ is_absolute, _, target_future = _decompose_path(target)
+ if is_absolute:
+ if not target_future: # path was effectively '/'
+ return (('', _root),)
+ past = [('', _root)]
+ future = target_future
+ else:
+ future.extend(target_future)
+ hops += 1
+
+def lresolve(repo, path, parent=None, want_meta=True):
+ """Perform exactly the same function as resolve(), except if the final
+ path element is a symbolic link, don't follow it, just return it
+ in the result.
+