~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/config.py

  • Committer: Alexander Belchenko
  • Date: 2006-10-14 08:51:07 UTC
  • mto: (2080.1.1 jam-integration)
  • mto: This revision was merged to the branch mainline in revision 2081.
  • Revision ID: bialix@ukr.net-20061014085107-8dff865674eed30a
win32 installer: make short info page instead of full GPL license text

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2007 Canonical Ltd
 
1
# Copyright (C) 2005 by Canonical Ltd
2
2
#   Authors: Robert Collins <robert.collins@canonical.com>
3
 
#            and others
4
3
#
5
4
# This program is free software; you can redistribute it and/or modify
6
5
# it under the terms of the GNU General Public License as published by
62
61
up=pull
63
62
"""
64
63
 
65
 
import os
66
 
import sys
67
64
 
68
 
from bzrlib.lazy_import import lazy_import
69
 
lazy_import(globals(), """
70
65
import errno
71
66
from fnmatch import fnmatch
 
67
import os
72
68
import re
73
 
from cStringIO import StringIO
 
69
import sys
 
70
from StringIO import StringIO
74
71
 
75
72
import bzrlib
76
 
from bzrlib import (
77
 
    debug,
78
 
    errors,
79
 
    mail_client,
80
 
    osutils,
81
 
    symbol_versioning,
82
 
    trace,
83
 
    ui,
84
 
    urlutils,
85
 
    win32utils,
86
 
    )
87
 
from bzrlib.util.configobj import configobj
88
 
""")
 
73
from bzrlib import errors, urlutils
 
74
from bzrlib.osutils import pathjoin
 
75
from bzrlib.trace import mutter, warning
 
76
import bzrlib.util.configobj.configobj as configobj
89
77
 
90
78
 
91
79
CHECK_IF_POSSIBLE=0
98
86
SIGN_NEVER=2
99
87
 
100
88
 
101
 
POLICY_NONE = 0
102
 
POLICY_NORECURSE = 1
103
 
POLICY_APPENDPATH = 2
104
 
 
105
 
_policy_name = {
106
 
    POLICY_NONE: None,
107
 
    POLICY_NORECURSE: 'norecurse',
108
 
    POLICY_APPENDPATH: 'appendpath',
109
 
    }
110
 
_policy_value = {
111
 
    None: POLICY_NONE,
112
 
    'none': POLICY_NONE,
113
 
    'norecurse': POLICY_NORECURSE,
114
 
    'appendpath': POLICY_APPENDPATH,
115
 
    }
116
 
 
117
 
 
118
 
STORE_LOCATION = POLICY_NONE
119
 
STORE_LOCATION_NORECURSE = POLICY_NORECURSE
120
 
STORE_LOCATION_APPENDPATH = POLICY_APPENDPATH
121
 
STORE_BRANCH = 3
122
 
STORE_GLOBAL = 4
123
 
 
124
 
 
125
89
class ConfigObj(configobj.ConfigObj):
126
90
 
127
91
    def get_bool(self, section, key):
144
108
        """Get the users pop up editor."""
145
109
        raise NotImplementedError
146
110
 
147
 
    def get_mail_client(self):
148
 
        """Get a mail client to use"""
149
 
        selected_client = self.get_user_option('mail_client')
150
 
        try:
151
 
            mail_client_class = {
152
 
                None: mail_client.DefaultMail,
153
 
                # Specific clients
154
 
                'evolution': mail_client.Evolution,
155
 
                'kmail': mail_client.KMail,
156
 
                'mutt': mail_client.Mutt,
157
 
                'thunderbird': mail_client.Thunderbird,
158
 
                # Generic options
159
 
                'default': mail_client.DefaultMail,
160
 
                'editor': mail_client.Editor,
161
 
                'mapi': mail_client.MAPIClient,
162
 
                'xdg-email': mail_client.XDGEmail,
163
 
            }[selected_client]
164
 
        except KeyError:
165
 
            raise errors.UnknownMailClient(selected_client)
166
 
        return mail_client_class(self)
167
 
 
168
111
    def _get_signature_checking(self):
169
112
        """Template method to override signature checking policy."""
170
113
 
236
179
        v = os.environ.get('BZR_EMAIL')
237
180
        if v:
238
181
            return v.decode(bzrlib.user_encoding)
239
 
 
 
182
        v = os.environ.get('BZREMAIL')
 
183
        if v:
 
184
            warning('BZREMAIL is deprecated in favor of BZR_EMAIL. Please update your configuration.')
 
185
            return v.decode(bzrlib.user_encoding)
 
186
    
240
187
        v = self._get_user_id()
241
188
        if v:
242
189
            return v
243
 
 
 
190
        
244
191
        v = os.environ.get('EMAIL')
245
192
        if v:
246
193
            return v.decode(bzrlib.user_encoding)
271
218
        if policy is None:
272
219
            policy = self._get_signature_checking()
273
220
            if policy is not None:
274
 
                trace.warning("Please use create_signatures,"
275
 
                              " not check_signatures to set signing policy.")
 
221
                warning("Please use create_signatures, not check_signatures "
 
222
                        "to set signing policy.")
276
223
            if policy == CHECK_ALWAYS:
277
224
                return True
278
225
        elif policy == SIGN_ALWAYS:
291
238
    def _get_nickname(self):
292
239
        return None
293
240
 
294
 
    def get_bzr_remote_path(self):
295
 
        try:
296
 
            return os.environ['BZR_REMOTE_PATH']
297
 
        except KeyError:
298
 
            path = self.get_user_option("bzr_remote_path")
299
 
            if path is None:
300
 
                path = 'bzr'
301
 
            return path
302
 
 
303
241
 
304
242
class IniBasedConfig(Config):
305
243
    """A configuration policy that draws from ini files."""
317
255
            raise errors.ParseConfigError(e.errors, e.config.filename)
318
256
        return self._parser
319
257
 
320
 
    def _get_matching_sections(self):
321
 
        """Return an ordered list of (section_name, extra_path) pairs.
