diff options
| -rw-r--r-- | git_command.py | 85 | ||||
| -rw-r--r-- | tests/test_git_command.py | 33 |
2 files changed, 89 insertions, 29 deletions
diff --git a/git_command.py b/git_command.py index 01b9ecb3..3a3bb34d 100644 --- a/git_command.py +++ b/git_command.py | |||
| @@ -16,6 +16,7 @@ import functools | |||
| 16 | import os | 16 | import os |
| 17 | import sys | 17 | import sys |
| 18 | import subprocess | 18 | import subprocess |
| 19 | from typing import Any, Optional | ||
| 19 | 20 | ||
| 20 | from error import GitError | 21 | from error import GitError |
| 21 | from git_refs import HEAD | 22 | from git_refs import HEAD |
| @@ -157,6 +158,53 @@ def git_require(min_version, fail=False, msg=''): | |||
| 157 | return False | 158 | return False |
| 158 | 159 | ||
| 159 | 160 | ||
| 161 | def _build_env( | ||
| 162 | _kwargs_only=(), | ||
| 163 | bare: Optional[bool] = False, | ||
| 164 | disable_editor: Optional[bool] = False, | ||
| 165 | ssh_proxy: Optional[Any] = None, | ||
| 166 | gitdir: Optional[str] = None, | ||
| 167 | objdir: Optional[str] = None | ||
| 168 | ): | ||
| 169 | """Constucts an env dict for command execution.""" | ||
| 170 | |||
| 171 | assert _kwargs_only == (), '_build_env only accepts keyword arguments.' | ||
| 172 | |||
| 173 | env = GitCommand._GetBasicEnv() | ||
| 174 | |||
| 175 | if disable_editor: | ||
| 176 | env['GIT_EDITOR'] = ':' | ||
| 177 | if ssh_proxy: | ||
| 178 | env['REPO_SSH_SOCK'] = ssh_proxy.sock() | ||
| 179 | env['GIT_SSH'] = ssh_proxy.proxy | ||
| 180 | env['GIT_SSH_VARIANT'] = 'ssh' | ||
| 181 | if 'http_proxy' in env and 'darwin' == sys.platform: | ||
| 182 | s = "'http.proxy=%s'" % (env['http_proxy'],) | ||
| 183 | p = env.get('GIT_CONFIG_PARAMETERS') | ||
| 184 | if p is not None: | ||
| 185 | s = p + ' ' + s | ||
| 186 | env['GIT_CONFIG_PARAMETERS'] = s | ||
| 187 | if 'GIT_ALLOW_PROTOCOL' not in env: | ||
| 188 | env['GIT_ALLOW_PROTOCOL'] = ( | ||
| 189 | 'file:git:http:https:ssh:persistent-http:persistent-https:sso:rpc') | ||
| 190 | env['GIT_HTTP_USER_AGENT'] = user_agent.git | ||
| 191 | |||
| 192 | if objdir: | ||
| 193 | # Set to the place we want to save the objects. | ||
| 194 | env['GIT_OBJECT_DIRECTORY'] = objdir | ||
| 195 | |||
| 196 | alt_objects = os.path.join(gitdir, 'objects') if gitdir else None | ||
| 197 | if (alt_objects and | ||
| 198 | os.path.realpath(alt_objects) != os.path.realpath(objdir)): | ||
| 199 | # Allow git to search the original place in case of local or unique refs | ||
| 200 | # that git will attempt to resolve even if we aren't fetching them. | ||
| 201 | env['GIT_ALTERNATE_OBJECT_DIRECTORIES'] = alt_objects | ||
| 202 | if bare and gitdir is not None: | ||
| 203 | env[GIT_DIR] = gitdir | ||
| 204 | |||
| 205 | return env | ||
| 206 | |||
| 207 | |||
| 160 | class GitCommand(object): | 208 | class GitCommand(object): |
| 161 | """Wrapper around a single git invocation.""" | 209 | """Wrapper around a single git invocation.""" |
| 162 | 210 | ||
| @@ -173,30 +221,13 @@ class GitCommand(object): | |||
| 173 | cwd=None, | 221 | cwd=None, |
| 174 | gitdir=None, | 222 | gitdir=None, |
| 175 | objdir=None): | 223 | objdir=None): |
| 176 | env = self._GetBasicEnv() | ||
| 177 | |||
| 178 | if disable_editor: | ||
| 179 | env['GIT_EDITOR'] = ':' | ||
| 180 | if ssh_proxy: | ||
| 181 | env['REPO_SSH_SOCK'] = ssh_proxy.sock() | ||
| 182 | env['GIT_SSH'] = ssh_proxy.proxy | ||
| 183 | env['GIT_SSH_VARIANT'] = 'ssh' | ||
| 184 | if 'http_proxy' in env and 'darwin' == sys.platform: | ||
| 185 | s = "'http.proxy=%s'" % (env['http_proxy'],) | ||
| 186 | p = env.get('GIT_CONFIG_PARAMETERS') | ||
| 187 | if p is not None: | ||
| 188 | s = p + ' ' + s | ||
| 189 | env['GIT_CONFIG_PARAMETERS'] = s | ||
| 190 | if 'GIT_ALLOW_PROTOCOL' not in env: | ||
| 191 | env['GIT_ALLOW_PROTOCOL'] = ( | ||
| 192 | 'file:git:http:https:ssh:persistent-http:persistent-https:sso:rpc') | ||
| 193 | env['GIT_HTTP_USER_AGENT'] = user_agent.git | ||
| 194 | 224 | ||
| 195 | if project: | 225 | if project: |
| 196 | if not cwd: | 226 | if not cwd: |
| 197 | cwd = project.worktree | 227 | cwd = project.worktree |
| 198 | if not gitdir: | 228 | if not gitdir: |
| 199 | gitdir = project.gitdir | 229 | gitdir = project.gitdir |
| 230 | |||
| 200 | # Git on Windows wants its paths only using / for reliability. | 231 | # Git on Windows wants its paths only using / for reliability. |
| 201 | if platform_utils.isWindows(): | 232 | if platform_utils.isWindows(): |
| 202 | if objdir: | 233 | if objdir: |
| @@ -204,20 +235,16 @@ class GitCommand(object): | |||
| 204 | if gitdir: | 235 | if gitdir: |
| 205 | gitdir = gitdir.replace('\\', '/') | 236 | gitdir = gitdir.replace('\\', '/') |
| 206 | 237 | ||
| 207 | if objdir: | 238 | env = _build_env( |
| 208 | # Set to the place we want to save the objects. | 239 | disable_editor=disable_editor, |
| 209 | env['GIT_OBJECT_DIRECTORY'] = objdir | 240 | ssh_proxy=ssh_proxy, |
| 210 | 241 | objdir=objdir, | |
| 211 | alt_objects = os.path.join(gitdir, 'objects') if gitdir else None | 242 | gitdir=gitdir, |
| 212 | if alt_objects and os.path.realpath(alt_objects) != os.path.realpath(objdir): | 243 | bare=bare, |
| 213 | # Allow git to search the original place in case of local or unique refs | 244 | ) |
| 214 | # that git will attempt to resolve even if we aren't fetching them. | ||
| 215 | env['GIT_ALTERNATE_OBJECT_DIRECTORIES'] = alt_objects | ||
| 216 | 245 | ||
| 217 | command = [GIT] | 246 | command = [GIT] |
| 218 | if bare: | 247 | if bare: |
| 219 | if gitdir: | ||
| 220 | env[GIT_DIR] = gitdir | ||
| 221 | cwd = None | 248 | cwd = None |
| 222 | command.append(cmdv[0]) | 249 | command.append(cmdv[0]) |
| 223 | # Need to use the --progress flag for fetch/clone so output will be | 250 | # Need to use the --progress flag for fetch/clone so output will be |
diff --git a/tests/test_git_command.py b/tests/test_git_command.py index 93300a6f..aaf21219 100644 --- a/tests/test_git_command.py +++ b/tests/test_git_command.py | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | """Unittests for the git_command.py module.""" | 15 | """Unittests for the git_command.py module.""" |
| 16 | 16 | ||
| 17 | import re | 17 | import re |
| 18 | import os | ||
| 18 | import unittest | 19 | import unittest |
| 19 | 20 | ||
| 20 | try: | 21 | try: |
| @@ -26,6 +27,38 @@ import git_command | |||
| 26 | import wrapper | 27 | import wrapper |
| 27 | 28 | ||
| 28 | 29 | ||
| 30 | class GitCommandTest(unittest.TestCase): | ||
| 31 | """Tests the GitCommand class (via git_command.git).""" | ||
| 32 | |||
| 33 | def setUp(self): | ||
| 34 | |||
| 35 | def realpath_mock(val): | ||
| 36 | return val | ||
| 37 | |||
| 38 | mock.patch.object(os.path, 'realpath', side_effect=realpath_mock).start() | ||
| 39 | |||
| 40 | def tearDown(self): | ||
| 41 | mock.patch.stopall() | ||
| 42 | |||
| 43 | def test_alternative_setting_when_matching(self): | ||
| 44 | r = git_command._build_env( | ||
| 45 | objdir = 'zap/objects', | ||
| 46 | gitdir = 'zap' | ||
| 47 | ) | ||
| 48 | |||
| 49 | self.assertIsNone(r.get('GIT_ALTERNATE_OBJECT_DIRECTORIES')) | ||
| 50 | self.assertEqual(r.get('GIT_OBJECT_DIRECTORY'), 'zap/objects') | ||
| 51 | |||
| 52 | def test_alternative_setting_when_different(self): | ||
| 53 | r = git_command._build_env( | ||
| 54 | objdir = 'wow/objects', | ||
| 55 | gitdir = 'zap' | ||
| 56 | ) | ||
| 57 | |||
| 58 | self.assertEqual(r.get('GIT_ALTERNATE_OBJECT_DIRECTORIES'), 'zap/objects') | ||
| 59 | self.assertEqual(r.get('GIT_OBJECT_DIRECTORY'), 'wow/objects') | ||
| 60 | |||
| 61 | |||
| 29 | class GitCallUnitTest(unittest.TestCase): | 62 | class GitCallUnitTest(unittest.TestCase): |
| 30 | """Tests the _GitCall class (via git_command.git).""" | 63 | """Tests the _GitCall class (via git_command.git).""" |
| 31 | 64 | ||
