Merge lp:~thomir-deactivatedaccount/bzr/add-global-config into lp:bzr
- add-global-config
- Merge into bzr.dev
Status: | Work in progress |
---|---|
Proposed branch: | lp:~thomir-deactivatedaccount/bzr/add-global-config |
Merge into: | lp:bzr |
Diff against target: |
342 lines (+112/-27) 4 files modified
bzrlib/config.py (+46/-13) bzrlib/tests/test_config.py (+22/-6) bzrlib/tests/test_win32utils.py (+17/-1) bzrlib/win32utils.py (+27/-7) |
To merge this branch: | bzr merge lp:~thomir-deactivatedaccount/bzr/add-global-config |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Vincent Ladeuil | Needs Fixing | ||
Jelmer Vernooij (community) | Approve | ||
Review via email: mp+69592@code.launchpad.net |
Commit message
Description of the change
Code not finished yet - working on making a system-wide config file (/etc/bazaar/
- 6048. By Thomi Richards
-
Fixed docstring for config.
system_ config_ dir
Matthew Fuller (fullermd) wrote : | # |
> (/etc/bazaar/
On BSD, there's going to be a strong preference for /usr/local/etc/.
This probably calls for it being settable somehow in the install
process at least...
Thomi Richards (thomir-deactivatedaccount) wrote : | # |
> On BSD, there's going to be a strong preference for /usr/local/etc/.
> This probably calls for it being settable somehow in the install
> process at least...
Okay, that's fine. What's the best way to do this?
Martin Pool (mbp) wrote : | # |
On 29 July 2011 04:52, Matthew Fuller <email address hidden> wrote:
>> (/etc/bazaar/
>
> On BSD, there's going to be a strong preference for /usr/local/etc/.
> This probably calls for it being settable somehow in the install
> process at least...
If you use distutils.sysconfig or similar, it should use whatever
prefix Python was compiled with.
- 6049. By Thomi Richards
-
Added unit tests for new method in win32utils.py
- 6050. By Thomi Richards
-
Added unit tests to test the new path functions for win32 and freebsd.
Martin Pool (mbp) wrote : | # |
Thanks for this, Thomi.
+ elif sys.platform.
+ return osutils.
+ else:
+ return osutils.
Ideally we would get the whole path to '...etc' from Python, rather than special-casing on the platform.
But I don't actually see anything that points to /etc in sysconfig.
The docstring also needs to be updated.
Thomi Richards (thomir-deactivatedaccount) wrote : | # |
Hi Martin,
Thanks for your feedback - I'll update the docstring and try and find some programmatic way to get the /etc/ path.
I also need to work out if my unit tests pass under Windows. Is there a CI server that can run these tests for me?
Martin Pool (mbp) wrote : | # |
+class SystemGlobalSto
+
+ def __init__(self, possible_
+ t = transport.
+ possible_
+ super(SystemGlo
The point of passing possible_transports is basically so that we can reuse some connection objects, and that's mostly important for remote transports, which this won't be at present. I think the current approach of manually passing it down is not working very well and we should probably look at putting it into the library state instead.
[tweak] However, for this patch, I don't think it's either used or particularly useful (since making new local transports is cheap), so you could just remove the parameter.
[suggestion] I'm not a big fan of creating new classes that only have different initial state, not different behaviour, so I would probably just make this a factory method.
Aside from that, this looks great. It could be good to get a review from vila too.
Martin Pool (mbp) wrote : | # |
On 2 August 2011 12:51, Thomi Richards <email address hidden> wrote:
> Hi Martin,
>
> Thanks for your feedback - I'll update the docstring and try and find some programmatic way to get the /etc/ path.
>
> I also need to work out if my unit tests pass under Windows. Is there a CI server that can run these tests for me?
There is Babune <http://
any post-landing regressions, but I don't think it is yet able to test
arbitrary unlanded branches.
I have Wine, Python installed under that, and then just a script
'winepython' that does
exec wine ~/.wine/
and then I can say 'winepython ./bzr selftest config' etc.
Thomi Richards (thomir-deactivatedaccount) wrote : | # |
> +class SystemGlobalSto
> +
> + def __init__(self, possible_
> + t = transport.
> + possible_
> + super(SystemGlo
>
> The point of passing possible_transports is basically so that we can reuse
> some connection objects, and that's mostly important for remote transports,
> which this won't be at present. I think the current approach of manually
> passing it down is not working very well and we should probably look at
> putting it into the library state instead.
>
> [tweak] However, for this patch, I don't think it's either used or
> particularly useful (since making new local transports is cheap), so you could
> just remove the parameter.
That sounds sensible. In fact, there's not a single place inside all of bzrlib where a transport is passed in. I've taken the liberty of removing that parameter from all the Store classes. If that was the wrong thing to do, please let me know.
>
> [suggestion] I'm not a big fan of creating new classes that only have
> different initial state, not different behaviour, so I would probably just
> make this a factory method.
>
That also sounds sensible. Since the Stores are an internal API (we want people to be using the Stack classes, right?), I guess I should follow naming convention and call these "_get_global_store" etc?
Also, I've renamed the GlobalStore to UserStore, and the "SystemGlobalStore" to just "GlobalStore", except that after the change above none of these will be visible, since they'll all come out of factory functions.
BranchStore is a bit more difficult, as it uses the branch lock for locking. I could keep the BranchStore class as-is, or I could wrap that up inside a factory function as well, which would make everything look a lot neater, but I'm not sure what your coding standards are regarding nested classes....
Finally, the win32utils unit tests fail, so I have some work to do there...
- 6051. By Thomi Richards
-
Several changes to clean up global config work:
* Store classes (GlobalStore et al) are now factory functions.
* What was previously called a "Global store" is now called a "User Store".
* similarly, what was the "System Global Store" is now just the "Global Store" - 6052. By Thomi Richards
-
Forgot to update docstring for system_config_dir()
- 6053. By Thomi Richards
-
Windows version 6 (WIndows 7, Server 2008) puts the common app data folder in a different place. Updated docstrings and fixed unit test.
Thomi Richards (thomir-deactivatedaccount) wrote : | # |
Unit tests now pass on Windows 7. I don't have access to anything older. However, it's a little inconvenient that the common appdata folder changes between windows versions. Perhaps a viable alternative would be to put the global app config file in the bzr installation directory under windows?
I'm not sure how that would work with non-standalone installations...
Martin Pool (mbp) wrote : | # |
> That also sounds sensible. Since the Stores are an internal API (we want people to be using the Stack classes, right?), I guess I should follow naming convention and call these "_get_global_store" etc?
>
> Also, I've renamed the GlobalStore to UserStore, and the "SystemGlobalStore" to just "GlobalStore", except that after the change above none of these will be visible, since they'll all come out of factory functions.
>
> BranchStore is a bit more difficult, as it uses the branch lock for locking. I could keep the BranchStore class as-is, or I could wrap that up inside a factory function as well, which would make everything look a lot neater, but I'm not sure what your coding standards are regarding nested classes....
>
> Finally, the win32utils unit tests fail, so I have some work to do there...
On naming:
We definitely shouldn't change the meaning of an existing name like
GlobalStore, even if it's not intended to be exposed. It's much
better for out-of-date code to get eg a NameError than to run the
wrong thing.
If the class really has actually different behaviour, like
BranchStore, it deserves to be a real different class. But if it's
basically the same class just with different constructor parameters, I
wonder if it's worthwhile. Perhaps for simplicity it is better just
to leave them all as classes. I may be getting a bit bikesheddy here
so don't block on it.
m
Thomi Richards (thomir-deactivatedaccount) wrote : | # |
Hi Michael,
I'd like to get this right, so I'll probably bug you later this evening if I get time...
> On naming:
>
> We definitely shouldn't change the meaning of an existing name like
> GlobalStore, even if it's not intended to be exposed. It's much
> better for out-of-date code to get eg a NameError than to run the
> wrong thing.
>
The branch as it currently stands will give you that behavior. Nobody should be creating the Store classes directly (nobody is within bzrlib, I don't know about external projects), and now if they try they'll get a NameError.
> If the class really has actually different behaviour, like
> BranchStore, it deserves to be a real different class. But if it's
> basically the same class just with different constructor parameters, I
> wonder if it's worthwhile.
So how about this, for the branch store: replace the BranchStore class with:
def _get_branch_
class BranchStore(
# otherstuff in here from BranchStore class
return BranchStore(branch)
This has the advantage that: A) it keeps it inline with the other factory functions. B) it hides the different implementation of the BranchStore class, and marks the BranchStore object as being a private thing that other code shouldn't use.
> Perhaps for simplicity it is better just
> to leave them all as classes. I may be getting a bit bikesheddy here
> so don't block on it.
>
Well, I'd like to get it right - I'm preparing to do some more things with sloecode & Bazaar, so learning the bzr code is helpful to me.
What do you think?
- 6054. By Thomi Richards
-
Hid BranchStore class behind _get_branch_store() factory function.
Vincent Ladeuil (vila) wrote : | # |
Thanks for working on this !
Did you read http://
> Things I know still need to be done:
> 1) to consider: rename GlobalStore to UserStore, and SystemGlobalStore to
> GlobalStore. no one outside bzrlib.config and associated unit tests use this
> class directly, so the rename should be trivial.
Two remarks:
1 - No one use them because these classes are there to help the transition to stack based configs which is not finished yet.
2 - GlobalStore is targeted at bazaar.conf, UserStore will probably use user.conf and SystemStore may use /etc/bazaar.conf or whatever we decide.
I didn't introduce the system-wide config file because I wanted to minimize the migration issues (section names, section matching, etc), see the Compatibility section in the URL above.
>
> 2) Test new windows path function.
>
> 3) System-wide config file path for Mac OS X? Haven't found any portable way
> to work out where this should go. Do macs have /etc/?
Vincent Ladeuil (vila) wrote : | # |
>
> > Perhaps for simplicity it is better just
> > to leave them all as classes. I may be getting a bit bikesheddy here
> > so don't block on it.
+1 on leaving them as classes. I think the plan is to use a registry rather than factory methods which is also why I made all the classes use transports whether they were using local files or not.
Thomi Richards (thomir-deactivatedaccount) wrote : | # |
Hi Vincent,
On 5 August 2011 04:13, Vincent Ladeuil <email address hidden> wrote:
>
> +1 on leaving them as classes. I think the plan is to use a registry rather than factory methods which is also why I made all the classes use transports whether they were using local files or not.
>
I'll revert them back to classes, and re-instate the
possible_transports parameter.
--
Thomi Richards
Thomi Richards (thomir-deactivatedaccount) wrote : | # |
Hi Vincent,
On 5 August 2011 04:09, Vincent Ladeuil <email address hidden> wrote:
> Did you read http://
No, I didn't see that. It certainly clears up a lot of questions I had ;)
> 2 - GlobalStore is targeted at bazaar.conf, UserStore will probably use user.conf and SystemStore may use /etc/bazaar.conf or whatever we decide.
...just to be clear, GlobarStore looks at ~/.bazaar/
what does UserStore do?
Cheers,
--
Thomi Richards
- 6055. By Thomi Richards
-
Reverted changes after feedback from Vila.
Thomi Richards (thomir-deactivatedaccount) wrote : | # |
Hi,
After reading your devnotes it's all a lot clearer.
I think the branch now contains everything as it should be. I'm happy to keep tweaking things, if you can see something that's not quite correct.
Cheers,
Vincent Ladeuil (vila) wrote : | # |
> No, I didn't see that. It certainly clears up a lot of questions I had ;)
Cool.
>
> > 2 - GlobalStore is targeted at bazaar.conf, UserStore will probably use
> user.conf and SystemStore may use /etc/bazaar.conf or whatever we decide.
>
> ...just to be clear, GlobarStore looks at ~/.bazaar/
Yes and is currently defined to accept the [DEFAULT] section and any arbitrary ones used by various plugins and provides no way to match section names as paths.
> So
> what does UserStore do?
UserStore is planned to be associated with ~/.bazaar/user.conf (or defaults.conf) and allows section names to be matched against paths.
Going from one to the other will require some migration path.
Martin Pool (mbp) wrote : | # |
That hack for /etc is a bit icky, but (modulo just matching all bsds, which I will tweak) I can't think of a cleaner way, and we shouldn't block on it. If someone comes up with a better api or complains that on some other systems it ought to be elsewhere, we can tweak it.
Martin Pool (mbp) wrote : | # |
So I'm just trying to test this interactively, and it's not obviously hooking in to the things I might like to configure, such as locks.steal_dead, debug_flags, 'config --scope global' etc. Perhaps we should merge it and hook it up later? I would be reluctant to actually document this as a new feature until it's at least mostly working.
Thomi Richards (thomir-deactivatedaccount) wrote : | # |
> So I'm just trying to test this interactively, and it's not obviously hooking
> in to the things I might like to configure, such as locks.steal_dead,
> debug_flags, 'config --scope global' etc. Perhaps we should merge it and hook
> it up later? I would be reluctant to actually document this as a new feature
> until it's at least mostly working.
The last time I checked the only config option that used the new stack-based API was the "editor" option.
Unfortunately I've been busy with work & real life, but I intend to get back to this at some point in the future. However, I'm not totally clear on what the future direction is, so if you're happy with the code as-is, the best option might be to merge and work from there.
Cheers,
Jelmer Vernooij (jelmer) wrote : | # |
I'd be interested to hear how this fits in with Vincent's current plans for config, but other than that I think we should just land it.
It seems reasonable enough in general, and we can always tweak it further.
Vincent Ladeuil (vila) wrote : | # |
Roughly speaking (summarising my previous remarks here): it's a bit early to land as is.
It introduces one more config file that will be accessed for each option query (http://
It introduces a new file with a semantic which is not the one we want (regarding section filtering/ordering http://
It doesn't address the defaults/overrides distinction we want to add there (which will require two distinct files, adding another queried config file for each option)
The rest seems fine, in particular:
We need to have platform specific paths for the system-wide config file.
We need to add this system-wide file at the right place in the stack definitions.
The new store *is* hooked in the right places but since this mp is based on an old trunk version, this can observed only for already migrated options. As such, we can't even measure its impact with -Econfig_stats.
So I'd say, either we land the path handling stuff only or we wait for the bugs mentioned above to be fixed before reconsidering this mp.
Martin Pool (mbp) wrote : | # |
I'd really like to get this feature in, and to not have this work stalled.
Vincent's away at the moment, but what do you think, Thomi, do you want to have a go at those changes suggested by Vincent or should someone pick it up?
> It introduces one more config file that will be accessed for each option query (http://
That bug's important to fix, but I don't think it needs to strictly serialize landing this. Reading a global file will make the penalty for multiple lookups linearly worse, but hopefully it doesn't block it entirely.
> It introduces a new file with a semantic which is not the one we want (regarding section filtering/ordering http://
Right, but again it doesn't seem wrong so much as just not yet fixing things we'd like to fix in existing files.
> It doesn't address the defaults/overrides distinction we want to add there (which will require two distinct files, adding another queried config file for each option)
I'm not sure I understand that. Is this to say you want one global configuration that is a low priority, and another that overrides everything else?
Thomi Richards (thomir-deactivatedaccount) wrote : | # |
Hi Martin,
On 14 October 2011 20:03, Martin Pool <email address hidden> wrote:
> I'd really like to get this feature in, and to not have this work stalled.
>
> Vincent's away at the moment, but what do you think, Thomi, do you want to
> have a go at those changes suggested by Vincent or should someone pick it
> up?
>
>
My day-job is getting pretty busy this time of year (just a few weeks until
the end of semester), but I'll see what I can do. The biggest issue stopping
this work going ahead right now is that I don't have a clear idea of what
needs to happen to get it merged. I don't understand the desired config file
semantic, and that seems like a separate piece of work to me.
If you know what needs to be done, please let me know and I'll try and find
an evening or two in which to clean up the code.
Cheers,
--
Thomi Richards
Martin Packman (gz) wrote : | # |
I think underlying config changes that are confusing the status of this proposal are gradually getting resolved. For now though, I'm going to move this off the review queue, but will poke Vincent later to make sure we know what else we need before global configs can move forward.
Vincent Ladeuil (vila) wrote : | # |
For the record, I've proposed https:/
Unmerged revisions
- 6055. By Thomi Richards
-
Reverted changes after feedback from Vila.
- 6054. By Thomi Richards
-
Hid BranchStore class behind _get_branch_store() factory function.
- 6053. By Thomi Richards
-
Windows version 6 (WIndows 7, Server 2008) puts the common app data folder in a different place. Updated docstrings and fixed unit test.
- 6052. By Thomi Richards
-
Forgot to update docstring for system_config_dir()
- 6051. By Thomi Richards
-
Several changes to clean up global config work:
* Store classes (GlobalStore et al) are now factory functions.
* What was previously called a "Global store" is now called a "User Store".
* similarly, what was the "System Global Store" is now just the "Global Store" - 6050. By Thomi Richards
-
Added unit tests to test the new path functions for win32 and freebsd.
- 6049. By Thomi Richards
-
Added unit tests for new method in win32utils.py
- 6048. By Thomi Richards
-
Fixed docstring for config.
system_ config_ dir - 6047. By Thomi Richards
-
LocationStack and BranchStack now use system global store as well.
- 6046. By Thomi Richards
-
First pass attempt at global config file implementation.
Preview Diff
1 | === modified file 'bzrlib/config.py' |
2 | --- bzrlib/config.py 2011-08-02 01:10:27 +0000 |
3 | +++ bzrlib/config.py 2011-08-05 04:17:29 +0000 |
4 | @@ -55,7 +55,7 @@ |
5 | turns on create_signatures. |
6 | create_signatures - this option controls whether bzr will always create |
7 | gpg signatures or not on commits. There is an unused |
8 | - option which in future is expected to work if |
9 | + option which in future is expected to work if |
10 | branch settings require signatures. |
11 | log_format - this option sets the default log format. Possible values are |
12 | long, short, line, or a plugin can register new formats. |
13 | @@ -72,6 +72,7 @@ |
14 | up=pull |
15 | """ |
16 | |
17 | +from distutils import sysconfig |
18 | import os |
19 | import string |
20 | import sys |
21 | @@ -452,7 +453,7 @@ |
22 | return None |
23 | |
24 | def acceptable_keys(self): |
25 | - """Comma separated list of key patterns acceptable to |
26 | + """Comma separated list of key patterns acceptable to |
27 | verify-signatures command""" |
28 | result = self._acceptable_keys() |
29 | return result |
30 | @@ -1533,6 +1534,26 @@ |
31 | base = os.path.expanduser("~") |
32 | return osutils.pathjoin(base, ".bazaar") |
33 | |
34 | +def system_config_dir(): |
35 | + """Return system-wide configuration directory. |
36 | + |
37 | + By default this is %ALLUSERSAPPDATA%/bazaar/2.0 on Windows, /etc/bazaar |
38 | + on Mac OS X and Linux, and {PREFIX}/etc/bazaar on BSD, where "{PREFIX}" is |
39 | + the path prefix python was installed with (usually "/usr/local"). |
40 | + """ |
41 | + if sys.platform == 'win32': |
42 | + # environ variables on Windows are in user encoding/mbcs. So decode |
43 | + # before using one |
44 | + base = win32utils.get_system_appdata_location() |
45 | + if base is None: |
46 | + raise errors.BzrError('Could not determine system-wide application' |
47 | + 'data directory. Do you have ALLUSERSAPPDATA' |
48 | + 'set?') |
49 | + return osutils.pathjoin(base, 'bazaar', '2.0') |
50 | + elif sys.platform.startswith('freebsd'): |
51 | + return osutils.pathjoin(sysconfig.PREFIX, 'etc', 'bazaar') |
52 | + else: |
53 | + return osutils.pathjoin('/etc', "bazaar") |
54 | |
55 | def config_filename(): |
56 | """Return per-user configuration ini file filename.""" |
57 | @@ -1608,11 +1629,11 @@ |
58 | |
59 | Only used when none is set in the environment or the id file. |
60 | |
61 | - This only returns an email address if we can be fairly sure the |
62 | + This only returns an email address if we can be fairly sure the |
63 | address is reasonable, ie if /etc/mailname is set on unix. |
64 | |
65 | - This doesn't use the FQDN as the default domain because that may be |
66 | - slow, and it doesn't use the hostname alone because that's not normally |
67 | + This doesn't use the FQDN as the default domain because that may be |
68 | + slow, and it doesn't use the hostname alone because that's not normally |
69 | a reasonable address. |
70 | """ |
71 | if sys.platform == 'win32': |
72 | @@ -1794,7 +1815,7 @@ |
73 | :param user: login (optional) |
74 | |
75 | :param path: the absolute path on the server (optional) |
76 | - |
77 | + |
78 | :param realm: the http authentication realm (optional) |
79 | |
80 | :return: A dict containing the matching credentials or None. |
81 | @@ -1938,7 +1959,7 @@ |
82 | |
83 | :param path: the absolute path on the server (optional) |
84 | |
85 | - :param ask: Ask the user if there is no explicitly configured username |
86 | + :param ask: Ask the user if there is no explicitly configured username |
87 | (optional) |
88 | |
89 | :param default: The username returned if none is defined (optional). |
90 | @@ -2074,7 +2095,7 @@ |
91 | :param override_existing: Raise KeyErorr if False and something has |
92 | already been registered for that key. If True, ignore if there |
93 | is an existing key (always register the new value). |
94 | - :param fallback: Whether this credential store should be |
95 | + :param fallback: Whether this credential store should be |
96 | used as fallback. |
97 | """ |
98 | return super(CredentialStoreRegistry, |
99 | @@ -2094,7 +2115,7 @@ |
100 | :param override_existing: If True, replace the existing object |
101 | with the new one. If False, if there is already something |
102 | registered with the same key, raise a KeyError |
103 | - :param fallback: Whether this credential store should be |
104 | + :param fallback: Whether this credential store should be |
105 | used as fallback. |
106 | """ |
107 | return super(CredentialStoreRegistry, self).register_lazy( |
108 | @@ -2575,6 +2596,12 @@ |
109 | possible_transports=possible_transports) |
110 | super(GlobalStore, self).__init__(t, 'bazaar.conf') |
111 | |
112 | +class SystemGlobalStore(LockableIniFileStore): |
113 | + |
114 | + def __init__(self, possible_transports=None): |
115 | + t = transport.get_transport_from_path(system_config_dir(), |
116 | + possible_transports=possible_transports) |
117 | + super(SystemGlobalStore, self).__init__(t, 'bazaar.conf') |
118 | |
119 | class LocationStore(LockableIniFileStore): |
120 | |
121 | @@ -2822,9 +2849,11 @@ |
122 | class GlobalStack(_CompatibleStack): |
123 | |
124 | def __init__(self): |
125 | - # Get a GlobalStore |
126 | + # Get a GlobalStore and a system-wide global store: |
127 | gstore = GlobalStore() |
128 | - super(GlobalStack, self).__init__([gstore.get_sections], gstore) |
129 | + swgstore = SystemGlobalStore() |
130 | + super(GlobalStack, self)\ |
131 | + .__init__([gstore.get_sections, swgstore.get_sections], gstore) |
132 | |
133 | |
134 | class LocationStack(_CompatibleStack): |
135 | @@ -2836,8 +2865,10 @@ |
136 | lstore = LocationStore() |
137 | matcher = LocationMatcher(lstore, location) |
138 | gstore = GlobalStore() |
139 | + swgstore = SystemGlobalStore() |
140 | super(LocationStack, self).__init__( |
141 | - [matcher.get_sections, gstore.get_sections], lstore) |
142 | + [matcher.get_sections, gstore.get_sections, swgstore.get_sections], |
143 | + lstore) |
144 | |
145 | class BranchStack(_CompatibleStack): |
146 | |
147 | @@ -2846,8 +2877,10 @@ |
148 | lstore = LocationStore() |
149 | matcher = LocationMatcher(lstore, branch.base) |
150 | gstore = GlobalStore() |
151 | + swgstore = SystemGlobalStore() |
152 | super(BranchStack, self).__init__( |
153 | - [matcher.get_sections, bstore.get_sections, gstore.get_sections], |
154 | + [matcher.get_sections, bstore.get_sections, gstore.get_sections, |
155 | + swgstore.get_sections], |
156 | bstore) |
157 | self.branch = branch |
158 | |
159 | |
160 | === modified file 'bzrlib/tests/test_config.py' |
161 | --- bzrlib/tests/test_config.py 2011-07-11 10:53:46 +0000 |
162 | +++ bzrlib/tests/test_config.py 2011-08-05 04:17:29 +0000 |
163 | @@ -17,6 +17,7 @@ |
164 | """Tests for finding and reading the bzr config file[s].""" |
165 | # import system imports here |
166 | from cStringIO import StringIO |
167 | +from distutils import sysconfig |
168 | import os |
169 | import sys |
170 | import threading |
171 | @@ -545,8 +546,20 @@ |
172 | 'BZR_HOME', r'C:\Documents and Settings\bogus\Application Data') |
173 | self.bzr_home = \ |
174 | 'C:/Documents and Settings/bogus/Application Data/bazaar/2.0' |
175 | + # Windows ver 6 (Windows 7, Server 2008) uses a different location |
176 | + # from earlier versions: |
177 | + if sys.getwindowsversion().major == 6: |
178 | + self.sys_config_dir = r'C:/ProgramData/bazaar/2.0' |
179 | + else: |
180 | + self.sys_config_dir = \ |
181 | + r'C:/Documents and Settings/All Users/Application Data' |
182 | else: |
183 | self.bzr_home = '/home/bogus/.bazaar' |
184 | + if sys.platform.startswith('freebsd'): |
185 | + self.sys_config_dir = osutils.pathjoin(sysconfig.PREFIX, 'etc', |
186 | + 'bazaar') |
187 | + else: |
188 | + self.sys_config_dir = '/etc/bazaar' |
189 | |
190 | def test_config_dir(self): |
191 | self.assertEqual(config.config_dir(), self.bzr_home) |
192 | @@ -567,6 +580,9 @@ |
193 | self.assertEqual(config.xdg_cache_dir(), |
194 | '/home/bogus/.cache') |
195 | |
196 | + def test_sys_config_dir(self): |
197 | + self.assertEqual(config.system_config_dir(), self.sys_config_dir) |
198 | + |
199 | |
200 | class TestXDGConfigDir(tests.TestCaseInTempDir): |
201 | # must be in temp dir because config tests for the existence of the bazaar |
202 | @@ -3175,7 +3191,7 @@ |
203 | conf = config.AuthenticationConfig(_file=StringIO( |
204 | 'foo = bar\xff')) |
205 | self.assertRaises(errors.ConfigContentError, conf._get_config) |
206 | - |
207 | + |
208 | def test_missing_auth_section_header(self): |
209 | conf = config.AuthenticationConfig(_file=StringIO('foo = bar')) |
210 | self.assertRaises(ValueError, conf.get_credentials, 'ftp', 'foo.net') |
211 | @@ -3371,8 +3387,8 @@ |
212 | port=99, path='/foo', |
213 | realm='realm') |
214 | CREDENTIALS = {'name': 'name', 'user': 'user', 'password': 'password', |
215 | - 'verify_certificates': False, 'scheme': 'scheme', |
216 | - 'host': 'host', 'port': 99, 'path': '/foo', |
217 | + 'verify_certificates': False, 'scheme': 'scheme', |
218 | + 'host': 'host', 'port': 99, 'path': '/foo', |
219 | 'realm': 'realm'} |
220 | self.assertEqual(CREDENTIALS, credentials) |
221 | credentials_from_disk = config.AuthenticationConfig().get_credentials( |
222 | @@ -3386,8 +3402,8 @@ |
223 | self.assertIs(None, conf._get_config().get('name')) |
224 | credentials = conf.get_credentials(host='host', scheme='scheme') |
225 | CREDENTIALS = {'name': 'name2', 'user': 'user2', 'password': |
226 | - 'password', 'verify_certificates': True, |
227 | - 'scheme': 'scheme', 'host': 'host', 'port': None, |
228 | + 'password', 'verify_certificates': True, |
229 | + 'scheme': 'scheme', 'host': 'host', 'port': None, |
230 | 'path': None, 'realm': None} |
231 | self.assertEqual(CREDENTIALS, credentials) |
232 | |
233 | @@ -3662,7 +3678,7 @@ |
234 | |
235 | def test_auto_user_id(self): |
236 | """Automatic inference of user name. |
237 | - |
238 | + |
239 | This is a bit hard to test in an isolated way, because it depends on |
240 | system functions that go direct to /etc or perhaps somewhere else. |
241 | But it's reasonable to say that on Unix, with an /etc/mailname, we ought |
242 | |
243 | === modified file 'bzrlib/tests/test_win32utils.py' |
244 | --- bzrlib/tests/test_win32utils.py 2011-06-14 01:26:41 +0000 |
245 | +++ bzrlib/tests/test_win32utils.py 2011-08-05 04:17:29 +0000 |
246 | @@ -38,7 +38,7 @@ |
247 | Win32RegistryFeature = features.ModuleAvailableFeature('_winreg') |
248 | CtypesFeature = features.ModuleAvailableFeature('ctypes') |
249 | Win32comShellFeature = features.ModuleAvailableFeature('win32com.shell') |
250 | -Win32ApiFeature = features.ModuleAvailableFeature('win32api') |
251 | +Win32ApiFeature = features.ModuleAvailableFeature('win32api') |
252 | |
253 | |
254 | # Tests |
255 | @@ -231,6 +231,22 @@ |
256 | encoding = osutils.get_user_encoding() |
257 | self.assertPathsEqual(lad, env.decode(encoding)) |
258 | |
259 | + def test_system_appdata_not_using_environment(self): |
260 | + # Test that we aren't falling back to the environment |
261 | + first = win32utils.get_system_appdata_location() |
262 | + self.overrideEnv("ALLUSERSAPPDATA", None) |
263 | + self.assertPathsEqual(first, win32utils.get_system_appdata_location()) |
264 | + |
265 | + def test_system_appdata_matches_environment(self): |
266 | + # ALLUSERSAPPDATA typically only exists on Vista, so we only attempt to |
267 | + # compare when it exists. |
268 | + auad = win32utils.get_system_appdata_location() |
269 | + env = os.environ.get("ALLUSERSAPPDATA") |
270 | + if env: |
271 | + # XXX - See bug 262874, which asserts the correct encoding is 'mbcs' |
272 | + encoding = osutils.get_user_encoding() |
273 | + self.assertPathsEqual(auad, env.decode(encoding)) |
274 | + |
275 | |
276 | class TestLocationsPywin32(TestLocationsCtypes): |
277 | |
278 | |
279 | === modified file 'bzrlib/win32utils.py' |
280 | --- bzrlib/win32utils.py 2011-06-11 01:11:43 +0000 |
281 | +++ bzrlib/win32utils.py 2011-08-05 04:17:29 +0000 |
282 | @@ -93,6 +93,7 @@ |
283 | CSIDL_APPDATA = 0x001A # Application Data folder |
284 | CSIDL_LOCAL_APPDATA = 0x001c# <user name>\Local Settings\Application Data (non roaming) |
285 | CSIDL_PERSONAL = 0x0005 # My Documents folder |
286 | +CSIDL_COMMON_APPDATA = 0x0023 # C:\Documents and Settings\All Users\Application Data |
287 | |
288 | # from winapi C headers |
289 | MAX_PATH = 260 |
290 | @@ -291,6 +292,25 @@ |
291 | return get_appdata_location() |
292 | |
293 | |
294 | +def get_system_appdata_location(): |
295 | + """Return system-wide local Application Data location. |
296 | + |
297 | + This returns the location of the system wide (i.e.- not per-user) |
298 | + application data folder. This can be one of several locations, depending on |
299 | + your platform. Common locations include "C:/ProgramData" and |
300 | + "C:/Documents and Settings/All Users/Application Data". |
301 | + |
302 | + Returned value can be unicode or plain string. |
303 | + To convert plain string to unicode use |
304 | + s.decode(osutils.get_user_encoding()) |
305 | + (XXX - but see bug 262874, which asserts the correct encoding is 'mbcs') |
306 | + """ |
307 | + system_appdata = _get_sh_special_folder_path(CSIDL_COMMON_APPDATA) |
308 | + if system_appdata: |
309 | + return system_appdata |
310 | + return os.environ.get('ALLUSERSAPPDATA') |
311 | + |
312 | + |
313 | def get_home_location(): |
314 | """Return user's home location. |
315 | Assume on win32 it's the <My Documents> folder. |
316 | @@ -537,19 +557,19 @@ |
317 | """ |
318 | # First, spit the command line |
319 | s = cmdline.Splitter(command_line, single_quotes_allowed=single_quotes_allowed) |
320 | - |
321 | - # Bug #587868 Now make sure that the length of s agrees with sys.argv |
322 | - # we do this by simply counting the number of arguments in each. The counts should |
323 | - # agree no matter what encoding sys.argv is in (AFAIK) |
324 | - # len(arguments) < len(sys.argv) should be an impossibility since python gets |
325 | + |
326 | + # Bug #587868 Now make sure that the length of s agrees with sys.argv |
327 | + # we do this by simply counting the number of arguments in each. The counts should |
328 | + # agree no matter what encoding sys.argv is in (AFAIK) |
329 | + # len(arguments) < len(sys.argv) should be an impossibility since python gets |
330 | # args from the very same PEB as does GetCommandLineW |
331 | arguments = list(s) |
332 | - |
333 | + |
334 | # Now shorten the command line we get from GetCommandLineW to match sys.argv |
335 | if len(arguments) < len(argv): |
336 | raise AssertionError("Split command line can't be shorter than argv") |
337 | arguments = arguments[len(arguments) - len(argv):] |
338 | - |
339 | + |
340 | # Carry on to process globs (metachars) in the command line |
341 | # expand globs if necessary |
342 | # TODO: Use 'globbing' instead of 'glob.glob', this gives us stuff like |
Things I know still need to be done:
1) to consider: rename GlobalStore to UserStore, and SystemGlobalStore to GlobalStore. no one outside bzrlib.config and associated unit tests use this class directly, so the rename should be trivial.
2) Test new windows path function.
3) System-wide config file path for Mac OS X? Haven't found any portable way to work out where this should go. Do macs have /etc/?