| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -27,6 +27,9 @@ General | |||
| 27 | 27 | terms are used everywhere, such as "Reference" ( ref ) and "Revision" ( rev ). | |
| 28 | 28 | Prevously multiple terms where used making it harder to know which type was allowed | |
| 29 | 29 | or not. | |
| 30 | + * Unified diff interface to allow easy diffing between trees, trees and index, trees | ||
| 31 | + and working tree, index and working tree, trees and index. This closely follows | ||
| 32 | + the git-diff capabilities. | ||
| 30 | 33 | ||
| 31 | 34 | ||
| 32 | 35 | Item Iteration | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -9,7 +9,7 @@ | |||
| 9 | 9 | ||
| 10 | 10 | class Diff(object): | |
| 11 | 11 | """ | |
| 12 | - A Diff contains diff information between two commits. | ||
| 12 | + A Diff contains diff information between two Trees. | ||
| 13 | 13 | ||
| 14 | 14 | It contains two sides a and b of the diff, members are prefixed with | |
| 15 | 15 | "a" and "b" respectively to inidcate that. | |
@@ -74,18 +74,20 @@ def __init__(self, repo, a_path, b_path, a_blob_id, b_blob_id, a_mode, | |||
| 74 | 74 | self.diff = diff | |
| 75 | 75 | ||
| 76 | 76 | @classmethod | |
| 77 | - def _list_from_string(cls, repo, text): | ||
| 77 | + def _index_from_patch_format(cls, repo, stream): | ||
| 78 | 78 | """ | |
| 79 | - Create a new diff object from the given text | ||
| 79 | + Create a new DiffIndex from the given text which must be in patch format | ||
| 80 | 80 | ``repo`` | |
| 81 | 81 | is the repository we are operating on - it is required | |
| 82 | 82 | ||
| 83 | - ``text`` | ||
| 84 | - result of 'git diff' between two commits or one commit and the index | ||
| 83 | + ``stream`` | ||
| 84 | + result of 'git diff' as a stream (supporting file protocol) | ||
| 85 | 85 | ||
| 86 | 86 | Returns | |
| 87 | - git.Diff[] | ||
| 87 | + git.DiffIndex | ||
| 88 | 88 | """ | |
| 89 | + # for now, we have to bake the stream | ||
| 90 | + text = stream.read() | ||
| 89 | 91 | diffs = [] | |
| 90 | 92 | ||
| 91 | 93 | diff_header = cls.re_header.match | |
@@ -102,4 +104,14 @@ def _list_from_string(cls, repo, text): | |||
| 102 | 104 | new_file, deleted_file, rename_from, rename_to, diff[header.end():])) | |
| 103 | 105 | ||
| 104 | 106 | return diffs | |
| 107 | + | ||
| 108 | + @classmethod | ||
| 109 | + def _index_from_raw_format(cls, repo, stream): | ||
| 110 | + """ | ||
| 111 | + Create a new DiffIndex from the given stream which must be in raw format. | ||
| 112 | + | ||
| 113 | + Returns | ||
| 114 | + git.DiffIndex | ||
| 115 | + """ | ||
| 116 | + raise NotImplementedError("") | ||
| 105 | 117 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -172,3 +172,74 @@ def _mode_str_to_int(cls, modestr): | |||
| 172 | 172 | return mode | |
| 173 | 173 | ||
| 174 | 174 | ||
| 175 | + class Diffable(object): | ||
| 176 | + """ | ||
| 177 | + Common interface for all object that can be diffed against another object of compatible type. | ||
| 178 | + | ||
| 179 | + NOTE: | ||
| 180 | + Subclasses require a repo member as it is the case for Object instances, for practical | ||
| 181 | + reasons we do not derive from Object. | ||
| 182 | + """ | ||
| 183 | + __slots__ = tuple() | ||
| 184 | + | ||
| 185 | + # subclasses provide additional arguments to the git-diff comamnd by supplynig | ||
| 186 | + # them in this tuple | ||
| 187 | + _diff_args = tuple() | ||
| 188 | + | ||
| 189 | + def diff(self, other=None, paths=None, create_patch=False, **kwargs): | ||
| 190 | + """ | ||
| 191 | + Creates diffs between two items being trees, trees and index or an | ||
| 192 | + index and the working tree. | ||
| 193 | + | ||
| 194 | + ``other`` | ||
| 195 | + Is the item to compare us with. | ||
| 196 | + If None, we will be compared to the working tree. | ||
| 197 | + | ||
| 198 | + ``paths`` | ||
| 199 | + is a list of paths or a single path to limit the diff to. | ||
| 200 | + It will only include at least one of the givne path or paths. | ||
| 201 | + | ||
| 202 | + ``create_patch`` | ||
| 203 | + If True, the returned Diff contains a detailed patch that if applied | ||
| 204 | + makes the self to other. Patches are somwhat costly as blobs have to be read | ||
| 205 | + and diffed. | ||
| 206 | + | ||
| 207 | + ``kwargs`` | ||
| 208 | + Additional arguments passed to git-diff, such as | ||
| 209 | + R=True to swap both sides of the diff. | ||
| 210 | + | ||
| 211 | + Returns | ||
| 212 | + git.DiffIndex | ||
| 213 | + | ||
| 214 | + Note | ||
| 215 | + Rename detection will only work if create_patch is True | ||
| 216 | + """ | ||
| 217 | + args = list(self._diff_args[:]) | ||
| 218 | + args.append( "--abbrev=40" ) # we need full shas | ||
| 219 | + args.append( "--full-index" ) # get full index paths, not only filenames | ||
| 220 | + | ||
| 221 | + if create_patch: | ||
| 222 | + args.append("-p") | ||
| 223 | + args.append("-M") # check for renames | ||
| 224 | + else: | ||
| 225 | + args.append("--raw") | ||
| 226 | + | ||
| 227 | + paths = paths or [] | ||
| 228 | + if paths: | ||
| 229 | + paths.insert(0, "--") | ||
| 230 | + | ||
| 231 | + if other is not None: | ||
| 232 | + args.insert(0, other) | ||
| 233 | + | ||
| 234 | + args.insert(0,self) | ||
| 235 | + args.extend(paths) | ||
| 236 | + | ||
| 237 | + kwargs['as_process'] = True | ||
| 238 | + proc = self.repo.git.diff(*args, **kwargs) | ||
| 239 | + | ||
| 240 | + diff_method = diff.Diff._index_from_raw_format | ||
| 241 | + if create_patch: | ||
| 242 | + diff_method = diff.Diff._index_from_patch_format(self.repo, proc.stdout) | ||
| 243 | + return diff_method(self.repo, proc.stdout) | ||
| 244 | + | ||
| 245 | + | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -11,7 +11,7 @@ | |||
| 11 | 11 | import base | |
| 12 | 12 | import utils | |
| 13 | 13 | ||
| 14 | - class Commit(base.Object, Iterable): | ||
| 14 | + class Commit(base.Object, Iterable, base.Diffable): | ||
| 15 | 15 | """ | |
| 16 | 16 | Wraps a git Commit object. | |
| 17 | 17 | ||
@@ -176,60 +176,6 @@ def iter_parents(self, paths='', **kwargs): | |||
| 176 | 176 | ||
| 177 | 177 | return self.iter_items( self.repo, self, paths, **kwargs ) | |
| 178 | 178 | ||
| 179 | - @classmethod | ||
| 180 | - def diff(cls, repo, a, b=None, paths=None): | ||
| 181 | - """ | ||
| 182 | - Creates diffs between a tree and the index or between two trees: | ||
| 183 | - | ||
| 184 | - ``repo`` | ||
| 185 | - is the Repo | ||
| 186 | - | ||
| 187 | - ``a`` | ||
| 188 | - is a named commit | ||
| 189 | - | ||
| 190 | - ``b`` | ||
| 191 | - is an optional named commit. Passing a list assumes you | ||
| 192 | - wish to omit the second named commit and limit the diff to the | ||
| 193 | - given paths. | ||
| 194 | - | ||
| 195 | - ``paths`` | ||
| 196 | - is a list of paths to limit the diff to. | ||
| 197 | - | ||
| 198 | - Returns | ||
| 199 | - git.Diff[]:: | ||
| 200 | - | ||
| 201 | - between tree and the index if only a is given | ||
| 202 | - between two trees if a and b are given and are commits | ||
| 203 | - """ | ||
| 204 | - paths = paths or [] | ||
| 205 | - | ||
| 206 | - if isinstance(b, list): | ||
| 207 | - paths = b | ||
| 208 | - b = None | ||
| 209 | - | ||
| 210 | - if paths: | ||
| 211 | - paths.insert(0, "--") | ||
| 212 | - | ||
| 213 | - if b: | ||
| 214 | - paths.insert(0, b) | ||
| 215 | - paths.insert(0, a) | ||
| 216 | - text = repo.git.diff('-M', full_index=True, *paths) | ||
| 217 | - return diff.Diff._list_from_string(repo, text) | ||
| 218 | - | ||
| 219 | - @property | ||
| 220 | - def diffs(self): | ||
| 221 | - """ | ||
| 222 | - Returns | ||
| 223 | - git.Diff[] | ||
| 224 | - Diffs between this commit and its first parent or all changes if this | ||
| 225 | - commit is the first commit and has no parent. | ||
| 226 | - """ | ||
| 227 | - if not self.parents: | ||
| 228 | - d = self.repo.git.show(self.id, '-M', full_index=True, pretty='raw') | ||
| 229 | - return diff.Diff._list_from_string(self.repo, d) | ||
| 230 | - else: | ||
| 231 | - return self.diff(self.repo, self.parents[0].id, self.id) | ||
| 232 | - | ||
| 233 | 179 | @property | |
| 234 | 180 | def stats(self): | |
| 235 | 181 | """ | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -15,7 +15,7 @@ def sha_to_hex(sha): | |||
| 15 | 15 | assert len(hexsha) == 40, "Incorrect length of sha1 string: %d" % hexsha | |
| 16 | 16 | return hexsha | |
| 17 | 17 | ||
| 18 | - class Tree(base.IndexObject): | ||
| 18 | + class Tree(base.IndexObject, base.Diffable): | ||
| 19 | 19 | """ | |
| 20 | 20 | Tress represent a ordered list of Blobs and other Trees. Hence it can be | |
| 21 | 21 | accessed like a list. | |
@@ -169,6 +169,7 @@ def _iter_recursive(cls, repo, tree, cur_depth, max_depth, predicate ): | |||
| 169 | 169 | def traverse(self, max_depth=-1, predicate = lambda i: True): | |
| 170 | 170 | """ | |
| 171 | 171 | Returns | |
| 172 | + | ||
| 172 | 173 | Iterator to traverse the tree recursively up to the given level. | |
| 173 | 174 | The iterator returns Blob and Tree objects | |
| 174 | 175 | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments