-
-
Notifications
You must be signed in to change notification settings - Fork 382
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improved support for navigating trees: #903
Conversation
Looks good! Could you fix the tests in Travis? Don't worry about AppVeyor, they're broken for a different reason. |
Been using this the last couple of days... it's much better to navigate the tree, but still a bit awkward to actually get to blobs. Before: meta_tree = repo[commit.tree['meta'].id]
features_tree = repo[meta_tree['features'].id]
info_blob = repo[features_tree['info.json'].id]
info = json.loads(info_blob.data) Now: feature_info = commit.tree / 'meta' / 'features' / 'info.json'
info = json.loads(repo[feature_info.id].data) With latest commit incorporating feature_info = commit.tree / 'meta' / 'features' / 'info.json'
info = json.loads(feature_info.blob.data) Thoughts? Submodules end up with a TreeEntry.type=commit, but I can't find a way to lookup the submodule from the oid, only from the absolute path (which we don't have in the TreeEntry, only the relative name) — so I've left that alone. |
@jdavid can you give the ref-counting/free'ing a review?
|
Good work! The ref-counting/free'ing looks correct. Just made a couple of tiny comments. About the user interface:
I think these changes would be nice for the user, and they would simplify a bit the code as well. |
These changes look fantastic! |
I considered both of these, I'll add my thoughts below. Happy to be challenged.
I like the elegance, but I can't think of an actual use-case for it? Seems like either I'd expect a blob or another tree for any particular case? "Explicit is better than implicit" and all. Commits are another type possibility wrt submodules, but I've left that for someone else when they need it.
If I'm iterating through everything in a directory then I'd always use an iterator or for/getitem. I know it makes it simpler for the implementation, but can't see how it helps the user? |
The fact that these two changes make the code simpler is a big advantage. It's difficult to stress it enough, 150+ developers have contributed changes to pygit2, and today I maintain those changes/code (and when I leave someone else will do). On the other side, the fact that we cannot imagine a use case, doesn't mean it doesn't exist, and more importantly it doesn't hurt, it's a feature superset anyway. |
@jdavid sorry, been distracted with other work. I've made both the changes you suggested. 👍 |
- `my_tree / 'path'` resolves to a TreeEntry (same as `my_tree['path']`) - If `my_tree_entry` is of type `tree`: `my_tree_entry / 'path'`, `my_tree_entry['path']`, and `my_tree_entry[0]` all resolve to another TreeEntry (same as `repo[my_tree_entry.id]['path']`) This enables `my_tree / 'path' / 'path'` navigation ala Pathlib & GitPython.
Saves doing another `repo[tree_entry.id]` lookup Tree navigation: `blob = (tree / 'path' / 'file').blob`
- drop .blob & .tree in favour of .obj - use getitem implementation for truediv: allows `T / 'a' / 0` to correspond to `T['a'][0]`
Rebased on latest master |
hmm, not so sure about that?
|
@jdavid at least one of the Windows build configs passed now 👍 Current appveyor failure looks intermittent, can you trigger a rebuild? |
Config.__init__() does not always set self._config, which can cause trouble during __del__(). This avoids seemingly spurious and not really helpful exceptions. Fixes libgit2#916
Thanks! Yes I fixed AppVeyor in master. I've re-run the incomplete jobs several times, but there're still failures. |
@jdavid aha, there's an actual compile error there now. Will figure it out somehow :) |
- `my_tree / 'path'` resolves to a TreeEntry (same as `my_tree['path']`) - If `my_tree_entry` is of type `tree`: `my_tree_entry / 'path'`, `my_tree_entry['path']`, and `my_tree_entry[0]` all resolve to another TreeEntry (same as `repo[my_tree_entry.id]['path']`) This enables `my_tree / 'path' / 'path'` navigation ala Pathlib & GitPython.
Saves doing another `repo[tree_entry.id]` lookup Tree navigation: `blob = (tree / 'path' / 'file').blob`
- drop .blob & .tree in favour of .obj - use getitem implementation for truediv: allows `T / 'a' / 0` to correspond to `T['a'][0]`
fixed in commit f0f8cc2 |
@jdavid pulled your changes into here. ✅ |
Merged thanks! I still want to give a 2nd look. Specifically this adds a reference to the repository from |
Thanks ❤️
Yeah, needs the repo reference to be able to look up the associated objects, but is a small wart implementation-wise. One alternative is to keep a reference to the parent/root tree, store one repository reference there, and access everything that way — but then TreeEntry's would need a parent reference instead: I decided the outcome wasn't much different, though it's arguably more elegant (I guess that would allow support for Right at the start I mentioned that I think ideally |
Navigating tree objects is pretty crude via Pygit2 at the moment, requiring a lot of boilerplate lookups.
This change incorporates the same
/
operator approach as Pathlib and GitPython:my_tree / 'path'
resolves to a TreeEntry (same asmy_tree['path']
currently)tree
, then:my_tree_entry / 'path'
resolves to a child TreeEntrymy_tree_entry['path']
andmy_tree_entry[0]
similarly'path' in my_tree_entry
returns a boolean.my_tree / 'path' / 'path'
navigationIdeally I'd suggest that maybe Tree should probably be a subclass of TreeEntry so it kinda magically works how the user expects, but that would require quite a few changes.