322
 
 
323
 
        If the section contains inherited configuration, extra_path is
324
 
        a string containing the additional path components.
325
 
        """
326
 
        section = self._get_section()
327
 
        if section is not None:
328
 
            return [(section, '')]
329
 
        else:
330
 
            return []
331
 
 
332
258
    def _get_section(self):
333
259
        """Override this to define the section used by the config."""
334
260
        return "DEFAULT"
335
261
 
336
 
    def _get_option_policy(self, section, option_name):
337
 
        """Return the policy for the given (section, option_name) pair."""
338
 
        return POLICY_NONE
339
 
 
340
262
    def _get_signature_checking(self):
341
263
        """See Config._get_signature_checking."""
342
264
        policy = self._get_user_option('check_signatures')
355
277
 
356
278
    def _get_user_option(self, option_name):
357
279
        """See Config._get_user_option."""
358
 
        for (section, extra_path) in self._get_matching_sections():
359
 
            try:
360
 
                value = self._get_parser().get_value(section, option_name)
361
 
            except KeyError:
362
 
                continue
363
 
            policy = self._get_option_policy(section, option_name)
364
 
            if policy == POLICY_NONE:
365
 
                return value
366
 
            elif policy == POLICY_NORECURSE:
367
 
                # norecurse items only apply to the exact path
368
 
                if extra_path:
369
 
                    continue
370
 
                else:
371
 
                    return value
372
 
            elif policy == POLICY_APPENDPATH:
373
 
                if extra_path:
374
 
                    value = urlutils.join(value, extra_path)
375
 
                return value
376
 
            else:
377
 
                raise AssertionError('Unexpected config policy %r' % policy)
378
 
        else:
379
 
            return None
 
280
        try:
 
281
            return self._get_parser().get_value(self._get_section(),
 
282
                                                option_name)
 
283
        except KeyError:
 
284
            pass
380
285
 
381
286
    def _gpg_signing_command(self):
382
287
        """See Config.gpg_signing_command."""
456
361
 
457
362
    def __init__(self, location):
458
363
        name_generator = locations_config_filename
459
 
        if (not os.path.exists(name_generator()) and
 
364
        if (not os.path.exists(name_generator()) and 
460
365
                os.path.exists(branches_config_filename())):
461
366
            if sys.platform == 'win32':
462
 
                trace.warning('Please rename %s to %s'
463
 
                              % (branches_config_filename(),
464
 
                                 locations_config_filename()))
 
367
                warning('Please rename %s to %s' 
 
368
                         % (branches_config_filename(),
 
369
                            locations_config_filename()))
465
370
            else:
466
 
                trace.warning('Please rename ~/.bazaar/branches.conf'
467
 
                              ' to ~/.bazaar/locations.conf')
 
371
                warning('Please rename ~/.bazaar/branches.conf'
 
372
                        ' to ~/.bazaar/locations.conf')
468
373
            name_generator = branches_config_filename
469
374
        super(LocationConfig, self).__init__(name_generator)
470
375
        # local file locations are looked up by local path, rather than
474
379
            location = urlutils.local_path_from_url(location)
475
380
        self.location = location
476
381
 
477
 
    def _get_matching_sections(self):
478
 
        """Return an ordered list of section names matching this location."""
 
382
    def _get_section(self):
 
383
        """Get the section we should look in for config items.
 
