Merge lp:~mbp/bzr/whoami into lp:bzr/2.3

Proposed by Martin Pool
Status: Merged
Approved by: Vincent Ladeuil
Approved revision: no longer in the source branch.
Merged at revision: 5636
Proposed branch: lp:~mbp/bzr/whoami
Merge into: lp:bzr/2.3
Diff against target: 180 lines (+115/-5)
3 files modified
bzrlib/config.py (+86/-5)
bzrlib/tests/test_config.py (+23/-0)
doc/en/release-notes/bzr-2.3.txt (+6/-0)
To merge this branch: bzr merge lp:~mbp/bzr/whoami
Reviewer Review Type Date Requested Status
Vincent Ladeuil Needs Fixing
Review via email: mp+55679@code.launchpad.net

Commit message

infer default user name from /etc/mailname on unix (bug 616878)

Description of the change

This addresses bug 616878 by making bzr automatically infer an email address if /etc/mailname is set. This tries to get a balance between on the one hand saving people from committing lots of work as joe@localhost, and on the other hand letting them commit without needing manual setup. Basically it's a partial reversion and then readjustment for the fix for bug 549310.

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

You just got a lot of positive karma from admins all over the planet ;-D

94 + # we try utf-8 first, because on many variants (like Linux),
95 + # /etc/passwd "should" be in utf-8, and because it's unlikely to give
96 + # false positives. (many users will have their user encoding set to
97 + # latin-1, which cannot raise UnicodeError.)

You will make savannah users happy with that, I think there is even a bug for that https://bugs.launchpad.net/bzr/+bug/659763 .

I think you could easily add more tests for _auto_user_id() and _get_default_mail_domain() by adding optional parameters to inject whatever test files you need (/etc/passwd (or getuid(), pwd.getpwuid() whatever), /etc/mailname, etc)

That's a tweak

review: Needs Fixing
Revision history for this message
Martin Pool (mbp) wrote :

The unicode code is not originally mine; it's resurrected from I think
mgz. So if that bug existed before, it probably still exists with
this patch...

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

@poolie: As I understood it from bug #659763, the issue was that we were using an ASCII encoding to interpret /etc/passwd instead of using utf-8, so I think your patch *addresses* the bug.

Revision history for this message
Martin Pool (mbp) wrote :

sent to pqm by email

Revision history for this message
Martin Pool (mbp) wrote :

