Beispiel #1
0
def get_tree_changes(repo):
    """Return add/delete/modify changes to tree by comparing index to HEAD.

    :param repo: repo path or object
    :return: dict with lists for each type of change
    """
    r = open_repo(repo)
    index = r.open_index()

    # Compares the Index to the HEAD & determines changes
    # Iterate through the changes and report add/delete/modify
    # TODO: call out to dulwich.diff_tree somehow.
    tracked_changes = {
        'add': [],
        'delete': [],
        'modify': [],
    }
    for change in index.changes_from_tree(r.object_store, r['HEAD'].tree):
        if not change[0][0]:
            tracked_changes['add'].append(change[0][1])
        elif not change[0][1]:
            tracked_changes['delete'].append(change[0][0])
        elif change[0][0] == change[0][1]:
            tracked_changes['modify'].append(change[0][0])
        else:
            raise AssertionError('git mv ops not yet supported')
    return tracked_changes
Beispiel #2
0
def get_tree_changes(repo):
    """Return add/delete/modify changes to tree by comparing index to HEAD.

    :param repo: repo path or object
    :return: dict with lists for each type of change
    """
    r = open_repo(repo)
    index = r.open_index()

    # Compares the Index to the HEAD & determines changes
    # Iterate through the changes and report add/delete/modify
    # TODO: call out to dulwich.diff_tree somehow.
    tracked_changes = {
        'add': [],
        'delete': [],
        'modify': [],
    }
    for change in index.changes_from_tree(r.object_store, r['HEAD'].tree):
        if not change[0][0]:
            tracked_changes['add'].append(change[0][1])
        elif not change[0][1]:
            tracked_changes['delete'].append(change[0][0])
        elif change[0][0] == change[0][1]:
            tracked_changes['modify'].append(change[0][0])
        else:
            raise AssertionError('git mv ops not yet supported')
    return tracked_changes
Beispiel #3
0
 def checkout(self, sha=None):
     self._fetch()
     print "#  Checkout repo %s @ %s => %s.."%(self.remote_uri,sha,self.path)
     self._init_subrepos(sha)
     target = self['HEAD']
     if sha:
         target = self[sha]
     target_tree = target.tree
     index = Index(self.index_path())
     for e_path,e_mode,e_sha in index.changes_from_tree(self.object_store, target_tree, want_unchanged=True):
         e_source = (e_path[1],e_mode[1],e_sha[1])
         e_target = (e_path[0],e_mode[0],e_sha[0])
         e_to_checkout = None
         if e_source[0] and e_target[0]:
             if not os.path.exists(os.path.join(self.path, e_target[0])):
                 e_to_checkout = ("A",e_target)
             elif e_source[2] != e_target[2]:
                 e_to_checkout = ("U",e_target)
         elif not e_target[0]:
             print "D  %s"%(os.path.join(self.path, e_source[0]))
             if stat.S_ISREG(e_source[1]):
                 os.unlink(os.path.join(self.path, e_source[0]))
                 del index[e_source[0]]
         else:
             e_to_checkout = ("A",e_target)
         if e_to_checkout:
             print "%s  %s"%(e_to_checkout[0],os.path.join(self.path,e_to_checkout[1][0]))
             self._checkout_entry(index, *e_to_checkout[1])
     self._init_subrepos(sha)
     for subrepo in self.subrepo.values():
         subrepo[1].checkout(subrepo[0])
Beispiel #4
0
    def _changed_entries(self, ref=None):
        ref = ref or self.DEFAULT_COMMIT
        if not self.has_commits:
            return []
        obj_sto = self.repo.object_store
        tree_id = self[ref].tree
        names = self.trackable_files

        lookup_func = partial(self.lookup_entry, trackable_files=names)

        # Format = [((old_name, new_name), (old_mode, new_mode), (old_sha, new_sha)), ...]
        tree_diff = changes_from_tree(names, lookup_func, obj_sto, tree_id, want_unchanged=False)
        return list(tree_diff)
