Merge lp:~jelmer/bzr/config-file-permdenied into lp:bzr

Proposed by Jelmer Vernooij
Status: Merged
Approved by: Vincent Ladeuil
Approved revision: no longer in the source branch.
Merged at revision: 6117
Proposed branch: lp:~jelmer/bzr/config-file-permdenied
Merge into: lp:bzr
Diff against target: 143 lines (+60/-8)
3 files modified
bzrlib/config.py (+14/-4)
bzrlib/tests/test_config.py (+42/-4)
doc/en/release-notes/bzr-2.5.txt (+4/-0)
To merge this branch: bzr merge lp:~jelmer/bzr/config-file-permdenied
Reviewer Review Type Date Requested Status
Vincent Ladeuil Needs Fixing
Review via email: mp+73361@code.launchpad.net

Commit message

Print a warning rather than an error when the current user does not have permission to read a configuration file.

Description of the change

If the current user is not allowed to read a configuration file,
warn and continue without it rather than raising an exception.

To post a comment you must log in.
Revision history for this message
Vincent Ladeuil (vila) wrote :

store.load() is used both for reading a config file and before saving it, the behavior should be different.

I've tweaked your submission at lp:~vila/bzr/config-file-permdenied

Also, I think configobj use os.path.isfile and as such should be immune to the issue, but your patch doesn't hurt either so let's land that.

review: Needs Fixing
Revision history for this message
Martin Packman (gz) wrote :

+ trace.warning("Permission denied while trying to open "
+ "configuration file %s.", urlutils.unescape_for_display(
+ urlutils.join(self._transport.base, self._filename), "utf-8"))

Again, this results in mangled path on non-utf-8 terminals.

Revision history for this message
Jelmer Vernooij (jelmer) wrote :

On 08/31/2011 01:27 AM, Martin [gz] wrote:
> + trace.warning("Permission denied while trying to open "
> + "configuration file %s.", urlutils.unescape_for_display(
> + urlutils.join(self._transport.base, self._filename), "utf-8"))
>
> Again, this results in mangled path on non-utf-8 terminals.
I think that's a separate issue we need to address. trace is defined as
using utf8 at the moment so this is the only sensible thing to do right now.

Ideally we should have trace recode the utf8 to whatever the terminal is
using when writing to stdout, or perhaps have it accept unicode too.

Cheers,

Jelmer

Revision history for this message
Vincent Ladeuil (vila) wrote :

> On 08/31/2011 01:27 AM, Martin [gz] wrote:
> > Again, this results in mangled path on non-utf-8 terminals.
> I think that's a separate issue we need to address. trace is defined as
> using utf8 at the moment so this is the only sensible thing to do right now.

I agree with mgz that encoding issues need to be addressed too ;)

I agree with jelmer that we need to go forward there ;)

@mgz: Is there a bug tracking this particular issue ?

I want my cake and eat it too: this fix addresses a specific
issue in a highly unsual env which deserves a better *error*
reporting, i.e.: something is already wrong in the setup.

If this env *also* provides a broken terminal, well, I don't mind
giving a mangled path until we are able to give a meaningful
one. If trying to report this error *fails*, then that's more
concerning, but 'mangled', I can live with that (for now ;).

Summary: I think we shouldn't block here. mgz, is that ok ?

Revision history for this message
Jelmer Vernooij (jelmer) wrote :

