~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/config.py

  • Committer: John Arbash Meinel
  • Date: 2010-02-17 17:11:16 UTC
  • mfrom: (4797.2.17 2.1)
  • mto: (4797.2.18 2.1)
  • mto: This revision was merged to the branch mainline in revision 5055.
  • Revision ID: john@arbash-meinel.com-20100217171116-h7t9223ystbnx5h8
merge bzr.2.1 in preparation for NEWS entry.

Show diffs side-by-side

added added

removed removed

Lines of Context:
65
65
import os
66
66
import sys
67
67
 
68
 
from bzrlib.decorators import needs_write_lock
69
68
from bzrlib.lazy_import import lazy_import
70
69
lazy_import(globals(), """
71
70
import errno
75
74
 
76
75
import bzrlib
77
76
from bzrlib import (
78
 
    atomicfile,
79
77
    debug,
80
78
    errors,
81
 
    lockdir,
82
79
    mail_client,
83
80
    osutils,
84
81
    registry,
85
82
    symbol_versioning,
86
83
    trace,
87
 
    transport,
88
84
    ui,
89
85
    urlutils,
90
86
    win32utils,
197
193
            interpreted as a boolean. Returns True or False otherwise.
198
194
        """
199
195
        s = self._get_user_option(option_name)
200
 
        if s is None:
201
 
            # The option doesn't exist
202
 
            return None
203
 
        val = ui.bool_from_string(s)
204
 
        if val is None:
205
 
            # The value can't be interpreted as a boolean
206
 
            trace.warning('Value "%s" is not a boolean for "%s"',
207
 
                          s, option_name)
208
 
        return val
 
196
        return ui.bool_from_string(s)
209
197
 
210
198
    def get_user_option_as_list(self, option_name):
211
199
        """Get a generic option as a list - no special process, no default.
261
249
 
262
250
        Something similar to 'Martin Pool <mbp@sourcefrog.net>'
263
251
 
264
 
        $BZR_EMAIL can be set to override this, then
 
252
        $BZR_EMAIL can be set to override this (as well as the
 
253
        deprecated $BZREMAIL), then
265
254
        the concrete policy type is checked, and finally
266
255
        $EMAIL is examined.
267
 
        If no username can be found, errors.NoWhoami exception is raised.
 
256
        If none is found, a reasonable default is (hopefully)
 
257
        created.
268
258
 
269
259
        TODO: Check it's reasonably well-formed.
270
260
        """
280
270
        if v:
281
271
            return v.decode(osutils.get_user_encoding())
282
272
 
283
 
        raise errors.NoWhoami()
284
 
 
285
 
    def ensure_username(self):
286
 
        """Raise errors.NoWhoami if username is not set.
287
 
 
288
 
        This method relies on the username() function raising the error.
289
 
        """
290
 
        self.username()
 
273
        name, email = _auto_user_id()
 
274
        if name:
 
275
            return '%s <%s>' % (name, email)
 
276
        else:
 
277
            return email
291
278
 
292
279
    def signature_checking(self):
293
280
        """What is the current policy for signature checking?."""
355
342
class IniBasedConfig(Config):
356
343
    """A configuration policy that draws from ini files."""
357
344
 
358
 
    def __init__(self, get_filename=symbol_versioning.DEPRECATED_PARAMETER,
359
 
                 file_name=None):
360
 
        """Base class for configuration files using an ini-like syntax.
361
 
 
362
 
        :param file_name: The configuration file path.
363
 
        """
 
345
    def __init__(self, get_filename):
364
346
        super(IniBasedConfig, self).__init__()
365
 
        self.file_name = file_name
366
 
        if symbol_versioning.deprecated_passed(get_filename):
367
 
            symbol_versioning.warn(
368
 
                'IniBasedConfig.__init__(get_filename) was deprecated in 2.3.'
369
 
                ' Use file_name instead.',
370
 
                DeprecationWarning,
371
 
                stacklevel=2)
372
 
            if get_filename is not None:
373
 
                self.file_name = get_filename()
374
 
        else:
375
 
            self.file_name = file_name
376
 
        self._content = None
 
347
        self._get_filename = get_filename
377
348
        self._parser = None
378
349
 
379
 
    @classmethod
380
 
    def from_string(cls, str_or_unicode, file_name=None, save=False):
381
 
        """Create a config object from a string.
382
 
 
383
 
        :param str_or_unicode: A string representing the file content. This will
384
 
            be utf-8 encoded.
385
 
 
386
 
        :param file_name: The configuration file path.
387
 
 
388
 
        :param _save: Whether the file should be saved upon creation.
389
 
        """
390
 
        conf = cls(file_name=file_name)
391
 
        conf._create_from_string(str_or_unicode, save)
392
 
        return conf
393
 
 
394
 
    def _create_from_string(self, str_or_unicode, save):
395
 
        self._content = StringIO(str_or_unicode.encode('utf-8'))
396
 
        # Some tests use in-memory configs, some other always need the config
397
 
        # file to exist on disk.
398
 
        if save:
399
 
            self._write_config_file()
400
 
 
401
 
    def _get_parser(self, file=symbol_versioning.DEPRECATED_PARAMETER):
 
350
    def _get_parser(self, file=None):
402
351
        if self._parser is not None:
403
352
            return self._parser
404
 
        if symbol_versioning.deprecated_passed(file):
405
 
            symbol_versioning.warn(
406
 
                'IniBasedConfig._get_parser(file=xxx) was deprecated in 2.3.'
407
 
                ' Use IniBasedConfig(_content=xxx) instead.',
408
 
                DeprecationWarning,
409
 
                stacklevel=2)
410
 
        if self._content is not None:
411
 
            co_input = self._content
412
 
        elif self.file_name is None:
413
 
            raise AssertionError('We have no content to create the config')
 
353
        if file is None:
 
354
            input = self._get_filename()
414
355
        else:
415
 
            co_input = self.file_name
 
356
            input = file
416
357
        try:
417
 
            self._parser = ConfigObj(co_input, encoding='utf-8')
 
358
            self._parser = ConfigObj(input, encoding='utf-8')
418
359
        except configobj.ConfigObjError, e:
419
360
            raise errors.ParseConfigError(e.errors, e.config.filename)
420
 
        # Make sure self.reload() will use the right file name
421
 
        self._parser.filename = self.file_name
422
361
        return self._parser
423
362
 
424
 
    def reload(self):
425
 
        """Reload the config file from disk."""
426
 
        if self.file_name is None:
427
 
            raise AssertionError('We need a file name to reload the config')
428
 
        if self._parser is not None:
429
 
            self._parser.reload()
430
 
 
431
363
    def _get_matching_sections(self):
432
364
        """Return an ordered list of (section_name, extra_path) pairs.
433
365
 
536
468
    def _get_nickname(self):
537
469
        return self.get_user_option('nickname')
538
470
 
539
 
    def _write_config_file(self):
540
 
        if self.file_name is None:
541
 
            raise AssertionError('We cannot save, self.file_name is None')
542
 
        conf_dir = os.path.dirname(self.file_name)
543
 
        ensure_config_dir_exists(conf_dir)
544
 
        atomic_file = atomicfile.AtomicFile(self.file_name)
545
 
        self._get_parser().write(atomic_file)
546
 
        atomic_file.commit()
547
 
        atomic_file.close()
548
 
        osutils.copy_ownership_from_path(self.file_name)
549
 
 
550
 
 
551
 
class LockableConfig(IniBasedConfig):
552
 
    """A configuration needing explicit locking for access.
553
 
 
554
 
    If several processes try to write the config file, the accesses need to be
555
 
    serialized.
556
 
 
557
 
    Daughter classes should decorate all methods that update a config with the
558
 
    ``@needs_write_lock`` decorator (they call, directly or indirectly, the
559
 
    ``_write_config_file()`` method. These methods (typically ``set_option()``
560
 
    and variants must reload the config file from disk before calling
561
 
    ``_write_config_file()``), this can be achieved by calling the
562
 
    ``self.reload()`` method. Note that the lock scope should cover both the
563
 
    reading and the writing of the config file which is why the decorator can't
564
 
    be applied to ``_write_config_file()`` only.
565
 
 
566
 
    This should be enough to implement the following logic:
567
 
    - lock for exclusive write access,
568
 
    - reload the config file from disk,
569
 
    - set the new value
570
 
    - unlock
571
 
 
572
 
    This logic guarantees that a writer can update a value without erasing an
573
 
    update made by another writer.
574
 
    """
575
 
 
576
 
    lock_name = 'lock'
577
 
 
578
 
    def __init__(self, file_name):
579
 
        super(LockableConfig, self).__init__(file_name=file_name)
580
 
        self.dir = osutils.dirname(osutils.safe_unicode(self.file_name))
581
 
        self.transport = transport.get_transport(self.dir)
582
 
        self._lock = lockdir.LockDir(self.transport, 'lock')
583
 
 
584
 
    def _create_from_string(self, unicode_bytes, save):
585
 
        super(LockableConfig, self)._create_from_string(unicode_bytes, False)
586
 
        if save:
587
 
            # We need to handle the saving here (as opposed to IniBasedConfig)
588
 
            # to be able to lock
589
 
            self.lock_write()
590
 
            self._write_config_file()
591
 
            self.unlock()
592
 
 
593
 
    def lock_write(self, token=None):
594
 
        """Takes a write lock in the directory containing the config file.
595
 
 
596
 
        If the directory doesn't exist it is created.
597
 
        """
598
 
        ensure_config_dir_exists(self.dir)
599
 
        return self._lock.lock_write(token)
600
 
 
601
 
    def unlock(self):
602
 
        self._lock.unlock()
603
 
 
604
 
    def break_lock(self):
605
 
        self._lock.break_lock()
606
 
 
607
 
    def _write_config_file(self):
608
 
        if self._lock is None or not self._lock.is_held:
609
 
            # NB: if the following exception is raised it probably means a
610
 
            # missing @needs_write_lock decorator on one of the callers.
611
 
            raise errors.ObjectNotLocked(self)
612
 
        super(LockableConfig, self)._write_config_file()
613
 
 
614
 
 
615
 
class GlobalConfig(LockableConfig):
 
471
 
 
472
class GlobalConfig(IniBasedConfig):
616
473
    """The configuration that should be used for a specific location."""
617
474
 
618
 
    def __init__(self):
619
 
        super(GlobalConfig, self).__init__(file_name=config_filename())
620
 
 
621
 
    @classmethod
622
 
    def from_string(cls, str_or_unicode, save=False):
623
 
        """Create a config object from a string.
624
 
 
625
 
        :param str_or_unicode: A string representing the file content. This
626
 
            will be utf-8 encoded.
627
 
 
628
 
        :param save: Whether the file should be saved upon creation.
629
 
        """
630
 
        conf = cls()
631
 
        conf._create_from_string(str_or_unicode, save)
632
 
        return conf
633
 
 
634
475
    def get_editor(self):
635
476
        return self._get_user_option('editor')
636
477
 
637
 
    @needs_write_lock
 
478
    def __init__(self):
 
479
        super(GlobalConfig, self).__init__(config_filename)
 
480
 
638
481
    def set_user_option(self, option, value):
639
482
        """Save option and its value in the configuration."""
640
483
        self._set_option(option, value, 'DEFAULT')
646
489
        else:
647
490
            return {}
648
491
 
649
 
    @needs_write_lock
650
492
    def set_alias(self, alias_name, alias_command):
651
493
        """Save the alias in the configuration."""
652
494
        self._set_option(alias_name, alias_command, 'ALIASES')
653
495
 
654
 
    @needs_write_lock
655
496
    def unset_alias(self, alias_name):
656
497
        """Unset an existing alias."""
657
 
        self.reload()
658
498
        aliases = self._get_parser().get('ALIASES')
659
499
        if not aliases or alias_name not in aliases:
660
500
            raise errors.NoSuchAlias(alias_name)
662
502
        self._write_config_file()
663
503
 
664
504
    def _set_option(self, option, value, section):
665
 
        self.reload()
 
505
        # FIXME: RBC 20051029 This should refresh the parser and also take a
 
506
        # file lock on bazaar.conf.
 
507
        conf_dir = os.path.dirname(self._get_filename())
 
508
        ensure_config_dir_exists(conf_dir)
666
509
        self._get_parser().setdefault(section, {})[option] = value
667
510
        self._write_config_file()
668
511
 
669
 
 
670
 
class LocationConfig(LockableConfig):
 
512
    def _write_config_file(self):
 
513
        f = open(self._get_filename(), 'wb')
 
514
        self._get_parser().write(f)
 
515
        f.close()
 
516
 
 
517
 
 
518
class LocationConfig(IniBasedConfig):
671
519
    """A configuration object that gives the policy for a location."""
672
520
 
673
521
    def __init__(self, location):
674
 
        super(LocationConfig, self).__init__(
675
 
            file_name=locations_config_filename())
 
522
        name_generator = locations_config_filename
 
523
        if (not os.path.exists(name_generator()) and
 
524
                os.path.exists(branches_config_filename())):
 
525
            if sys.platform == 'win32':
 
526
                trace.warning('Please rename %s to %s'
 
527
                              % (branches_config_filename(),
 
528
                                 locations_config_filename()))
 
529
            else:
 
530
                trace.warning('Please rename ~/.bazaar/branches.conf'
 
531
                              ' to ~/.bazaar/locations.conf')
 
532
            name_generator = branches_config_filename
 
533
        super(LocationConfig, self).__init__(name_generator)
676
534
        # local file locations are looked up by local path, rather than
677
535
        # by file url. This is because the config file is a user
678
536
        # file, and we would rather not expose the user to file urls.
680
538
            location = urlutils.local_path_from_url(location)
681
539
        self.location = location
682
540
 
683
 
    @classmethod
684
 
    def from_string(cls, str_or_unicode, location, save=False):
685
 
        """Create a config object from a string.
686
 
 
687
 
        :param str_or_unicode: A string representing the file content. This will
688
 
            be utf-8 encoded.
689
 
 
690
 
        :param location: The location url to filter the configuration.
691
 
 
692
 
        :param save: Whether the file should be saved upon creation.
693
 
        """
694
 
        conf = cls(location)
695
 
        conf._create_from_string(str_or_unicode, save)
696
 
        return conf
697
 
 
698
541
    def _get_matching_sections(self):
699
542
        """Return an ordered list of section names matching this location."""
700
543
        sections = self._get_parser()
788
631
            if policy_key in self._get_parser()[section]:
789
632
                del self._get_parser()[section][policy_key]
790
633
 
791
 
    @needs_write_lock
792
634
    def set_user_option(self, option, value, store=STORE_LOCATION):
793
635
        """Save option and its value in the configuration."""
794
636
        if store not in [STORE_LOCATION,
796
638
                         STORE_LOCATION_APPENDPATH]:
797
639
            raise ValueError('bad storage policy %r for %r' %
798
640
                (store, option))
799
 
        self.reload()
 
641
        # FIXME: RBC 20051029 This should refresh the parser and also take a
 
642
        # file lock on locations.conf.
 
643
        conf_dir = os.path.dirname(self._get_filename())
 
644
        ensure_config_dir_exists(conf_dir)
800
645
        location = self.location
801
646
        if location.endswith('/'):
802
647
            location = location[:-1]
803
 
        parser = self._get_parser()
804
 
        if not location in parser and not location + '/' in parser:
805
 
            parser[location] = {}
806
 
        elif location + '/' in parser:
 
648
        if (not location in self._get_parser() and
 
649
            not location + '/' in self._get_parser()):
 
650
            self._get_parser()[location]={}
 
651
        elif location + '/' in self._get_parser():
807
652
            location = location + '/'
808
 
        parser[location][option]=value
 
653
        self._get_parser()[location][option]=value
809
654
        # the allowed values of store match the config policies
810
655
        self._set_option_policy(location, option, store)
811
 
        self._write_config_file()
 
656
        self._get_parser().write(file(self._get_filename(), 'wb'))
812
657
 
813
658
 
814
659
class BranchConfig(Config):
815
660
    """A configuration object giving the policy for a branch."""
816
661
 
817
 
    def __init__(self, branch):
818
 
        super(BranchConfig, self).__init__()
819
 
        self._location_config = None
820
 
        self._branch_data_config = None
821
 
        self._global_config = None
822
 
        self.branch = branch
823
 
        self.option_sources = (self._get_location_config,
824
 
                               self._get_branch_data_config,
825
 
                               self._get_global_config)
826
 
 
827
662
    def _get_branch_data_config(self):
828
663
        if self._branch_data_config is None:
829
664
            self._branch_data_config = TreeConfig(self.branch)
927
762
        """See Config.gpg_signing_command."""
928
763
        return self._get_safe_value('_gpg_signing_command')
929
764
 
 
765
    def __init__(self, branch):
 
766
        super(BranchConfig, self).__init__()
 
767
        self._location_config = None
 
768
        self._branch_data_config = None
 
769
        self._global_config = None
 
770
        self.branch = branch
 
771
        self.option_sources = (self._get_location_config,
 
772
                               self._get_branch_data_config,
 
773
                               self._get_global_config)
 
774
 
930
775
    def _post_commit(self):
931
776
        """See Config.post_commit."""
932
777
        return self._get_safe_value('_post_commit')
965
810
            os.mkdir(parent_dir)
966
811
        trace.mutter('creating config directory: %r', path)
967
812
        os.mkdir(path)
968
 
        osutils.copy_ownership_from_path(path)
969
813
 
970
814
 
971
815
def config_dir():
986
830
                                  ' or HOME set')
987
831
        return osutils.pathjoin(base, 'bazaar', '2.0')
988
832
    else:
 
833
        # cygwin, linux, and darwin all have a $HOME directory
989
834
        if base is None:
990
835
            base = os.path.expanduser("~")
991
836
        return osutils.pathjoin(base, ".bazaar")
996
841
    return osutils.pathjoin(config_dir(), 'bazaar.conf')
997
842
 
998
843
 
 
844
def branches_config_filename():
 
845
    """Return per-user configuration ini file filename."""
 
846
    return osutils.pathjoin(config_dir(), 'branches.conf')
 
847
 
 
848
 
999
849
def locations_config_filename():
1000
850
    """Return per-user configuration ini file filename."""
1001
851
    return osutils.pathjoin(config_dir(), 'locations.conf')
1016
866
 
1017
867
    This doesn't implicitly create it.
1018
868
 
1019
 
    On Windows it's in the config directory; elsewhere it's /var/crash
1020
 
    which may be monitored by apport.  It can be overridden by
1021
 
    $APPORT_CRASH_DIR.
 
869
    On Windows it's in the config directory; elsewhere in the XDG cache directory.
1022
870
    """
1023
871
    if sys.platform == 'win32':
1024
872
        return osutils.pathjoin(config_dir(), 'Crash')
1025
873
    else:
1026
 
        # XXX: hardcoded in apport_python_hook.py; therefore here too -- mbp
1027
 
        # 2010-01-31
1028
 
        return os.environ.get('APPORT_CRASH_DIR', '/var/crash')
 
874
        return osutils.pathjoin(xdg_cache_dir(), 'crash')
1029
875
 
1030
876
 
1031
877
def xdg_cache_dir():
1038
884
        return os.path.expanduser('~/.cache')
1039
885
 
1040
886
 
 
887
def _auto_user_id():
 
888
    """Calculate automatic user identification.
 
889
 
 
890
    Returns (realname, email).
 
891
 
 
892
    Only used when none is set in the environment or the id file.
 
893
 
 
894
    This previously used the FQDN as the default domain, but that can
 
895
    be very slow on machines where DNS is broken.  So now we simply
 
896
    use the hostname.
 
897
    """
 
898
    import socket
 
899
 
 
900
    if sys.platform == 'win32':
 
901
        name = win32utils.get_user_name_unicode()
 
902
        if name is None:
 
903
            raise errors.BzrError("Cannot autodetect user name.\n"
 
904
                                  "Please, set your name with command like:\n"
 
905
                                  'bzr whoami "Your Name <name@domain.com>"')
 
906
        host = win32utils.get_host_name_unicode()
 
907
        if host is None:
 
908
            host = socket.gethostname()
 
909
        return name, (name + '@' + host)
 
910
 
 
911
    try:
 
912
        import pwd
 
913
        uid = os.getuid()
 
914
        try:
 
915
            w = pwd.getpwuid(uid)
 
916
        except KeyError:
 
917
            raise errors.BzrCommandError('Unable to determine your name.  '
 
918
                'Please use "bzr whoami" to set it.')
 
919
 
 
920
        # we try utf-8 first, because on many variants (like Linux),
 
921
        # /etc/passwd "should" be in utf-8, and because it's unlikely to give
 
922
        # false positives.  (many users will have their user encoding set to
 
923
        # latin-1, which cannot raise UnicodeError.)
 
924
        try:
 
925
            gecos = w.pw_gecos.decode('utf-8')
 
926
            encoding = 'utf-8'
 
927
        except UnicodeError:
 
928
            try:
 
929
                encoding = osutils.get_user_encoding()
 
930
                gecos = w.pw_gecos.decode(encoding)
 
931
            except UnicodeError:
 
932
                raise errors.BzrCommandError('Unable to determine your name.  '
 
933
                   'Use "bzr whoami" to set it.')
 
934
        try:
 
935
            username = w.pw_name.decode(encoding)
 
936
        except UnicodeError:
 
937
            raise errors.BzrCommandError('Unable to determine your name.  '
 
938
                'Use "bzr whoami" to set it.')
 
939
 
 
940
        comma = gecos.find(',')
 
941
        if comma == -1:
 
942
            realname = gecos
 
943
        else:
 
944
            realname = gecos[:comma]
 
945
        if not realname:
 
946
            realname = username
 
947
 
 
948
    except ImportError:
 
949
        import getpass
 
950
        try:
 
951
            user_encoding = osutils.get_user_encoding()
 
952
            realname = username = getpass.getuser().decode(user_encoding)
 
953
        except UnicodeDecodeError:
 
954
            raise errors.BzrError("Can't decode username as %s." % \
 
955
                    user_encoding)
 
956
 
 
957
    return realname, (username + '@' + socket.gethostname())
 
958
 
 
959
 
1041
960
def parse_username(username):
1042
961
    """Parse e-mail username and return a (name, address) tuple."""
1043
962
    match = re.match(r'(.*?)\s*<?([\w+.-]+@[\w+.-]+)>?', username)
1129
1048
        """Save the config file, only tests should use it for now."""
1130
1049
        conf_dir = os.path.dirname(self._filename)
1131
1050
        ensure_config_dir_exists(conf_dir)
1132
 
        f = file(self._filename, 'wb')
1133
 
        try:
1134
 
            self._get_config().write(f)
1135
 
        finally:
1136
 
            f.close()
 
1051
        self._get_config().write(file(self._filename, 'wb'))
1137
1052
 
1138
1053
    def _set_option(self, section_name, option_name, value):
1139
1054
        """Set an authentication configuration option"""
1487
1402
 
1488
1403
 
1489
1404
class PlainTextCredentialStore(CredentialStore):
1490
 
    __doc__ = """Plain text credential store for the authentication.conf file"""
 
1405
    """Plain text credential store for the authentication.conf file."""
1491
1406
 
1492
1407
    def decode_password(self, credentials):
1493
1408
        """See CredentialStore.decode_password."""
1587
1502
            return StringIO()
1588
1503
 
1589
1504
    def _get_configobj(self):
1590
 
        f = self._get_config_file()
1591
 
        try:
1592
 
            return ConfigObj(f, encoding='utf-8')
1593
 
        finally:
1594
 
            f.close()
 
1505
        return ConfigObj(self._get_config_file(), encoding='utf-8')
1595
1506
 
1596
1507
    def _set_configobj(self, configobj):
1597
1508
        out_file = StringIO()