Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

tiennou
Copy link
Contributor

@tiennou tiennou commented Apr 20, 2018

While working on the submodule-in-worktree issue, I had to finagle with #4149. So let's add that to the API.

Arguably, it could be named git_submodule_add and perform all the steps by itself.

@tiennou
Copy link
Contributor Author

tiennou commented Jul 6, 2018

Now I don't know what changes you're requesting anymore 😉.

@pks-t
Copy link
Member

pks-t commented Jul 13, 2018

Sorry for my comments being confusing :P

The thing is that your function unfortunately doesn't work. The test you've written works by accident due to a bug in git_submodule_add_clone, as you clone into git_submodule_path(submodule), which returns a path relative to the parent repo. So the git_clone will in fact clone into the current working directory and not into the parent repo. What you have to do is to make git_submodule_path(submodule) an absolute path relative to the parent repo and then do the clone. This is where the next issue will surface: as the submodule directory already exists and due to a ".git" gitlink file existing inside of it, the git_clone step will error out due to the target directory not being empty.

@tiennou
Copy link
Contributor Author

tiennou commented Jul 20, 2018

Okay, I fixed the function, so yeah the test wasn't working as expected because of pathing issues (which I wasn't expecting so, good catch 😉).

There's two ways to fix : either the clone existence check is wrong, and this should be changed, or it's not, and the clone must be performed manually.