sent to pqm by email

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'bzrlib/config.py'
2--- bzrlib/config.py 2011-08-29 12:01:49 +0000
3+++ bzrlib/config.py 2011-08-30 12:59:32 +0000
4@@ -1397,7 +1397,7 @@
5 return (self.branch._transport.get_bytes("email")
6 .decode(osutils.get_user_encoding())
7 .rstrip("\r\n"))
8- except errors.NoSuchFile, e:
9+ except (errors.NoSuchFile, errors.PermissionDenied), e:
10 pass
11
12 return self._get_best_value('_get_user_id')
13@@ -2278,6 +2278,11 @@
14 return f
15 except errors.NoSuchFile:
16 return StringIO()
17+ except errors.PermissionDenied, e:
18+ trace.warning("Permission denied while trying to open "
19+ "configuration file %s.", urlutils.unescape_for_display(
20+ urlutils.join(self._transport.base, self._filename), "utf-8"))
21+ return StringIO()
22
23 def _external_url(self):
24 return urlutils.join(self._transport.external_url(), self._filename)
25@@ -2690,7 +2695,12 @@
26 """Load the store from the associated file."""
27 if self.is_loaded():
28 return
29- content = self.transport.get_bytes(self.file_name)
30+ try:
31+ content = self.transport.get_bytes(self.file_name)
32+ except errors.PermissionDenied:
33+ trace.warning("Permission denied while trying to load "
34+ "configuration store %s.", self.external_url())
35+ raise
36 self._load_from_string(content)
37 for hook in ConfigHooks['load']:
38 hook(self)
39@@ -2738,8 +2748,8 @@
40 # We need a loaded store
41 try:
42 self.load()
43- except errors.NoSuchFile:
44- # If the file doesn't exist, there is no sections
45+ except (errors.NoSuchFile, errors.PermissionDenied):
46+ # If the file can't be read, there is no sections
47 return
48 cobj = self._config_obj
49 if cobj.scalars:
50
51=== modified file 'bzrlib/tests/test_config.py'
52--- bzrlib/tests/test_config.py 2011-08-29 12:01:49 +0000
53+++ bzrlib/tests/test_config.py 2011-08-30 12:59:32 +0000
54@@ -33,18 +33,14 @@
55 errors,
56 osutils,
57 mail_client,
58- mergetools,
59 ui,
60 urlutils,
61- registry,
62 remote,
63 tests,
64 trace,
65- transport,
66 )
67 from bzrlib.symbol_versioning import (
68 deprecated_in,
69- deprecated_method,
70 )
71 from bzrlib.transport import remote as transport_remote
72 from bzrlib.tests import (
73@@ -1968,6 +1964,29 @@
74 conf = config.TransportConfig(t, 'foo.conf')
75 self.assertRaises(errors.ParseConfigError, conf._get_configobj)
76
77+ def test_load_permission_denied(self):
78+ """Ensure we get an empty config file if the file is inaccessible."""
79+ warnings = []
80+ def warning(*args):
81+ warnings.append(args[0] % args[1:])
82+ self.overrideAttr(trace, 'warning', warning)
83+
84+ class DenyingTransport(object):
85+
86+ def __init__(self, base):
87+ self.base = base
88+
89+ def get_bytes(self, relpath):
90+ raise errors.PermissionDenied(relpath, "")
91+
92+ cfg = config.TransportConfig(
93+ DenyingTransport("nonexisting://"), 'control.conf')
94+ self.assertIs(None, cfg.get_option('non-existant', 'SECTION'))
95+ self.assertEquals(
96+ warnings,
97+ [u'Permission denied while trying to open configuration file '
98+ u'nonexisting:///control.conf.'])
99+
100 def test_get_value(self):
101 """Test that retreiving a value from a section is possible"""
102 bzrdir_config = config.TransportConfig(self.get_transport('.'),
103@@ -2584,6 +2603,25 @@
104 store = config.IniFileStore(t, 'foo.conf')
105 self.assertRaises(errors.ParseConfigError, store.load)
106
107+ def test_load_permission_denied(self):
108+ """Ensure we get warned when trying to load an inaccessible file."""
109+ warnings = []
110+ def warning(*args):
111+ warnings.append(args[0] % args[1:])
112+ self.overrideAttr(trace, 'warning', warning)
113+
114+ t = self.get_transport()
115+
116+ def get_bytes(relpath):
117+ raise errors.PermissionDenied(relpath, "")
118+ t.get_bytes = get_bytes
119+ store = config.IniFileStore(t, 'foo.conf')
120+ self.assertRaises(errors.PermissionDenied, store.load)
121+ self.assertEquals(
122+ warnings,
123+ [u'Permission denied while trying to load configuration store %s.'
124+ % store.external_url()])
125+
126
127 class TestIniConfigContent(tests.TestCaseWithTransport):
128 """Simulate loading a IniBasedConfig without content of various encodings.
129
130=== modified file 'doc/en/release-notes/bzr-2.5.txt'
131--- doc/en/release-notes/bzr-2.5.txt 2011-08-27 19:08:54 +0000
132+++ doc/en/release-notes/bzr-2.5.txt 2011-08-30 12:59:32 +0000
133@@ -136,6 +136,10 @@
134 * Decode ``BZR_HOME`` with fs encoding on posix platforms to avoid unicode
135 errors. (Vincent Ladeuil, #822571)
136
137+* Rather than an error being raised, a warning is now printed when the
138+ current user does not have permission to read a configuration file.
139+ (Jelmer Vernooij, #837324)
140+
141 * TreeTransformBase.fixup_new_roots no longer forces trees to have a root, so
142 operations that use it, like merge, can now create trees without a root.
143 (Aaron Bentley)