384
 
 
385
        Returns None if none exists. 
 
386
        TODO: perhaps return a NullSection that thunks through to the 
 
387
              global config.
 
388
        """
479
389
        sections = self._get_parser()
480
390
        location_names = self.location.split('/')
481
391
        if self.location.endswith('/'):
505
415
            # if section is longer, no match.
506
416
            if len(section_names) > len(location_names):
507
417
                continue
508
 
            matches.append((len(section_names), section,
509
 
                            '/'.join(location_names[len(section_names):])))
 
418
            # if path is longer, and recurse is not true, no match
 
419
            if len(section_names) < len(location_names):
 
420
                try:
 
421
                    if not self._get_parser()[section].as_bool('recurse'):
 
422
                        continue
 
423
                except KeyError:
 
424
                    pass
 
425
            matches.append((len(section_names), section))
 
426
        if not len(matches):
 
427
            return None
510
428
        matches.sort(reverse=True)
511
 
        sections = []
512
 
        for (length, section, extra_path) in matches:
513
 
            sections.append((section, extra_path))
514
 
            # should we stop looking for parent configs here?
515
 
            try:
516
 
                if self._get_parser()[section].as_bool('ignore_parents'):
517
 
                    break
518
 
            except KeyError:
519
 
                pass
520
 
        return sections
521
 
 
522
 
    def _get_option_policy(self, section, option_name):
523
 
        """Return the policy for the given (section, option_name) pair."""
524
 
        # check for the old 'recurse=False' flag
525
 
        try:
526
 
            recurse = self._get_parser()[section].as_bool('recurse')
527
 
        except KeyError:
528
 
            recurse = True
529
 
        if not recurse:
530
 
            return POLICY_NORECURSE
531
 
 
532
 
        policy_key = option_name + ':policy'
533
 
        try:
534
 
            policy_name = self._get_parser()[section][policy_key]
535
 
        except KeyError:
536
 
            policy_name = None
537
 
 
538
 
        return _policy_value[policy_name]
539
 
 
540
 
    def _set_option_policy(self, section, option_name, option_policy):
541
 
        """Set the policy for the given option name in the given section."""
542
 
        # The old recurse=False option affects all options in the
543
 
        # section.  To handle multiple policies in the section, we
544
 
        # need to convert it to a policy_norecurse key.
545
 
        try:
546
 
            recurse = self._get_parser()[section].as_bool('recurse')
547
 
        except KeyError:
548
 
            pass
549
 
        else:
550
 
            symbol_versioning.warn(
551
 
                'The recurse option is deprecated as of 0.14.  '
552
 
                'The section "%s" has been converted to use policies.'
553
 
                % section,
554
 
                DeprecationWarning)
555
 
            del self._get_parser()[section]['recurse']
556
 
            if not recurse:
557
 
                for key in self._get_parser()[section].keys():
558
 
                    if not key.endswith(':policy'):
559
 
                        self._get_parser()[section][key +
560
 
                                                    ':policy'] = 'norecurse'
561
 
 
562
 
        policy_key = option_name + ':policy'
563
 
        policy_name = _policy_name[option_policy]
564
 
        if policy_name is not None:
565
 
            self._get_parser()[section][policy_key] = policy_name
566
 
        else:
567
 
            if policy_key in self._get_parser()[section]:
568
 
                del self._get_parser()[section][policy_key]
569
 
 
570
 
    def set_user_option(self, option, value, store=STORE_LOCATION):
 
429
        return matches[0][1]
 
430
 
 
431
    def set_user_option(self, option, value):
571
432
        """Save option and its value in the configuration."""
572
 
        assert store in [STORE_LOCATION,
573
 
                         STORE_LOCATION_NORECURSE,
574
 
                         STORE_LOCATION_APPENDPATH], 'bad storage policy'
575
433
        # FIXME: RBC 20051029 This should refresh the parser and also take a
576
434
        # file lock on locations.conf.
577
435
        conf_dir = os.path.dirname(self._get_filename())
585
443
        elif location + '/' in self._get_parser():
586
444
            location = location + '/'
587
445
        self._get_parser()[location][option]=value
588
 
        # the allowed values of store match the config policies
589
 
        self._set_option_policy(location, option, store)
590
446
        self._get_parser().write(file(self._get_filename(), 'wb'))
591
447
 
592
448
 
667
523
                return value
668
524
        return None
669
525
 
670
 
    def set_user_option(self, name, value, store=STORE_BRANCH,
671
 
        warn_masked=False):
672
 
        if store == STORE_BRANCH:
 
526
    def set_user_option(self, name, value, local=False):
 
527
        if local is True:
 
528
            self._get_location_config().set_user_option(name, value)
 
529
        else:
673
530
            self._get_branch_data_config().set_option(value, name)
674
 
        elif store == STORE_GLOBAL:
675
 
            self._get_global_config().set_user_option(name, value)
676
 
        else:
677
 
            self._get_location_config().set_user_option(name, value, store)
678
 
        if not warn_masked:
679
 
            return
680
 
        if store in (STORE_GLOBAL, STORE_BRANCH):
681
 
            mask_value = self._get_location_config().get_user_option(name)
682
 
            if mask_value is not None:
683
 
                trace.warning('Value "%s" is masked by "%s" from'
684
 
                              ' locations.conf', value, mask_value)
685
 
            else:
686
 
                if store == STORE_GLOBAL:
687
 
                    branch_config = self._get_branch_data_config()
688
 
                    mask_value = branch_config.get_user_option(name)
689
 
                    if mask_value is not None:
690
 
                        trace.warning('Value "%s" is masked by "%s" from'
691
 
                                      ' branch.conf', value, mask_value)
692
531
 
693
532
 
694
533
    def _gpg_signing_command(self):
713
552
        value = self._get_explicit_nickname()
714
553
        if value is not None:
715
554
            return value
716
 
        return urlutils.unescape(self.branch.base.split('/')[-2])
 
555
        return self.branch.base.split('/')[-2]
717
556
 
718
557
    def has_explicit_nickname(self):
719
558
        """Return true if a nickname has been explicitly assigned."""
739
578
        if sys.platform == 'win32':
740
579
            parent_dir = os.path.dirname(path)
741
580
            if not os.path.isdir(parent_dir):
742
 
                trace.mutter('creating config parent directory: %r', parent_dir)
 
581
                mutter('creating config parent directory: %r', parent_dir)
743
582
            os.mkdir(parent_dir)
744
 
        trace.mutter('creating config directory: %r', path)
 
583
        mutter('creating config directory: %r', path)
745
584
        os.mkdir(path)
746
585
 
747
586
 
755
594
    base = os.environ.get('BZR_HOME', None)
756
595
    if sys.platform == 'win32':
757
596
        if base is None:
758
 
            base = win32utils.get_appdata_location_unicode()
 
597
            base = os.environ.get('APPDATA', None)
759
598
        if base is None:
760
599
            base = os.environ.get('HOME', None)
761
600
        if base is None:
762
 
            raise errors.BzrError('You must have one of BZR_HOME, APPDATA,'
763
 
                                  ' or HOME set')
764
 
        return osutils.pathjoin(base, 'bazaar', '2.0')
 
601
            raise errors.BzrError('You must have one of BZR_HOME, APPDATA, or HOME set')
 
602
        return pathjoin(base, 'bazaar', '2.0')
765
603
    else:
766
604
        # cygwin, linux, and darwin all have a $HOME directory
767
605
        if base is None:
768
606
            base = os.path.expanduser("~")
769
 
        return osutils.pathjoin(base, ".bazaar")
 
607
        return pathjoin(base, ".bazaar")
770
608
 
771
609
 
772
610
def config_filename():
773
611
    """Return per-user configuration ini file filename."""
774
 
    return osutils.pathjoin(config_dir(), 'bazaar.conf')
 
612
    return pathjoin(config_dir(), 'bazaar.conf')
775
613
 
776
614
 
777
615
def branches_config_filename():
778
616
    """Return per-user configuration ini file filename."""
779
 
    return osutils.pathjoin(config_dir(), 'branches.conf')
 
617
    return pathjoin(config_dir(), 'branches.conf')
780
618
 
781
619
 
782
620
def locations_config_filename():
783
621
    """Return per-user configuration ini file filename."""
784
 
    return osutils.pathjoin(config_dir(), 'locations.conf')
785
 
 
786
 
 
787
 
def authentication_config_filename():
788
 
    """Return per-user authentication ini file filename."""
789
 
    return osutils.pathjoin(config_dir(), 'authentication.conf')
 
622
    return pathjoin(config_dir(), 'locations.conf')
790
623
 
791
624
 
792
625
def user_ignore_config_filename():
793
626
    """Return the user default ignore filename"""
794
 
    return osutils.pathjoin(config_dir(), 'ignore')
 
627
    return pathjoin(config_dir(), 'ignore')
795
628
 
796
629
 
797
630
def _auto_user_id():
807
640
    """
