summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--git_command.py128
-rwxr-xr-xmain.py6
-rw-r--r--tests/test_git_command.py18
3 files changed, 95 insertions, 57 deletions
diff --git a/git_command.py b/git_command.py
index 32dcde09..a4081f45 100644
--- a/git_command.py
+++ b/git_command.py
@@ -22,6 +22,7 @@ import tempfile
22from signal import SIGTERM 22from signal import SIGTERM
23 23
24from error import GitError 24from error import GitError
25from git_refs import HEAD
25import platform_utils 26import platform_utils
26from repo_trace import REPO_TRACE, IsTrace, Trace 27from repo_trace import REPO_TRACE, IsTrace, Trace
27from wrapper import Wrapper 28from wrapper import Wrapper
@@ -99,50 +100,72 @@ class _GitCall(object):
99git = _GitCall() 100git = _GitCall()
100 101
101 102
102_user_agent = None 103def RepoSourceVersion():
104 """Return the version of the repo.git tree."""
105 ver = getattr(RepoSourceVersion, 'version', None)
103 106
104def RepoUserAgent(): 107 # We avoid GitCommand so we don't run into circular deps -- GitCommand needs
105 """Return a User-Agent string suitable for HTTP-like services. 108 # to initialize version info we provide.
109 if ver is None:
110 env = GitCommand._GetBasicEnv()
106 111
107 We follow the style as documented here: 112 proj = os.path.dirname(os.path.abspath(__file__))
108 https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent 113 env[GIT_DIR] = os.path.join(proj, '.git')
109 """ 114
110 global _user_agent 115 p = subprocess.Popen([GIT, 'describe', HEAD], stdout=subprocess.PIPE,
111 116 env=env)
112 if _user_agent is None: 117 if p.wait() == 0:
113 py_version = sys.version_info 118 ver = p.stdout.read().strip().decode('utf-8')
114 119 if ver.startswith('v'):
115 os_name = sys.platform 120 ver = ver[1:]
116 if os_name == 'linux2':
117 os_name = 'Linux'
118 elif os_name == 'win32':
119 os_name = 'Win32'
120 elif os_name == 'cygwin':
121 os_name = 'Cygwin'
122 elif os_name == 'darwin':
123 os_name = 'Darwin'
124
125 p = GitCommand(
126 None, ['describe', 'HEAD'],
127 cwd=os.path.dirname(__file__),
128 capture_stdout=True)
129 if p.Wait() == 0:
130 repo_version = p.stdout
131 if repo_version and repo_version[-1] == '\n':
132 repo_version = repo_version[0:-1]
133 if repo_version and repo_version[0] == 'v':
134 repo_version = repo_version[1:]
135 else: 121 else:
136 repo_version = 'unknown' 122 ver = 'unknown'
123 setattr(RepoSourceVersion, 'version', ver)
137 124
138 _user_agent = 'git-repo/%s (%s) git/%s Python/%d.%d.%d' % ( 125 return ver
139 repo_version,
140 os_name,
141 git.version_tuple().full,
142 py_version.major, py_version.minor, py_version.micro)
143 126
144 return _user_agent
145 127
128class UserAgent(object):
129 """Mange User-Agent settings when talking to external services
130
131 We follow the style as documented here:
132 https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent
133 """
134
135 _os = None
136 _repo_ua = None
137
138 @property
139 def os(self):
140 """The operating system name."""
141 if self._os is None:
142 os_name = sys.platform
143 if os_name.lower().startswith('linux'):
144 os_name = 'Linux'
145 elif os_name == 'win32':
146 os_name = 'Win32'
147 elif os_name == 'cygwin':
148 os_name = 'Cygwin'
149 elif os_name == 'darwin':
150 os_name = 'Darwin'
151 self._os = os_name
152
153 return self._os
154
155 @property
156 def repo(self):
157 """The UA when connecting directly from repo."""
158 if self._repo_ua is None:
159 py_version = sys.version_info
160 self._repo_ua = 'git-repo/%s (%s) git/%s Python/%d.%d.%d' % (
161 RepoSourceVersion(),
162 self.os,
163 git.version_tuple().full,
164 py_version.major, py_version.minor, py_version.micro)
165
166 return self._repo_ua
167
168user_agent = UserAgent()
146 169
147def git_require(min_version, fail=False, msg=''): 170def git_require(min_version, fail=False, msg=''):
148 git_version = git.version_tuple() 171 git_version = git.version_tuple()
@@ -171,17 +194,7 @@ class GitCommand(object):
171 ssh_proxy = False, 194 ssh_proxy = False,
172 cwd = None, 195 cwd = None,
173 gitdir = None): 196 gitdir = None):
174 env = os.environ.copy() 197 env = self._GetBasicEnv()
175
176 for key in [REPO_TRACE,
177 GIT_DIR,
178 'GIT_ALTERNATE_OBJECT_DIRECTORIES',
179 'GIT_OBJECT_DIRECTORY',
180 'GIT_WORK_TREE',
181 'GIT_GRAFT_FILE',
182 'GIT_INDEX_FILE']:
183 if key in env:
184 del env[key]
185 198
186 # If we are not capturing std* then need to print it. 199 # If we are not capturing std* then need to print it.
187 self.tee = {'stdout': not capture_stdout, 'stderr': not capture_stderr} 200 self.tee = {'stdout': not capture_stdout, 'stderr': not capture_stderr}
@@ -273,6 +286,23 @@ class GitCommand(object):
273 self.process = p 286 self.process = p
274 self.stdin = p.stdin 287 self.stdin = p.stdin
275 288
289 @staticmethod
290 def _GetBasicEnv():
291 """Return a basic env for running git under.
292
293 This is guaranteed to be side-effect free.
294 """
295 env = os.environ.copy()
296 for key in (REPO_TRACE,
297 GIT_DIR,
298 'GIT_ALTERNATE_OBJECT_DIRECTORIES',
299 'GIT_OBJECT_DIRECTORY',
300 'GIT_WORK_TREE',
301 'GIT_GRAFT_FILE',
302 'GIT_INDEX_FILE'):
303 env.pop(key, None)
304 return env
305
276 def Wait(self): 306 def Wait(self):
277 try: 307 try:
278 p = self.process 308 p = self.process
diff --git a/main.py b/main.py
index 0b19aeb5..515cdf47 100755
--- a/main.py
+++ b/main.py
@@ -46,7 +46,7 @@ except ImportError:
46from color import SetDefaultColoring 46from color import SetDefaultColoring
47import event_log 47import event_log
48from repo_trace import SetTrace 48from repo_trace import SetTrace
49from git_command import git, GitCommand, RepoUserAgent 49from git_command import git, GitCommand, user_agent
50from git_config import init_ssh, close_ssh 50from git_config import init_ssh, close_ssh
51from command import InteractiveCommand 51from command import InteractiveCommand
52from command import MirrorSafeCommand 52from command import MirrorSafeCommand
@@ -297,11 +297,11 @@ def _PruneOptions(argv, opt):
297 297
298class _UserAgentHandler(urllib.request.BaseHandler): 298class _UserAgentHandler(urllib.request.BaseHandler):
299 def http_request(self, req): 299 def http_request(self, req):
300 req.add_header('User-Agent', RepoUserAgent()) 300 req.add_header('User-Agent', user_agent.repo)
301 return req 301 return req
302 302
303 def https_request(self, req): 303 def https_request(self, req):
304 req.add_header('User-Agent', RepoUserAgent()) 304 req.add_header('User-Agent', user_agent.repo)
305 return req 305 return req
306 306
307def _AddPasswordFromUserInput(handler, msg, req): 307def _AddPasswordFromUserInput(handler, msg, req):
diff --git a/tests/test_git_command.py b/tests/test_git_command.py
index 4d65d3ce..5ceb0b33 100644
--- a/tests/test_git_command.py
+++ b/tests/test_git_command.py
@@ -50,12 +50,20 @@ class GitCallUnitTest(unittest.TestCase):
50 self.assertNotEqual('', ver.full) 50 self.assertNotEqual('', ver.full)
51 51
52 52
53class RepoUserAgentUnitTest(unittest.TestCase): 53class UserAgentUnitTest(unittest.TestCase):
54 """Tests the RepoUserAgent function.""" 54 """Tests the UserAgent function."""
55 55
56 def test_smoke(self): 56 def test_smoke_os(self):
57 """Make sure it returns something useful.""" 57 """Make sure UA OS setting returns something useful."""
58 ua = git_command.RepoUserAgent() 58 os_name = git_command.user_agent.os
59 # We can't dive too deep because of OS/tool differences, but we can check
60 # the general form.
61 m = re.match(r'^[^ ]+$', os_name)
62 self.assertIsNotNone(m)
63
64 def test_smoke_repo(self):
65 """Make sure repo UA returns something useful."""
66 ua = git_command.user_agent.repo
59 # We can't dive too deep because of OS/tool differences, but we can check 67 # We can't dive too deep because of OS/tool differences, but we can check
60 # the general form. 68 # the general form.
61 m = re.match(r'^git-repo/[^ ]+ ([^ ]+) git/[^ ]+ Python/[0-9.]+', ua) 69 m = re.match(r'^git-repo/[^ ]+ ([^ ]+) git/[^ ]+ Python/[0-9.]+', ua)