Chris@427
|
1 # -*- coding: utf-8 -*-
|
Chris@427
|
2 #
|
Chris@427
|
3 # EasyMercurial
|
Chris@427
|
4 #
|
Chris@427
|
5 # Based on hgExplorer by Jari Korhonen
|
Chris@427
|
6 # Copyright (c) 2010 Jari Korhonen
|
Chris@427
|
7 # Copyright (c) 2010 Chris Cannam
|
Chris@427
|
8 # Copyright (c) 2010 Queen Mary, University of London
|
Chris@427
|
9 #
|
Chris@427
|
10 # This program is free software; you can redistribute it and/or
|
Chris@427
|
11 # modify it under the terms of the GNU General Public License as
|
Chris@427
|
12 # published by the Free Software Foundation; either version 2 of the
|
Chris@427
|
13 # License, or (at your option) any later version. See the file
|
Chris@427
|
14 # COPYING included with this distribution for more information.
|
Chris@427
|
15
|
Chris@427
|
16 import sys
|
Chris@427
|
17
|
Chris@427
|
18 import urllib, urllib2, urlparse
|
Chris@427
|
19
|
Chris@427
|
20 from mercurial import ui, getpass, util
|
Chris@427
|
21 try:
|
Chris@427
|
22 from mercurial.url import passwordmgr
|
Chris@427
|
23 except:
|
Chris@427
|
24 from mercurial.httprepo import passwordmgr
|
Chris@427
|
25
|
Chris@427
|
26 from mercurial.i18n import _
|
Chris@427
|
27
|
Chris@427
|
28 #!!! do this later? as for Qt? also see notes on demandimport in mercurial_keyring
|
Chris@427
|
29 import keyring
|
Chris@427
|
30
|
Chris@427
|
31 # The value assigned here may be modified during installation, by
|
Chris@427
|
32 # replacing its default value with another one. We can't compare
|
Chris@427
|
33 # against its default value, because then the comparison text would
|
Chris@427
|
34 # get modified as well. So, compare using prefix only.
|
Chris@427
|
35 #
|
Chris@427
|
36 easyhg_import_path = 'NO_EASYHG_IMPORT_PATH'
|
Chris@427
|
37 if not easyhg_import_path.startswith('NO_'):
|
Chris@427
|
38 # We have an installation path: append it twice, once with
|
Chris@427
|
39 # the Python version suffixed
|
Chris@427
|
40 version_suffix = "Py" + str(sys.version_info[0]) + "." + str(sys.version_info[1]);
|
Chris@427
|
41 sys.path.append(easyhg_import_path + "/" + version_suffix)
|
Chris@427
|
42 sys.path.append(easyhg_import_path)
|
Chris@427
|
43
|
Chris@427
|
44 # Try to load the PyQt4 module that we need. If this fails, we should
|
Chris@427
|
45 # bail out later (in uisetup), because if we bail out now, Mercurial
|
Chris@427
|
46 # will just continue without us and report success. The invoking
|
Chris@427
|
47 # application needs to be able to discover whether the module load
|
Chris@427
|
48 # succeeded or not, so we need to ensure that Mercurial itself returns
|
Chris@427
|
49 # failure if it didn't.
|
Chris@427
|
50 #
|
Chris@427
|
51 easyhg_pyqt_ok = True
|
Chris@427
|
52 try:
|
Chris@427
|
53 from PyQt4 import Qt, QtGui
|
Chris@427
|
54 except ImportError:
|
Chris@427
|
55 easyhg_pyqt_ok = False
|
Chris@427
|
56
|
Chris@427
|
57 easyhg_qtapp = None
|
Chris@427
|
58
|
Chris@427
|
59 def monkeypatch_method(cls):
|
Chris@427
|
60 def decorator(func):
|
Chris@427
|
61 setattr(cls, func.__name__, func)
|
Chris@427
|
62 return func
|
Chris@427
|
63 return decorator
|
Chris@427
|
64
|
Chris@427
|
65 def uisetup(ui):
|
Chris@427
|
66 if not easyhg_pyqt_ok:
|
Chris@427
|
67 raise util.Abort(_('Failed to load PyQt4 module required by easyhg.py'))
|
Chris@427
|
68 global easyhg_qtapp
|
Chris@427
|
69 easyhg_qtapp = QtGui.QApplication([])
|
Chris@427
|
70
|
Chris@427
|
71 orig_find = passwordmgr.find_user_password
|
Chris@427
|
72
|
Chris@427
|
73 # from mercurial_keyring by Marcin Kasperski
|
Chris@427
|
74 def canonical_url(authuri):
|
Chris@427
|
75 """
|
Chris@427
|
76 Strips query params from url. Used to convert urls like
|
Chris@427
|
77 https://repo.machine.com/repos/apps/module?pairs=0000000000000000000000000000000000000000-0000000000000000000000000000000000000000&cmd=between
|
Chris@427
|
78 to
|
Chris@427
|
79 https://repo.machine.com/repos/apps/module
|
Chris@427
|
80 """
|
Chris@427
|
81 parsed_url = urlparse.urlparse(authuri)
|
Chris@427
|
82 return "%s://%s%s" % (parsed_url.scheme, parsed_url.netloc,
|
Chris@427
|
83 parsed_url.path)
|
Chris@427
|
84
|
Chris@427
|
85 @monkeypatch_method(passwordmgr)
|
Chris@427
|
86 def find_user_password(self, realm, authuri):
|
Chris@427
|
87
|
Chris@427
|
88 if not self.ui.interactive():
|
Chris@427
|
89 return orig_find(self, realm, authuri)
|
Chris@427
|
90 if not easyhg_pyqt_ok:
|
Chris@427
|
91 return orig_find(self, realm, authuri)
|
Chris@427
|
92
|
Chris@427
|
93 authinfo = urllib2.HTTPPasswordMgrWithDefaultRealm.find_user_password(
|
Chris@427
|
94 self, realm, authuri)
|
Chris@427
|
95 user, passwd = authinfo
|
Chris@427
|
96
|
Chris@427
|
97 if user and passwd:
|
Chris@427
|
98 return orig_find(self, realm, authuri)
|
Chris@427
|
99
|
Chris@427
|
100 self.ui.write("want username and/or password for %s\n" % authuri)
|
Chris@427
|
101
|
Chris@427
|
102 uri = canonical_url(authuri)
|
Chris@427
|
103
|
Chris@427
|
104 from_keyring = False
|
Chris@427
|
105 keyring_key = ''
|
Chris@427
|
106 if user and not passwd:
|
Chris@427
|
107 keyring_key = '%s@@%s' % (uri, user)
|
Chris@427
|
108 self.ui.write("keyring_key is %s" % keyring_key)
|
Chris@427
|
109 # passwd = keyring.get_password('Mercurial', keyring_key)
|
Chris@427
|
110 self.ui.write("got passwd: %s\n" % passwd)
|
Chris@427
|
111 if passwd:
|
Chris@427
|
112 from_keyring = True
|
Chris@427
|
113
|
Chris@427
|
114 dialog = QtGui.QDialog()
|
Chris@427
|
115 layout = QtGui.QGridLayout()
|
Chris@427
|
116 dialog.setLayout(layout)
|
Chris@427
|
117
|
Chris@427
|
118 layout.addWidget(QtGui.QLabel(_('Please supply your user name and password for\n%s:') % uri), 0, 0, 1, 2)
|
Chris@427
|
119
|
Chris@427
|
120 userfield = QtGui.QLineEdit()
|
Chris@427
|
121 if user:
|
Chris@427
|
122 userfield.setText(user)
|
Chris@427
|
123 layout.addWidget(QtGui.QLabel(_('User:')), 1, 0)
|
Chris@427
|
124 layout.addWidget(userfield, 1, 1)
|
Chris@427
|
125
|
Chris@427
|
126 passfield = QtGui.QLineEdit()
|
Chris@427
|
127 passfield.setEchoMode(QtGui.QLineEdit.Password)
|
Chris@427
|
128 if passwd:
|
Chris@427
|
129 userfield.setText(passwd)
|
Chris@427
|
130 layout.addWidget(QtGui.QLabel(_('Password:')), 2, 0)
|
Chris@427
|
131 layout.addWidget(passfield, 2, 1)
|
Chris@427
|
132
|
Chris@427
|
133 bb = QtGui.QDialogButtonBox()
|
Chris@427
|
134 ok = bb.addButton(bb.Ok)
|
Chris@427
|
135 cancel = bb.addButton(bb.Cancel)
|
Chris@427
|
136 cancel.setDefault(False)
|
Chris@427
|
137 cancel.setAutoDefault(False)
|
Chris@427
|
138 ok.setDefault(True)
|
Chris@427
|
139 bb.connect(ok, Qt.SIGNAL("clicked()"), dialog, Qt.SLOT("accept()"))
|
Chris@427
|
140 bb.connect(cancel, Qt.SIGNAL("clicked()"), dialog, Qt.SLOT("reject()"))
|
Chris@427
|
141 layout.addWidget(bb, 3, 0, 1, 2)
|
Chris@427
|
142
|
Chris@427
|
143 dialog.setWindowTitle(_('EasyMercurial: Password'))
|
Chris@427
|
144 dialog.show()
|
Chris@427
|
145 dialog.raise_()
|
Chris@427
|
146 ok = dialog.exec_()
|
Chris@427
|
147 if ok:
|
Chris@427
|
148 self.ui.write('Dialog accepted\n')
|
Chris@427
|
149 user = userfield.text()
|
Chris@427
|
150 passwd = passfield.text()
|
Chris@427
|
151 if passwd and keyring_key != '' and not from_keyring:
|
Chris@427
|
152 keyring_key = '%s@@%s' % (uri, user)
|
Chris@427
|
153 keyring.set_password('Mercurial', keyring_key, passwd)
|
Chris@427
|
154 self.add_password(realm, authuri, user, passwd)
|
Chris@427
|
155 else:
|
Chris@427
|
156 raise util.Abort(_('password entry cancelled'))
|
Chris@427
|
157 return (user, passwd)
|
Chris@427
|
158
|
Chris@427
|
159
|
Chris@427
|
160
|