Beispiel #5
0
    def _changed_entries(self, ref=None):
        ref = ref or self.DEFAULT_COMMIT
        if not self.has_commits:
            return []
        obj_sto = self.repo.object_store
        tree_id = self[ref].tree
        names = self.trackable_files

        lookup_func = partial(self.lookup_entry, trackable_files=names)

        # Format = [((old_name, new_name), (old_mode, new_mode), (old_sha, new_sha)), ...]
        tree_diff = changes_from_tree(names, lookup_func, obj_sto, tree_id, want_unchanged=False)
        return list(tree_diff)
Beispiel #6
0
def write_tree_workingdir_diff(f,
                               store,
                               tree,
                               names,
                               filter_callback=None,
                               diff_binary=False):
    """Write diff of tree against current working dir

    Args:
      f: File-like object to write to.
      tree: tree id for base of comparison
      names: list of working directory relative file paths (bytes only)
      diff_binary: Whether to diff files even if they
        are considered binary files by is_binary().
    """

    entry_info = {}

    def lookup_entry(name):
        if name in entry_info:
            blob, fmode = entry_info[name]
            return (blob.id, fmode)
        return (None, None)

    # convert tree_paths that represent files in working dir
    # to an equivalent temp blob mode and store it
    # This should properly handle checkin normalization
    # which is required to make diffs work properly
    for name in names:
        filepath = name
        if os_sep_bytes != b'/':
            filepath = name.replace(b'/', os_sep_bytes)
        stat = os.stat(filepath)
        fmode = stat.st_mode
        blob = blob_from_path_and_stat(filepath, stat)
        if filter_callback:
            blob = filter_callback(blob, name)
        entry_info[name] = (blob, fmode)

    for change_entry in changes_from_tree(names, lookup_entry, store, tree):
        (name1, name2), (mode1, mode2), (sha1, sha2) = change_entry
        content1 = b''
        content2 = b''
        if name2:
            if name2 in entry_info:
                blob, fmode = entry_info[name2]
                content2 = blob.as_raw_string()
        if name1:
            content1 = store[sha1].as_raw_string()
        _write_diff(f, (name1, mode1, sha1, content1),
                    (name2, mode2, sha2, content2))
Beispiel #7
0
 def status(self, sha=None):
     print "#  Status.."
     target = self['HEAD']
     if sha:
         target = self[sha]
     target_tree = target.tree
     index = Index(self.index_path())
     for e_path,e_mode,e_sha in index.changes_from_tree(self.object_store, target_tree, want_unchanged=True):
         e_source = (e_path[0],e_mode[0],e_sha[0])
         e_target = (e_path[1],e_mode[1],e_sha[1])
         if e_source[0] and e_target[0]:
             if not os.path.exists(os.path.join(self.path, e_source[0])):
                 print "D  %s"%(os.path.join(self.path, e_source[0]))
             elif e_source[2] != e_target[2]:
                 print "M  %s"%(os.path.join(self.path, e_source[0]))
         elif not e_target[0]:
             print "D  %s"%(os.path.join(self.path, e_source[0]))
         else:
             print "A  %s"%(os.path.join(self.path, e_target[0]))