808
641
    import socket
809
642
 
810
 
    if sys.platform == 'win32':
811
 
        name = win32utils.get_user_name_unicode()
812
 
        if name is None:
813
 
            raise errors.BzrError("Cannot autodetect user name.\n"
814
 
                                  "Please, set your name with command like:\n"
815
 
                                  'bzr whoami "Your Name <name@domain.com>"')
816
 
        host = win32utils.get_host_name_unicode()
817
 
        if host is None:
818
 
            host = socket.gethostname()
819
 
        return name, (name + '@' + host)
 
643
    # XXX: Any good way to get real user name on win32?
820
644
 
821
645
    try:
822
646
        import pwd
862
686
    return realname, (username + '@' + socket.gethostname())
863
687
 
864
688
 
865
 
def parse_username(username):
866
 
    """Parse e-mail username and return a (name, address) tuple."""
867
 
    match = re.match(r'(.*?)\s*<?([\w+.-]+@[\w+.-]+)>?', username)
868
 
    if match is None:
869
 
        return (username, '')
870
 
    else:
871
 
        return (match.group(1), match.group(2))
872
 
 
873
 
 
874
689
def extract_email_address(e):
875
690
    """Return just the address part of an email string.
876
 
 
 
691
    
877
692
    That is just the user@domain part, nothing else. 
878
693
    This part is required to contain only ascii characters.
879
694
    If it can't be extracted, raises an error.
880
 
 
 
695
    
881
696
    >>> extract_email_address('Jane Tester <jane@test.com>')
882
697
    "jane@test.com"
883
698
    """
