Skip to content
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

Allow libgit2# to redirect the global/system/xdg config search path #1123

Merged
merged 1 commit into from
Sep 9, 2015

Conversation

rcorre
Copy link
Contributor

@rcorre rcorre commented Jun 26, 2015

This provides an interface for libgit2# to redirect config file lookups via libgit2's git_libgit2_opt.

This is useful for unit-testing methods that hit the global, system, or xdg config files.

It is currently possible to redirect config access using RepositoryOptions, but this only works if the functions you are testing take a Repository as an argument. This isn't much of a problem for libgit2#, but other frameworks may not want to pass a Repository all the way through their call stack to support testing with a faked config. This provides a more foolproof way to sandbox your tests as it guarantees that all config access is redirected (libgit2 uses this for testing).

The first commit adds the actual functionality. git_libgit2_opts has a number of other options -- I only added bindings for search path redirection, but this sets the stage for binding other libgit2 settings if they are needed.

The second commit shows how this could be used within libgit2# tests. The current redirection scheme can be flaky -- I noticed some tests failing because they only redirected system config access, and my personal global config was interfering.
The test could be fixed without this, of course, but I think this will help prevent mistakes in the long run.

[EDIT]
I've removed the second commit for now -- my partial fixup of the test fixtures was causing problems in as many tests as it fixed.

This PR just allows libgit2# consumers to redirect config access, I can work on a second PR to use this in the lg2# test fixtures if it seems like a good idea (started here).

@rcorre rcorre force-pushed the search-path branch 3 times, most recently from 555c275 to 3cd756e Compare June 29, 2015 18:39
internal static extern int git_libgit2_opts(int option, uint level,
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))]string name);

// Not yet implemented libgit2_opts signatures:
Copy link
Member

Choose a reason for hiding this comment

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

We could definitely change the functionality in libgit2 and this comment would get out of date. This might be frustrating to a future implementer, so I would recommend dropping these comments. Maybe we should have something alluding to the fact that there are other possible signatures that the above do not cover.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point, I guess someone wanting to implement another one of these would have checked the libgit2 docs anyways

@nulltoken
Copy link
Member

Your proposal is growing on me.

Actually, I'm starting to wonder if we shouldn't obsolete
RepositoryOptions.{[Global|Xdg|System]ConfigurationLocation} in favor of this.

Thoughts?

/cc @shiftkey @ammeep @dahlbyk

@rcorre
Copy link
Contributor Author

rcorre commented Jul 1, 2015

I have a branch here where I use this for the libgit2# tests. With that in place, I should be able to strip out all uses of ConfigurationLocation in the tests.

As a bonus, it prevents tests from accidentally writing to a user's config or taking a dependency on the test environment (e.g. failing if you don't have the right core.autocrlf setting).

@nulltoken
Copy link
Member

@rcorre 🆒

We would also have to cleanup all the tests that actually rely on those RepositoryOptions properties as well. However, before diving into this, I'd like to make sure that it's ok to set this globally and that there's no need for a temporary override of those ones.

@whoisj
Copy link

whoisj commented Jul 1, 2015

Actually, I'm starting to wonder if we shouldn't obsolete
RepositoryOptions.{[Global|Xdg|System]ConfigurationLocation} in favor of this.

Given the desire to be able to, eventually, run unit-tests in parallel this would be a bummer. It would be nice if the RepositoryOptions overrode the values still.

@nulltoken
Copy link
Member

Given the desire to be able to, eventually, run unit-tests in parallel this would be a bummer. It would be nice if the RepositoryOptions overrode the values still.

I've pondered this as well, but I think we're already doomed (filters, subtransports, ...). Besides, if the only use of those RepositoryOptions properties is to help us out with the tests, that may be interesting hint that we should deprecate them. 😉

@whoisj
Copy link

whoisj commented Jul 1, 2015

I've pondered this as well, but I think we're already doomed (filters, subtransports, ...). Besides, if the only use of those RepositoryOptions properties is to help us out with the tests, that may be interesting hint that we should deprecate them. 😉

touché

@nulltoken
Copy link
Member

@shiftkey Unkess I'm wrong, you're making use of this feature. How do you feel about @rcorre's proposal?

@shiftkey
Copy link
Contributor

@nulltoken I'm interested in this proposal.

