~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/config.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2010-09-01 08:02:42 UTC
  • mfrom: (5390.3.3 faster-revert-593560)
  • Revision ID: pqm@pqm.ubuntu.com-20100901080242-esg62ody4frwmy66
(spiv) Avoid repeatedly calling self.target.all_file_ids() in
 InterTree.iter_changes. (Andrew Bennetts)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2007, 2008 Canonical Ltd
 
1
# Copyright (C) 2005-2010 Canonical Ltd
2
2
#   Authors: Robert Collins <robert.collins@canonical.com>
3
3
#            and others
4
4
#
65
65
import os
66
66
import sys
67
67
 
 
68
from bzrlib.decorators import needs_write_lock
68
69
from bzrlib.lazy_import import lazy_import
69
70
lazy_import(globals(), """
70
71
import errno
74
75
 
75
76
import bzrlib
76
77
from bzrlib import (
 
78
    atomicfile,
77
79
    debug,
78
80
    errors,
 
81
    lockdir,
79
82
    mail_client,
80
83
    osutils,
81
84
    registry,
82
85
    symbol_versioning,
83
86
    trace,
 
87
    transport,
84
88
    ui,
85
89
    urlutils,
86
90
    win32utils,
193
197
            interpreted as a boolean. Returns True or False otherwise.
194
198
        """
195
199
        s = self._get_user_option(option_name)
196
 
        return ui.bool_from_string(s)
 
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
197
209
 
198
210
    def get_user_option_as_list(self, option_name):
199
211
        """Get a generic option as a list - no special process, no default.
249
261
 
250
262
        Something similar to 'Martin Pool <mbp@sourcefrog.net>'
251
263
 
252
 
        $BZR_EMAIL can be set to override this (as well as the
253
 
        deprecated $BZREMAIL), then
 
264
        $BZR_EMAIL can be set to override this, then
254
265
        the concrete policy type is checked, and finally
255
266
        $EMAIL is examined.
256
 
        If none is found, a reasonable default is (hopefully)
257
 
        created.
 
267
        If no username can be found, errors.NoWhoami exception is raised.
258
268
 
259
269
        TODO: Check it's reasonably well-formed.
260
270
        """
270
280
        if v:
271
281
            return v.decode(osutils.get_user_encoding())
272
282
 
273
 
        name, email = _auto_user_id()
274
 
        if name:
275
 
            return '%s <%s>' % (name, email)
276
 
        else:
277
 
            return email
 
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()
278
291
 
279
292
    def signature_checking(self):
280
293
        """What is the current policy for signature checking?."""
342
355
class IniBasedConfig(Config):
343
356
    """A configuration policy that draws from ini files."""
344
357
 
345
 
    def __init__(self, get_filename):
 
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
        """
346
364
        super(IniBasedConfig, self).__init__()
347
 
        self._get_filename = get_filename
 
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
348
377
        self._parser = None
349
378
 
350
 
    def _get_parser(self, file=None):
 
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):
351
402
        if self._parser is not None:
352
403
            return self._parser
353
 
        if file is None:
354
 
            input = self._get_filename()
 
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')
355
414
        else:
356
 
            input = file
 
415
            co_input = self.file_name
357
416
        try:
358
 
            self._parser = ConfigObj(input, encoding='utf-8')
 
417
            self._parser = ConfigObj(co_input, encoding='utf-8')
359
418
        except configobj.ConfigObjError, e:
360
419
            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
361
422
        return self._parser
362
423
 
 
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
 
363
431
    def _get_matching_sections(self):
364
432
        """Return an ordered list of (section_name, extra_path) pairs.
365
433
 
468
536
    def _get_nickname(self):
469
537
        return self.get_user_option('nickname')
470
538
 
471
 
 
472
 
class GlobalConfig(IniBasedConfig):
 
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):
473
616
    """The configuration that should be used for a specific location."""
474
617
 
 
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
 
475
634
    def get_editor(self):
476
635
        return self._get_user_option('editor')
477
636
 
478
 
    def __init__(self):
479
 
        super(GlobalConfig, self).__init__(config_filename)
480
 
 
 
637
    @needs_write_lock
481
638
    def set_user_option(self, option, value):
482
639
        """Save option and its value in the configuration."""
483
640
        self._set_option(option, value, 'DEFAULT')
489
646
        else:
490
647
            return {}
491
648
 
 
649
    @needs_write_lock
492
650
    def set_alias(self, alias_name, alias_command):
493
651
        """Save the alias in the configuration."""
494
652
        self._set_option(alias_name, alias_command, 'ALIASES')
495
653
 
 
654
    @needs_write_lock
496
655
    def unset_alias(self, alias_name):
497
656
        """Unset an existing alias."""
 
657
        self.reload()
498
658
        aliases = self._get_parser().get('ALIASES')
499
659
        if not aliases or alias_name not in aliases:
500
660
            raise errors.NoSuchAlias(alias_name)
502
662
        self._write_config_file()
503
663
 
504
664
    def _set_option(self, option, value, section):
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)
 
665
        self.reload()
509
666
        self._get_parser().setdefault(section, {})[option] = value
510
667
        self._write_config_file()
511
668
 
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):
 
669
 
 
670
class LocationConfig(LockableConfig):
519
671
    """A configuration object that gives the policy for a location."""
520
672
 
521
673
    def __init__(self, location):
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)
 
674
        super(LocationConfig, self).__init__(
 
675
            file_name=locations_config_filename())
534
676
        # local file locations are looked up by local path, rather than