Beispiel #8
0
def emit_repo_as_xdot(repo, options):
    '''Emits xdot for the given repo on stdout.'''

    global graph  # TODO: globals are bad mmmmkay
    global vertices

    vertices = {}

    graph = pydot.Graph(verbose=True)
    graph.set_bgcolor('#00000000')  # transparent background

    objstore = repo.object_store
    seen = set()

    # walk everything in the object store. (this means orphaned nodes will show.)
    for sha in objstore:
        if not options.blobs and objstore[sha].type_name in ('blob', 'tree'):
            continue
        walk_node(objstore, seen, sha, options)

    for ref in repo.refs.keys():
        if ref == 'HEAD':
            continue  # TODO: let this loop handle symbolic refs too
        branch_node = add_branch_node(ref)
        graph.add_edge(
            pydot.Edge(branch_node, repo.refs[ref],
                       **edge_opts(style='dotted')))

    # do HEAD as a special case
    ref = 'HEAD'
    nopts = node_opts(label=ref,
                      shape='diamond',
                      style='filled',
                      fillcolor='#ff3333',
                      fontcolor='white',
                      tooltip='Symbolic Ref: HEAD')
    head_node = pydot.Node(ref, **nopts)
    graph.add_node(head_node)

    symref = repo.refs.read_ref(ref)
    if symref.startswith('ref: '):
        symref = symref[5:]
    points_to = add_branch_node(symref)
    graph.add_node(points_to)
    graph.add_edge(
        pydot.Edge(head_node, add_branch_node(symref),
                   **edge_opts(style='dotted')))

    # index
    if options.index:
        try:
            head_tree = repo['HEAD'].tree
        except KeyError:
            head_tree = None

        index = repo.open_index()

    try:
        changes = list(index.changes_from_tree(objstore, head_tree))
    except TypeError:
        # the official dulwich repo throws a TypeError changes_from_tree is
        # called against an empty tree (None)
        if head_tree is not None: raise
        changes = []

    if changes:
        index_node = pydot.Node('index',
                                shape='invtriangle',
                                style='filled',
                                fillcolor='#33ff33',
                                fontname=DEFAULT_FONTNAME,
                                fontsize=DEFAULT_FONTSIZE)
        graph.add_node(index_node)
        for (oldpath, newpath), (oldmode, newmode), (oldsha,
                                                     newsha) in changes:
            graph.add_edge(
                pydot.Edge(index_node,
                           vert_for_sha(objstore, newsha),
                           label=q('  ' + newpath),
                           fontname=DEFAULT_FONTNAME,
                           fontsize=DEFAULT_FONTSIZE))

    # invoke dot -Txdot to turn out DOT file into an xdot file, which canviz is expecting
    subprocess.Popen(['dot', '-Txdot'],
                     stdin=subprocess.PIPE).communicate(graph.to_string())
Beispiel #9
0
def emit_repo_as_xdot(repo, options):
    """Emits xdot for the given repo on stdout."""

    global graph  # TODO: globals are bad mmmmkay
    global vertices

    vertices = {}

    graph = pydot.Graph(verbose=True)
    graph.set_bgcolor("#00000000")  # transparent background

    objstore = repo.object_store
    seen = set()

    # walk everything in the object store. (this means orphaned nodes will show.)
    for sha in objstore:
        if not options.blobs and objstore[sha].type_name in ("blob", "tree"):
            continue
        walk_node(objstore, seen, sha, options)

    for ref in repo.refs.keys():
        if ref == "HEAD":
            continue  # TODO: let this loop handle symbolic refs too
        branch_node = add_branch_node(ref)
        graph.add_edge(pydot.Edge(branch_node, repo.refs[ref], **edge_opts(style="dotted")))

    # do HEAD as a special case
    ref = "HEAD"
    nopts = node_opts(
        label=ref, shape="diamond", style="filled", fillcolor="#ff3333", fontcolor="white", tooltip="Symbolic Ref: HEAD"
    )
    head_node = pydot.Node(ref, **nopts)
    graph.add_node(head_node)

    symref = repo.refs.read_ref(ref)
    if symref.startswith("ref: "):
        symref = symref[5:]
    points_to = add_branch_node(symref)
    graph.add_node(points_to)
    graph.add_edge(pydot.Edge(head_node, add_branch_node(symref), **edge_opts(style="dotted")))

    # index
    if options.index:
        try:
            head_tree = repo["HEAD"].tree
        except KeyError:
            head_tree = None

        index = repo.open_index()

    try:
        changes = list(index.changes_from_tree(objstore, head_tree))
    except TypeError:
        # the official dulwich repo throws a TypeError changes_from_tree is
        # called against an empty tree (None)
        if head_tree is not None:
            raise
        changes = []

    if changes:
        index_node = pydot.Node(
            "index",
            shape="invtriangle",
            style="filled",
            fillcolor="#33ff33",
            fontname=DEFAULT_FONTNAME,
            fontsize=DEFAULT_FONTSIZE,
        )
        graph.add_node(index_node)
        for (oldpath, newpath), (oldmode, newmode), (oldsha, newsha) in changes:
            graph.add_edge(
                pydot.Edge(
                    index_node,
                    vert_for_sha(objstore, newsha),
                    label=q("  " + newpath),
                    fontname=DEFAULT_FONTNAME,
                    fontsize=DEFAULT_FONTSIZE,
                )
            )

    # invoke dot -Txdot to turn out DOT file into an xdot file, which canviz is expecting
    subprocess.Popen(["dot", "-Txdot"], stdin=subprocess.PIPE).communicate(graph.to_string())