// set a value in the first config
using (var config = Configuration.BuildFrom(null))
{
config.Set("luggage.code", 9876, ConfigurationLevel.Global);
Copy link
Member

Choose a reason for hiding this comment

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

ZOMG! You're disclosing secrets, here!!1! 😜

Copy link

Choose a reason for hiding this comment

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

Isn't that supposed to be "1-2-3-4-5?"?

I mean "That's the stupidest combination I've ever heard of in my life! That's the kinda thing an idiot would have on his luggage!"

😛

Copy link
Contributor

Choose a reason for hiding this comment

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

Shout out to obscure Mel Brooks references...

Copy link
Member

Choose a reason for hiding this comment

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

Literally that first thing that came to mind when I read that line.

@rcorre
Copy link
Contributor Author

rcorre commented Jul 17, 2015

Removed GlobalSettings.PathListSeparator in favor of Path.PathListSeparator. Thanks @Therzok!

@dahlbyk
Copy link
Member

dahlbyk commented Jul 21, 2015

What's the expected/actual behavior for GlobalSettings.SetConfigSearchPath(configLevel, "") or GlobalSettings.SetConfigSearchPaths(configLevel, Enumerable.Empty<string>())?

@rcorre
Copy link
Contributor Author

rcorre commented Jul 21, 2015

It should restore the default search path. Having trouble getting libgit2# to build right now, but I'll verify that when I can.

@rcorre
Copy link
Contributor Author

rcorre commented Jul 23, 2015

Confirmed that "" and Enumerable.Empty<string>() behave as expected (same as null).
As an aside, would overloading SetConfigSearchPath be preferable to having SetConfigSearchPath and SetConfigSearchPaths?

@dahlbyk
Copy link
Member

dahlbyk commented Jul 27, 2015

Confirmed that "" and Enumerable.Empty<string>() behave as expected (same as null).

Add tests to prove the behavior?

As an aside, would overloading SetConfigSearchPath be preferable to having SetConfigSearchPath and SetConfigSearchPaths?

I'd be fine with an overloaded SetConfigSearchPath.

@nulltoken
Copy link
Member

I'd be fine with an overloaded SetConfigSearchPath

Maybe in the plural form?

@rcorre
Copy link
Contributor Author

rcorre commented Jul 27, 2015

SetCofigSearchPaths is technically what it does, though I'd imagine setting a single path is the most common case.

@dahlbyk
Copy link
Member

dahlbyk commented Jul 28, 2015

SetCofigSearchPaths it is, then

@Therzok
Copy link
Member

Therzok commented Jul 28, 2015

Cofigs are really nice things to have.

@rcorre
Copy link
Contributor Author

rcorre commented Jul 30, 2015

Overloading for IEnumerable/string wouldn't work as null would be an ambiguous argument, so I compromised with:

SetConfigSearchPaths(ConfigurationLevel level, params string[] paths)

I noticed that libgit2 documents that the special string "$PATH" refers to the current path, so I documented and tested that too (as well as the empty string behavior).

As tempting as it was to shave another character off of the function name, I decided to keep the n in Config :p

@dahlbyk
Copy link
Member

dahlbyk commented Jul 30, 2015

Overloading for IEnumerable/string wouldn't work as null would be an ambiguous argument, so I compromised...

👍

I noticed that libgit2 documents that the special string "$PATH" refers to the current path, so I documented and tested that too (as well as the empty string behavior).

👍

As tempting as it was to shave another character off of the function name, I decided to keep the n in Config :p

👍

The Travis CI build failed

👎

@ethomson
Copy link
Member

The Travis CI build failed

I kicked it, but Travis is again having Mac Issues.

@rcorre
Copy link
Contributor Author

rcorre commented Jul 30, 2015

Thanks!

Incidentally, should LibGit2Sharp build with mono >= 4.0?
I tried to test the linux build locally, but I had to roll back mono to 3.12

@dahlbyk
Copy link
Member

dahlbyk commented Aug 7, 2015

Incidentally, should LibGit2Sharp build with mono >= 4.0?

@nulltoken @Therzok?

@Therzok
Copy link
Member

Therzok commented Aug 8, 2015

This should make it build? #1034

@shiftkey
Copy link
Contributor

Apologies if I mess up something here, I've not kept up with this PR as it's evolved over time...

Do you think we would indeed need both an app-domain level and a per repository override?

I guess I'm not clear on the scenario where a "per repository" override would be needed. I'm trying to think of a scenario in the past where I've come across this, but coming up empty.

👍 with the direction this is heading in - will definitely help with testing on my end...

@rcorre
Copy link
Contributor Author

rcorre commented Aug 26, 2015

Another thing I've been looking into is libgit2's config_backend. If custom config backends were supported in libgit2#, could that replace the RepositoryOptions config path override?

Setting it up might be a bit more involved than using RepositoryOptions, but it could be much more flexible (i.e. faking configs in memory).

@jamill
Copy link
Member

jamill commented Aug 26, 2015

The more compelling case to me is the plug-in model..

I think this is the interesting use case - a setup where multiple components depend on the same LG2S, and the individual components do not want to affect each other.

@ethomson
Copy link
Member

The more compelling case to me is the plug-in model, e.g. the GitHub VS extension may want to load in config for its credential store without impacting anything else that depends on the bundled LG2S.

Nobody should be using the Visual Studio bundled in Visual Studio except people internal to Visual Studio. (I'm including the GitHub VS extension in this, since they're shipping in our box but note that as soon as 2015 was RTM'd, they are now using their own LibGit2Sharp.)

I realize that you may be using this as an example of a plug-in model type system. I don't think that LibGit2Sharp can predict this sort of behavior and that if Visual Studio (to continue this example) were to offer consumers the ability to work with its LibGit2Sharp instance then there needs to be a contract between consumers and the provider about what can be called. I don't think LibGit2Sharp can really be good at predicting what this/these things should look like.

@ethomson
Copy link
Member

Anyway. I'm 👍 on this change and on pluggable configuration backends. That's something various people have wanted for a while but it has not bubbled up very high on my priority list.

Assert.Equal(xdgPath, GlobalSettings.GetConfigSearchPaths(ConfigurationLevel.Xdg).Single());

// reset the search paths to their defaults
GlobalSettings.SetConfigSearchPaths(ConfigurationLevel.Global, null);
Copy link
Member

Choose a reason for hiding this comment

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

Do we want to try and always run the code that reset's the search paths to their defaults (via try / finally), to try and prevent possibly polluting other tests? Although, if there is a bug in logic for setting the global search paths, then maybe the rest logic would also not work anways...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, probably a good idea. As you point out, this test is a bit weird -- if the logic is flawed, the whole setup/teardown process is bugged.

Copy link
Member

Choose a reason for hiding this comment

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

I'm generally opposed to asserts in setup/teardown, but this might be a case where we want to capture global config state at the fixture level, and then restore (and assert restoration) on teardown. If any of that fails, we're probably not going to trust these config tests anyway.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Right now its only being used in the tests I added, the other ConfigurationFixture tests, still rely on the old redirection method (RepositoryOptions set up through a BuildFakeConfigs test method).

I could use this redirection for all the config tests (and potentially all tests in the library), but I think that's a whole different PR :)

@jamill
Copy link
Member

jamill commented Aug 26, 2015

Thanks @rcorre - I think this looks good!

@rcorre
Copy link
Contributor Author

rcorre commented Aug 26, 2015

This fell pretty far behind, so I've rebased back up to vNext (and added a comment about Cdecl).

@rcorre
Copy link
Contributor Author

rcorre commented Sep 8, 2015

Anything preventing this from going through at this point?

As far as whether to deprecate RepositoryOptions.{[Global|Xdg|System]ConfigurationLocation}:

  1. That decision could be made separately from this PR
  2. I am partway through implementing config_backend support, which could truly replace it.

@nulltoken
Copy link
Member

@rcorre Let's do this. Could you please squash this PR into a single commit so we can merge it?

Allow getting/setting the global/system/XDG config search path using
Configuration.GetSearchPath Configuration.SetSearchPath.

This is useful for libgit2sharp consumers who are writing unit tests that want
to 'fake' a global config.

While the config search path can be changed using the RepositoryOptions, this
requires that every function you test would need to accept a config path
argument. Changing the search path at the library level ensures that all config
access is redirected.

This is how the libgit2 config tests work; see the initialization of
tests/config/global.c for an example.
@rcorre
Copy link
Contributor Author

rcorre commented Sep 9, 2015

@nulltoken: squashed and ready to go

@Therzok
Copy link
Member

Therzok commented Sep 9, 2015

I am sad Cofigs are no longer an option. :(

@nulltoken
Copy link
Member

@nulltoken: squashed and ready to go

@rcorre ❤️ Let's merge it. Awesome job!

I am sad Configs are no longer an option. :(

@Therzok I'm going to open an issue discussing the potential deprecation of those

nulltoken added a commit that referenced this pull request Sep 9, 2015
Allow libgit2# to redirect the global/system/xdg config search path
@nulltoken nulltoken merged commit 8688f10 into libgit2:vNext Sep 9, 2015
@nulltoken nulltoken added this to the v0.22 milestone Sep 9, 2015
@rcorre rcorre deleted the search-path branch September 10, 2015 01:20
@Therzok
Copy link
Member

Therzok commented Sep 10, 2015

@nulltoken you do realise I actually meant to type Cofigs, right? And my sadness is coming from the lack of typo in the final naming.

#1123 (comment)

@nulltoken
Copy link
Member

@Therzok 😨 AAAaaaaaahhhhh! ... Nope. I didn't. Thanks for being on the lookout ❤️

@rcorre How would you feel about a tiny PR to fix this up? 🙏

@nulltoken
Copy link
Member

@rcorre How would you feel about a tiny PR to fix this up? 🙏

:trollface: of course 😉

@rcorre
Copy link
Contributor Author

rcorre commented Sep 10, 2015

It is one letter shorter...
Think of all the collective developer time we could save!

@nulltoken
Copy link
Member

It is one letter shorter...
Think of all the collective developer time we could save!

Dammit! You're right.

There are indeed a finite number of keystrokes left in developers'hands before they die.

image

Help us @shanselman you're our only hope!

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.

None yet

9 participants