sent to pqm by email

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'bzrlib/config.py'
--- bzrlib/config.py 2011-01-12 18:12:58 +0000
+++ bzrlib/config.py 2011-04-01 03:15:39 +0000
@@ -63,6 +63,7 @@
63"""63"""
6464
65import os65import os
66import string
66import sys67import sys
6768
68from bzrlib import commands69from bzrlib import commands
@@ -271,21 +272,21 @@
271 the concrete policy type is checked, and finally272 the concrete policy type is checked, and finally
272 $EMAIL is examined.273 $EMAIL is examined.
273 If no username can be found, errors.NoWhoami exception is raised.274 If no username can be found, errors.NoWhoami exception is raised.
274
275 TODO: Check it's reasonably well-formed.
276 """275 """
277 v = os.environ.get('BZR_EMAIL')276 v = os.environ.get('BZR_EMAIL')
278 if v:277 if v:
279 return v.decode(osutils.get_user_encoding())278 return v.decode(osutils.get_user_encoding())
280
281 v = self._get_user_id()279 v = self._get_user_id()
282 if v:280 if v:
283 return v281 return v
284
285 v = os.environ.get('EMAIL')282 v = os.environ.get('EMAIL')
286 if v:283 if v:
287 return v.decode(osutils.get_user_encoding())284 return v.decode(osutils.get_user_encoding())
288285 name, email = _auto_user_id()
286 if name and email:
287 return '%s <%s>' % (name, email)
288 elif email:
289 return email
289 raise errors.NoWhoami()290 raise errors.NoWhoami()
290291
291 def ensure_username(self):292 def ensure_username(self):
@@ -1213,6 +1214,86 @@
1213 return os.path.expanduser('~/.cache')1214 return os.path.expanduser('~/.cache')
12141215
12151216
1217def _get_default_mail_domain():
1218 """If possible, return the assumed default email domain.
1219
1220 :returns: string mail domain, or None.
1221 """
1222 if sys.platform == 'win32':
1223 # No implementation yet; patches welcome
1224 return None
1225 try:
1226 f = open('/etc/mailname')
1227 except (IOError, OSError), e:
1228 return None
1229 try:
1230 domain = f.read().strip()
1231 return domain
1232 finally:
1233 f.close()
1234
1235
1236def _auto_user_id():
1237 """Calculate automatic user identification.
1238
1239 :returns: (realname, email), either of which may be None if they can't be
1240 determined.
1241
1242 Only used when none is set in the environment or the id file.
1243
1244 This only returns an email address if we can be fairly sure the
1245 address is reasonable, ie if /etc/mailname is set on unix.
1246
1247 This doesn't use the FQDN as the default domain because that may be
1248 slow, and it doesn't use the hostname alone because that's not normally
1249 a reasonable address.
1250 """
1251 if sys.platform == 'win32':
1252 # No implementation to reliably determine Windows default mail
1253 # address; please add one.
1254 return None, None
1255
1256 default_mail_domain = _get_default_mail_domain()
1257 if not default_mail_domain:
1258 return None, None
1259
1260 import pwd
1261 uid = os.getuid()
1262 try:
1263 w = pwd.getpwuid(uid)
1264 except KeyError:
1265 mutter('no passwd entry for uid %d?' % uid)
1266 return None, None
1267
1268 # we try utf-8 first, because on many variants (like Linux),
1269 # /etc/passwd "should" be in utf-8, and because it's unlikely to give
1270 # false positives. (many users will have their user encoding set to
1271 # latin-1, which cannot raise UnicodeError.)
1272 try:
1273 gecos = w.pw_gecos.decode('utf-8')
1274 encoding = 'utf-8'
1275 except UnicodeError:
1276 try:
1277 encoding = osutils.get_user_encoding()
1278 gecos = w.pw_gecos.decode(encoding)
1279 except UnicodeError, e:
1280 mutter("cannot decode passwd entry %s" % w)
1281 return None, None
1282 try:
1283 username = w.pw_name.decode(encoding)
1284 except UnicodeError, e:
1285 mutter("cannot decode passwd entry %s" % w)
1286 return None, None
1287
1288 comma = gecos.find(',')
1289 if comma == -1:
1290 realname = gecos
1291 else:
1292 realname = gecos[:comma]
1293
1294 return realname, (username + '@' + default_mail_domain)
1295
1296
1216def parse_username(username):1297def parse_username(username):
1217 """Parse e-mail username and return a (name, address) tuple."""1298 """Parse e-mail username and return a (name, address) tuple."""
1218 match = re.match(r'(.*?)\s*<?([\w+.-]+@[\w+.-]+)>?', username)1299 match = re.match(r'(.*?)\s*<?([\w+.-]+@[\w+.-]+)>?', username)
12191300
=== modified file 'bzrlib/tests/test_config.py'
--- bzrlib/tests/test_config.py 2011-02-22 09:49:45 +0000
+++ bzrlib/tests/test_config.py 2011-04-01 03:15:39 +0000
@@ -41,6 +41,7 @@
41 )41 )
42from bzrlib.tests import (42from bzrlib.tests import (
43 features,43 features,
44 TestSkipped,
44 scenarios,45 scenarios,
45 )46 )
46from bzrlib.util.configobj import configobj47from bzrlib.util.configobj import configobj
@@ -2237,3 +2238,25 @@
2237# test_user_prompted ?2238# test_user_prompted ?
2238class TestAuthenticationRing(tests.TestCaseWithTransport):2239class TestAuthenticationRing(tests.TestCaseWithTransport):
2239 pass2240 pass
2241
2242
2243class TestAutoUserId(tests.TestCase):
2244 """Test inferring an automatic user name."""
2245
2246 def test_auto_user_id(self):
2247 """Automatic inference of user name.
2248
2249 This is a bit hard to test in an isolated way, because it depends on
2250 system functions that go direct to /etc or perhaps somewhere else.
2251 But it's reasonable to say that on Unix, with an /etc/mailname, we ought
2252 to be able to choose a user name with no configuration.
2253 """
2254 if sys.platform == 'win32':
2255 raise TestSkipped("User name inference not implemented on win32")
2256 realname, address = config._auto_user_id()
2257 if os.path.exists('/etc/mailname'):
2258 self.assertTrue(realname)
2259 self.assertTrue(address)
2260 else:
2261 self.assertEquals((None, None), (realname, address))
2262
22402263
=== modified file 'doc/en/release-notes/bzr-2.3.txt'
--- doc/en/release-notes/bzr-2.3.txt 2011-04-01 01:37:43 +0000
+++ doc/en/release-notes/bzr-2.3.txt 2011-04-01 03:15:39 +0000
@@ -39,6 +39,12 @@
39.. Fixes for situations where bzr would previously crash or give incorrect39.. Fixes for situations where bzr would previously crash or give incorrect
40 or undesirable results.40 or undesirable results.
4141
42* Bazaar now infers the default user email address on Unix from the local
43 account name plus the contents of ``/etc/mailname`` if that file exists.
44 In particular, this means that committing as root through etckeeper will
45 normally not require running ``bzr whoami`` first.
46 (Martin Pool, #616878)
47
42* When reporting a crash without apport, don't print the full list of48* When reporting a crash without apport, don't print the full list of
43 plugins because it's often too long.49 plugins because it's often too long.
44 (Martin Pool, #716389)50 (Martin Pool, #716389)

Subscribers

People subscribed via source and target branches