884
 
    name, email = parse_username(e)
885
 
    if not email:
 
699
    m = re.search(r'[\w+.-]+@[\w+.-]+', e)
 
700
    if not m:
886
701
        raise errors.NoEmailInUsername(e)
887
 
    return email
 
702
    return m.group(0)
888
703
 
889
704
 
890
705
class TreeConfig(IniBasedConfig):
891
706
    """Branch configuration data associated with its contents, not location"""
892
 
 
893
707
    def __init__(self, branch):
894
708
        self.branch = branch
895
709
 
900
714
 
901
715
    def _get_config(self):
902
716
        try:
903
 
            obj = ConfigObj(self.branch.control_files.get('branch.conf'),
 
717
            obj = ConfigObj(self.branch.control_files.get('branch.conf'), 
904
718
                            encoding='utf-8')
905
719
        except errors.NoSuchFile:
906
720
            obj = ConfigObj(encoding='utf=8')
912
726
            obj = self._get_config()
913
727
            try:
914
728
                if section is not None:
915
 
                    obj = obj[section]
 
729
                    obj[section]
916
730
                result = obj[name]
917
731
            except KeyError:
918
732
                result = default
940
754
            self.branch.control_files.put('branch.conf', out_file)
941
755
        finally:
942
756
            self.branch.unlock()
943
 
 
944
 
 
945
 
class AuthenticationConfig(object):
946
 
    """The authentication configuration file based on a ini file.
947
 
 
948
 
    Implements the authentication.conf file described in
949
 
    doc/developers/authentication-ring.txt.
950
 
    """
951
 
 
952
 
    def __init__(self, _file=None):
953
 
        self._config = None # The ConfigObj
954
 
        if _file is None:
955
 
            self._filename = authentication_config_filename()
956
 
            self._input = self._filename = authentication_config_filename()
957
 
        else:
958
 
            # Tests can provide a string as _file
959
 
            self._filename = None
960
 
            self._input = _file
961
 
 
962
 
    def _get_config(self):
963
 
        if self._config is not None:
964
 
            return self._config
965
 
        try:
966
 
            # FIXME: Should we validate something here ? Includes: empty
967
 
            # sections are useless, at least one of
968
 
            # user/password/password_encoding should be defined, etc.
969
 
 
970
 
            # Note: the encoding below declares that the file itself is utf-8
971
 
            # encoded, but the values in the ConfigObj are always Unicode.
972
 
            self._config = ConfigObj(self._input, encoding='utf-8')
973
 
        except configobj.ConfigObjError, e:
974
 
            raise errors.ParseConfigError(e.errors, e.config.filename)
975
 
        return self._config
976
 
 
977
 
    def _save(self):
978
 
        """Save the config file, only tests should use it for now."""
979
 
        conf_dir = os.path.dirname(self._filename)
980
 
        ensure_config_dir_exists(conf_dir)
981
 
        self._get_config().write(file(self._filename, 'wb'))
982
 
 
983
 
    def _set_option(self, section_name, option_name, value):
984
 
        """Set an authentication configuration option"""
985
 
        conf = self._get_config()
986
 
        section = conf.get(section_name)
987
 
        if section is None:
988
 
            conf[section] = {}
989
 
            section = conf[section]
990
 
        section[option_name] = value
991
 
        self._save()
992
 
 
993
 
    def get_credentials(self, scheme, host, port=None, user=None, path=None):
994
 
        """Returns the matching credentials from authentication.conf file.
995
 
 
996
 
        :param scheme: protocol
997
 
 
998
 
        :param host: the server address
999
 
 
1000
 
        :param port: the associated port (optional)
1001
 
 
1002
 
        :param user: login (optional)
1003
 
 
1004
 
        :param path: the absolute path on the server (optional)
1005
 
 
1006
 
        :return: A dict containing the matching credentials or None.
1007
 
           This includes:
1008
 
           - name: the section name of the credentials in the
1009
 
             authentication.conf file,
1010
 
           - user: can't de different from the provided user if any,
1011
 
           - password: the decoded password, could be None if the credential
1012
 
             defines only the user
1013
 
           - verify_certificates: https specific, True if the server
1014
 
             certificate should be verified, False otherwise.
1015
 
        """
1016
 
        credentials = None
1017
 
        for auth_def_name, auth_def in self._get_config().items():
1018
 
            a_scheme, a_host, a_user, a_path = map(
1019
 
                auth_def.get, ['scheme', 'host', 'user', 'path'])
1020
 
 
1021
 
            try:
1022
 
                a_port = auth_def.as_int('port')
1023
 
            except KeyError:
1024
 
                a_port = None
1025
 
            except ValueError:
1026
 
                raise ValueError("'port' not numeric in %s" % auth_def_name)
1027
 
            try:
1028
 
                a_verify_certificates = auth_def.as_bool('verify_certificates')
1029
 
            except KeyError:
1030
 
                a_verify_certificates = True
1031
 
            except ValueError:
1032
 
                raise ValueError(
1033
 
                    "'verify_certificates' not boolean in %s" % auth_def_name)
1034
 
 
1035
 
            # Attempt matching
1036
 
            if a_scheme is not None and scheme != a_scheme:
1037
 
                continue
1038
 
            if a_host is not None:
1039
 
                if not (host == a_host
1040
 
                        or (a_host.startswith('.') and host.endswith(a_host))):
1041
 
                    continue
1042
 
            if a_port is not None and port != a_port:
1043
 
                continue
1044
 
            if (a_path is not None and path is not None
1045
 
                and not path.startswith(a_path)):
1046
 
                continue
1047
 
            if (a_user is not None and user is not None
1048
 
                and a_user != user):
1049
 
                # Never contradict the caller about the user to be used
1050
 
                continue
1051
 
            if a_user is None:
1052
 
                # Can't find a user
1053
 
                continue
1054
 
            credentials = dict(name=auth_def_name,
1055
 
                               user=a_user, password=auth_def['password'],
1056
 
                               verify_certificates=a_verify_certificates)
1057
 
            self.decode_password(credentials,
1058
 
                                 auth_def.get('password_encoding', None))
1059
 
            if 'auth' in debug.debug_flags:
1060
 
                trace.mutter("Using authentication section: %r", auth_def_name)
1061
 
            break
1062
 
 
1063
 
        return credentials
1064
 
 
1065
 
    def get_user(self, scheme, host, port=None,
1066
 
                 realm=None, path=None, prompt=None):
1067
 
        """Get a user from authentication file.
1068
 
 
1069
 
        :param scheme: protocol
1070
 
 
1071
 
        :param host: the server address
1072
 
 
1073
 
        :param port: the associated port (optional)
1074
 
 
1075
 
        :param realm: the realm sent by the server (optional)
1076
 
 
1077
 
        :param path: the absolute path on the server (optional)
1078
 
 
1079
 
        :return: The found user.
1080
 
        """
1081
 
        credentials = self.get_credentials(scheme, host, port, user=None,
1082
 
                                           path=path)
1083
 
        if credentials is not None:
1084
 
            user = credentials['user']
1085
 
        else:
1086
 
            user = None
1087
 
        return user
1088
 
 
1089
 
    def get_password(self, scheme, host, user, port=None,
1090
 
                     realm=None, path=None, prompt=None):
1091
 
        """Get a password from authentication file or prompt the user for one.
1092
 
 
1093
 
        :param scheme: protocol
1094
 
 
1095
 
        :param host: the server address
1096
 
 
1097
 
        :param port: the associated port (optional)
1098
 
 
1099
 
        :param user: login
1100
 
 
1101
 
        :param realm: the realm sent by the server (optional)
1102
 
 
1103
 
        :param path: the absolute path on the server (optional)
1104
 
 
1105
 
        :return: The found password or the one entered by the user.
1106
 
        """
1107
 
        credentials = self.get_credentials(scheme, host, port, user, path)
1108
 
        if credentials is not None:
1109
 
            password = credentials['password']
1110
 
        else:
1111
 
            password = None
1112
 
        # Prompt user only if we could't find a password
1113
 
        if password is None:
1114
 
            if prompt is None:
1115
 
                # Create a default prompt suitable for most of the cases
1116
 
                prompt = '%s' % scheme.upper() + ' %(user)s@%(host)s password'
1117
 
            # Special handling for optional fields in the prompt
1118
 
            if port is not None:
1119
 
                prompt_host = '%s:%d' % (host, port)
1120
 
            else:
1121
 
                prompt_host = host
1122
 
            password = ui.ui_factory.get_password(prompt,
1123
 
                                                  host=prompt_host, user=user)
1124
 
        return password
1125
 
 
1126
 
    def decode_password(self, credentials, encoding):
1127
 
        return credentials