535
677
        # by file url. This is because the config file is a user
536
678
        # file, and we would rather not expose the user to file urls.
538
680
            location = urlutils.local_path_from_url(location)
539
681
        self.location = location
540
682
 
 
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
 
541
698
    def _get_matching_sections(self):
542
699
        """Return an ordered list of section names matching this location."""
543
700
        sections = self._get_parser()
631
788
            if policy_key in self._get_parser()[section]:
632
789
                del self._get_parser()[section][policy_key]
633
790
 
 
791
    @needs_write_lock
634
792
    def set_user_option(self, option, value, store=STORE_LOCATION):
635
793
        """Save option and its value in the configuration."""
636
794
        if store not in [STORE_LOCATION,
638
796
                         STORE_LOCATION_APPENDPATH]:
639
797
            raise ValueError('bad storage policy %r for %r' %
640
798
                (store, option))
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)
 
799
        self.reload()
645
800
        location = self.location
646
801
        if location.endswith('/'):
647
802
            location = location[:-1]
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():
 
803
        parser = self._get_parser()
 
804
        if not location in parser and not location + '/' in parser:
 
805
            parser[location] = {}
 
806
        elif location + '/' in parser:
652
807
            location = location + '/'
653
 
        self._get_parser()[location][option]=value
 
808
        parser[location][option]=value
654
809
        # the allowed values of store match the config policies
655
810
        self._set_option_policy(location, option, store)
656
 
        self._get_parser().write(file(self._get_filename(), 'wb'))
 
811
        self._write_config_file()
657
812
 
658
813
 
659
814
class BranchConfig(Config):
660
815
    """A configuration object giving the policy for a branch."""
661
816
 
 
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
 
662
827
    def _get_branch_data_config(self):
663
828
        if self._branch_data_config is None:
664
829
            self._branch_data_config = TreeConfig(self.branch)
762
927
        """See Config.gpg_signing_command."""
763
928
        return self._get_safe_value('_gpg_signing_command')
764
929
 
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
 
 
775
930
    def _post_commit(self):
776
931
        """See Config.post_commit."""
777
932
        return self._get_safe_value('_post_commit')
810
965
            os.mkdir(parent_dir)
811
966
        trace.mutter('creating config directory: %r', path)
812
967
        os.mkdir(path)
 
968
        osutils.copy_ownership_from_path(path)
813
969
 
814
970
 
815
971
def config_dir():
830
986
                                  ' or HOME set')
831
987
        return osutils.pathjoin(base, 'bazaar', '2.0')
832
988
    else:
833
 
        # cygwin, linux, and darwin all have a $HOME directory
834
989
        if base is None:
835
990
            base = os.path.expanduser("~")
836
991
        return osutils.pathjoin(base, ".bazaar")
841
996
    return osutils.pathjoin(config_dir(), 'bazaar.conf')
842
997
 
843
998
 
844
 
def branches_config_filename():
845
 
    """Return per-user configuration ini file filename."""
846
 
    return osutils.pathjoin(config_dir(), 'branches.conf')
847
 
 
848
 
 
849
999
def locations_config_filename():
850
1000
    """Return per-user configuration ini file filename."""
851
1001
    return osutils.pathjoin(config_dir(), 'locations.conf')
866
1016
 
867
1017
    This doesn't implicitly create it.
868
1018
 
869
 
    On Windows it's in the config directory; elsewhere in the XDG cache directory.
 
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.
870
1022
    """
871
1023
    if sys.platform == 'win32':
872
1024
        return osutils.pathjoin(config_dir(), 'Crash')
873
1025
    else:
874
 
        return osutils.pathjoin(xdg_cache_dir(), 'crash')
 
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')
875
1029
 
876
1030
 
877
1031
def xdg_cache_dir():
884
1038
        return os.path.expanduser('~/.cache')
885
1039
 
886
1040
 
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
 
 
960
1041
def parse_username(username):
961
1042
    """Parse e-mail username and return a (name, address) tuple."""
962
1043
    match = re.match(r'(.*?)\s*<?([\w+.-]+@[\w+.-]+)>?', username)
1048
1129
        """Save the config file, only tests should use it for now."""
1049
1130
        conf_dir = os.path.dirname(self._filename)
1050
1131
        ensure_config_dir_exists(conf_dir)
1051
 
        self._get_config().write(file(self._filename, 'wb'))
 
1132
        f = file(self._filename, 'wb')
 
1133
        try:
 
1134
            self._get_config().write(f)
 
1135
        finally:
 
1136
            f.close()
1052
1137
 
1053
1138
    def _set_option(self, section_name, option_name, value):
1054
1139
        """Set an authentication configuration option"""
1402
1487
 
1403
1488
 
1404
1489
class PlainTextCredentialStore(CredentialStore):
1405
 
    """Plain text credential store for the authentication.conf file."""
 
1490
    __doc__ = """Plain text credential store for the authentication.conf file"""
1406
1491
 
1407
1492
    def decode_password(self, credentials):
1408
1493
        """See CredentialStore.decode_password."""
1502
1587
            return StringIO()
1503
1588
 
1504
1589
    def _get_configobj(self):
1505
 
        return ConfigObj(self._get_config_file(), encoding='utf-8')
 
1590
        f = self._get_config_file()
 
1591
        try:
 
1592
            return ConfigObj(f, encoding='utf-8')
 
1593
        finally:
 
1594
            f.close()
1506
1595
 
1507
1596
    def _set_configobj(self, configobj):
1508
1597
        out_file = StringIO()