Now for the discussion part, is clone wrong ? We're using the "approved" clone_opts->repository_cb function for grabbing a user-provided repository, but the emptiness check happens first. I can think of a few workarounds :

  • trust that the user gave us something sane via the repository_cb, in that it would have called git_repository_open to be able to do that. The definition of sane in that case is fuzzy though.
  • make the empty check more precise by saying that empty allows a valid gitlink at the root of the folder, but that looks to be a deviation from git (I've checked against a manually crafted gitlink). So I'd make it a 👎.

@pks-t
Copy link
Member

pks-t commented Jul 26, 2018

I don't like the second option, it's much too specific. While I think the first option is quite nice, I don't know if we really want to relax the check like that. So, option number three:

  • create a permit-clone-into-a-populated-directory flag (defaulting to false) in git_clone_options, and if it is set we skip the check for emptiness

@tiennou tiennou force-pushed the feature/submodule-easy-clone branch from bd490b5 to 95f75e6 Compare April 4, 2019 19:47
@tiennou
Copy link
Contributor Author

tiennou commented Apr 4, 2019

I've gone a 4th way: add a private variant of git_clone with a relaxed check and use that. That restricts it to this specific function call, which is sufficient, and keep it from being exposed in the API (less API to hang you with).

Copy link
Member

@pks-t pks-t left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the update! I'm +1 on this, only got some stylistic remarks.

@tiennou tiennou force-pushed the feature/submodule-easy-clone branch 6 times, most recently from 38cc2d5 to 87f34eb Compare April 5, 2019 17:14
@tiennou
Copy link
Contributor Author

tiennou commented Apr 5, 2019

Apart from the naming question, this is good to go (my reply somehow doesn't show up from the conversation view though).

@tiennou tiennou force-pushed the feature/submodule-easy-clone branch from 87f34eb to df087eb Compare April 20, 2019 12:33
@tiennou
Copy link
Contributor Author

tiennou commented Apr 20, 2019

Rebased, I've renamed the function to git_submodule_clone, and I've moved its tests to submodule/add.c (it seemed more relevant). I hope that's fine.

*/
GIT_EXTERN(int) git_submodule_clone(
git_repository **out,
git_submodule *submodule);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To not repeat past mistakes, do we maybe want to introduce an options struct here from the get-go? Doesn't need to contain anything options for now

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I usually like having a default "do the default thing" and provide an _ext on top of that, if/when the need arises. But it feels a little premature (though only because of a lack of use cases, so if you have a definite not too difficult "this is needed" example, I'll reconsider).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm. I would very quickly want progress reporting if I were to use this in anger. I concede that this is a bit tricky. I would definitely want, eg, progress reporting but many fields should not be eligible to be set by an end-user, so taking a whole git_clone_options may not be appropriate. Additionally, we may need to do some proxy'ing with some of the callbacks to ensure that payloads are delivered correctly.

Having said that, progress reporting and cancellation still feels like table-stakes for any function that does network I/O.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I usually like having a default "do the default thing" and provide an _ext on top of that, if/when the need arises.

Well, defaults are easily attainable by just passing NULL. Personally, I'm not too happy with the _ext suffix and I see it rather as a "Okay we f'd up the first time, so let's just tack on a suffix and fix up the function".

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And yeah, fully agree with the usecases @ethomson proposes.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, yeah that's a tough decision. I can see pros and cons to simply taking a git_clone_options struct and just ignoring and overwriting parts of it (documenting this of course). Or a simpler struct and proxying that data into a git_clone_options.

The former seems like the simpler strategy for you (the implementer). What I'm not sure of is whether it's easier for users of the library, which is of course where I think the important bits are.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simply taking git_clone_options is not going to fly in case there's going to be submodule-cloning specific options at some point in time, which I'd say is not all that unlikely. So I think it should definitely be a new git_submodule_clone_options struct, but as you said it may just embed and forward (parts of) the git_clone_options struct.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've noticed that git_submodule_update_options seemed to have mostly what we needed, so I've added this as our option struct. Sorry, I forgot to rebase-ping, but IIRC it was ready to 🚢 as well.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, didn't see that, sorry.

git_submodule_update_options does look similar to what we need, that's true. I'm still a bit hesitant, though. It includes options that cannot fit the bill right now and we may need to extend the struct for either git_submodule_update or git_submodule_clone with options that are incompatible with the respective other function. If you ask me, that's trading ease of implementation (no need for an additional struct) for a confusing API. I'm more in the camp of using one struct per function whenever it's not obvious that they're always going to take the same set of opts.

Just my 2 cents -- I'm happy to be overruled here due to my recent lack of time for libgit2.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Struct for reference)

typedef struct git_submodule_update_options {
	unsigned int version;
	git_checkout_options checkout_opts;
	git_fetch_options fetch_opts;
	int allow_fetch;
} git_submodule_update_options;

Of theses, allow_fetch feels the most dubious, since we don't have any repository before the call. checkout seems fine (though I think there's a few rough edges), and fetch looks okay.

Now, I don't have that much experience with submodules, but a shared "those are the settings to obey if an update needs to happen", especially given the git submodule update --init --recursive thingie seems to be a nice thing. Writing in the docblock that allow_fetch only makes sense if the submodule is already initialized, and ignoring it if it's set seems sufficient.

@pks-t
Copy link
Member

pks-t commented Apr 26, 2019

Thanks, @tiennou! Looks good to me except for the one comment I have

@tiennou tiennou force-pushed the feature/submodule-easy-clone branch 2 times, most recently from 17ebc26 to 6669106 Compare May 1, 2019 14:17
@pks-t pks-t force-pushed the feature/submodule-easy-clone branch from 6669106 to 3c5d78b Compare October 17, 2019 11:10
@pks-t
Copy link
Member

pks-t commented Oct 17, 2019

Rebased your branch to fix conflicts.

pks-t added 3 commits October 17, 2019 13:35
The test submodule::add::homemade_clone unfortunately doesn't test
what's expected, but does instead clone the submodule to a directory
that is outside of the parent repository. Fixing this by cloning to the
correct location isn't possible, though, as `git_submodule_add_setup`
will have pre-created a ".git" file already, which will cause
`git_clone` to error out.

As it's not possible to perform the clone without fiddling around with
the repo's layout, let's just remove this test as that is in fact what
the new `git_submodule_clone` function is for.
The test submodule::add::submodule_clone doesn't use a sandbox, and thus
the created repo will not get deleted after the test has finished.
Convert the test to use the empty standard repo sandbox instead to fix
this.
Add two more tests that verify our behaviour in some edge cases, notably
when cloning into a non-empty directory and when cloning the same
submodule twice.
@pks-t
Copy link
Member

pks-t commented Oct 17, 2019

I've removed the homegrown clone test, which didn't do what one expected (the resulting submodule was cloned outside of the parent repo) and added two new tests

@pks-t pks-t merged commit 4c0dea5 into libgit2:master Oct 17, 2019
@tiennou tiennou deleted the feature/submodule-easy-clone branch October 17, 2019 22:18
@tiennou
Copy link
Contributor Author

tiennou commented Oct 17, 2019

Thanks for keeping up with this ! ✨

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants