diff options
| -rw-r--r-- | git_command.py | 3 | ||||
| -rw-r--r-- | git_config.py | 14 | ||||
| -rw-r--r-- | git_superproject.py | 81 | ||||
| -rw-r--r-- | subcmds/sync.py | 11 |
4 files changed, 98 insertions, 11 deletions
diff --git a/git_command.py b/git_command.py index 04953f38..95db91f2 100644 --- a/git_command.py +++ b/git_command.py | |||
| @@ -75,7 +75,8 @@ def RepoSourceVersion(): | |||
| 75 | proj = os.path.dirname(os.path.abspath(__file__)) | 75 | proj = os.path.dirname(os.path.abspath(__file__)) |
| 76 | env[GIT_DIR] = os.path.join(proj, '.git') | 76 | env[GIT_DIR] = os.path.join(proj, '.git') |
| 77 | result = subprocess.run([GIT, 'describe', HEAD], stdout=subprocess.PIPE, | 77 | result = subprocess.run([GIT, 'describe', HEAD], stdout=subprocess.PIPE, |
| 78 | encoding='utf-8', env=env, check=False) | 78 | stderr=subprocess.DEVNULL, encoding='utf-8', |
| 79 | env=env, check=False) | ||
| 79 | if result.returncode == 0: | 80 | if result.returncode == 0: |
| 80 | ver = result.stdout.strip() | 81 | ver = result.stdout.strip() |
| 81 | if ver.startswith('v'): | 82 | if ver.startswith('v'): |
diff --git a/git_config.py b/git_config.py index 978f6a59..3eaf201c 100644 --- a/git_config.py +++ b/git_config.py | |||
| @@ -65,6 +65,15 @@ class GitConfig(object): | |||
| 65 | 65 | ||
| 66 | _USER_CONFIG = '~/.gitconfig' | 66 | _USER_CONFIG = '~/.gitconfig' |
| 67 | 67 | ||
| 68 | _ForSystem = None | ||
| 69 | _SYSTEM_CONFIG = '/etc/gitconfig' | ||
| 70 | |||
| 71 | @classmethod | ||
| 72 | def ForSystem(cls): | ||
| 73 | if cls._ForSystem is None: | ||
| 74 | cls._ForSystem = cls(configfile=cls._SYSTEM_CONFIG) | ||
| 75 | return cls._ForSystem | ||
| 76 | |||
| 68 | @classmethod | 77 | @classmethod |
| 69 | def ForUser(cls): | 78 | def ForUser(cls): |
| 70 | if cls._ForUser is None: | 79 | if cls._ForUser is None: |
| @@ -356,7 +365,10 @@ class GitConfig(object): | |||
| 356 | return c | 365 | return c |
| 357 | 366 | ||
| 358 | def _do(self, *args): | 367 | def _do(self, *args): |
| 359 | command = ['config', '--file', self.file, '--includes'] | 368 | if self.file == self._SYSTEM_CONFIG: |
| 369 | command = ['config', '--system', '--includes'] | ||
| 370 | else: | ||
| 371 | command = ['config', '--file', self.file, '--includes'] | ||
| 360 | command.extend(args) | 372 | command.extend(args) |
| 361 | 373 | ||
| 362 | p = GitCommand(None, | 374 | p = GitCommand(None, |
diff --git a/git_superproject.py b/git_superproject.py index 0c477060..2a47847a 100644 --- a/git_superproject.py +++ b/git_superproject.py | |||
| @@ -23,11 +23,14 @@ Examples: | |||
| 23 | """ | 23 | """ |
| 24 | 24 | ||
| 25 | import hashlib | 25 | import hashlib |
| 26 | import functools | ||
| 26 | import os | 27 | import os |
| 27 | import sys | 28 | import sys |
| 29 | import time | ||
| 28 | from typing import NamedTuple | 30 | from typing import NamedTuple |
| 29 | 31 | ||
| 30 | from git_command import git_require, GitCommand | 32 | from git_command import git_require, GitCommand |
| 33 | from git_config import RepoConfig | ||
| 31 | from git_refs import R_HEADS | 34 | from git_refs import R_HEADS |
| 32 | from manifest_xml import LOCAL_MANIFEST_GROUP_PREFIX | 35 | from manifest_xml import LOCAL_MANIFEST_GROUP_PREFIX |
| 33 | 36 | ||
| @@ -343,3 +346,81 @@ class Superproject(object): | |||
| 343 | 346 | ||
| 344 | manifest_path = self._WriteManfiestFile() | 347 | manifest_path = self._WriteManfiestFile() |
| 345 | return UpdateProjectsResult(manifest_path, False) | 348 | return UpdateProjectsResult(manifest_path, False) |
| 349 | |||
| 350 | |||
| 351 | @functools.lru_cache(maxsize=None) | ||
| 352 | def _UseSuperprojectFromConfiguration(): | ||
| 353 | """Returns the user choice of whether to use superproject.""" | ||
| 354 | user_cfg = RepoConfig.ForUser() | ||
| 355 | system_cfg = RepoConfig.ForSystem() | ||
| 356 | time_now = int(time.time()) | ||
| 357 | |||
| 358 | user_value = user_cfg.GetBoolean('repo.superprojectChoice') | ||
| 359 | if user_value is not None: | ||
| 360 | user_expiration = user_cfg.GetInt('repo.superprojectChoiceExpire') | ||
| 361 | if user_expiration is not None and (user_expiration <= 0 or user_expiration >= time_now): | ||
| 362 | # TODO(b/190688390) - Remove prompt when we are comfortable with the new | ||
| 363 | # default value. | ||
| 364 | print(('You are currently enrolled in Git submodules experiment ' | ||
| 365 | '(go/android-submodules-quickstart). Use --no-use-superproject ' | ||
| 366 | 'to override.\n'), file=sys.stderr) | ||
| 367 | return user_value | ||
| 368 | |||
| 369 | # We don't have an unexpired choice, ask for one. | ||
| 370 | system_value = system_cfg.GetBoolean('repo.superprojectChoice') | ||
| 371 | if system_value: | ||
| 372 | # The system configuration is proposing that we should enable the | ||
| 373 | # use of superproject. Present this to user for confirmation if we | ||
| 374 | # are on a TTY, or, when we are not on a TTY, accept the system | ||
| 375 | # default for this time only. | ||
| 376 | # | ||
| 377 | # TODO(b/190688390) - Remove prompt when we are comfortable with the new | ||
| 378 | # default value. | ||
| 379 | prompt = ('Repo can now use Git submodules (go/android-submodules-quickstart) ' | ||
| 380 | 'instead of manifests to represent the state of the Android ' | ||
| 381 | 'superproject, which results in faster syncs and better atomicity.\n\n') | ||
| 382 | if sys.stdout.isatty(): | ||
| 383 | prompt += 'Would you like to opt in for two weeks (y/N)? ' | ||
| 384 | response = input(prompt).lower() | ||
| 385 | time_choiceexpire = time_now + (86400 * 14) | ||
| 386 | if response in ('y', 'yes'): | ||
| 387 | userchoice = True | ||
| 388 | elif response in ('a', 'always'): | ||
| 389 | userchoice = True | ||
| 390 | time_choiceexpire = 0 | ||
| 391 | elif response == 'never': | ||
| 392 | userchoice = False | ||
| 393 | time_choiceexpire = 0 | ||
| 394 | elif response in ('n', 'no'): | ||
| 395 | userchoice = False | ||
| 396 | else: | ||
| 397 | # Unrecognized user response, assume the intention was no, but | ||
| 398 | # only for 2 hours instead of 2 weeks to balance between not | ||
| 399 | # being overly pushy while still retain the opportunity to | ||
| 400 | # enroll. | ||
| 401 | userchoice = False | ||
| 402 | time_choiceexpire = time_now + 7200 | ||
| 403 | |||
| 404 | user_cfg.SetString('repo.superprojectChoiceExpire', str(time_choiceexpire)) | ||
| 405 | user_cfg.SetBoolean('repo.superprojectChoice', userchoice) | ||
| 406 | |||
| 407 | return userchoice | ||
| 408 | else: | ||
| 409 | print('Accepting once since we are not on a TTY', file=sys.stderr) | ||
| 410 | return True | ||
| 411 | |||
| 412 | # For all other cases, we would not use superproject by default. | ||
| 413 | return False | ||
| 414 | |||
| 415 | |||
| 416 | def UseSuperproject(opt, manifest): | ||
| 417 | """Returns a boolean if use-superproject option is enabled.""" | ||
| 418 | |||
| 419 | if opt.use_superproject is not None: | ||
| 420 | return opt.use_superproject | ||
| 421 | else: | ||
| 422 | client_value = manifest.manifestProject.config.GetBoolean('repo.superproject') | ||
| 423 | if client_value is not None: | ||
| 424 | return client_value | ||
| 425 | else: | ||
| 426 | return _UseSuperprojectFromConfiguration() | ||
diff --git a/subcmds/sync.py b/subcmds/sync.py index 8d89cf72..8defc932 100644 --- a/subcmds/sync.py +++ b/subcmds/sync.py | |||
| @@ -278,16 +278,9 @@ later is required to fix a server side protocol bug. | |||
| 278 | branch = branch[len(R_HEADS):] | 278 | branch = branch[len(R_HEADS):] |
| 279 | return branch | 279 | return branch |
| 280 | 280 | ||
| 281 | def _UseSuperproject(self, opt): | ||
| 282 | """Returns True if use-superproject option is enabled""" | ||
| 283 | if opt.use_superproject is not None: | ||
| 284 | return opt.use_superproject | ||
| 285 | else: | ||
| 286 | return self.manifest.manifestProject.config.GetBoolean('repo.superproject') | ||
| 287 | |||
| 288 | def _GetCurrentBranchOnly(self, opt): | 281 | def _GetCurrentBranchOnly(self, opt): |
| 289 | """Returns True if current-branch or use-superproject options are enabled.""" | 282 | """Returns True if current-branch or use-superproject options are enabled.""" |
| 290 | return opt.current_branch_only or self._UseSuperproject(opt) | 283 | return opt.current_branch_only or git_superproject.UseSuperproject(opt, self.manifest) |
| 291 | 284 | ||
| 292 | def _UpdateProjectsRevisionId(self, opt, args, load_local_manifests): | 285 | def _UpdateProjectsRevisionId(self, opt, args, load_local_manifests): |
| 293 | """Update revisionId of every project with the SHA from superproject. | 286 | """Update revisionId of every project with the SHA from superproject. |
| @@ -964,7 +957,7 @@ later is required to fix a server side protocol bug. | |||
| 964 | self._UpdateManifestProject(opt, mp, manifest_name) | 957 | self._UpdateManifestProject(opt, mp, manifest_name) |
| 965 | 958 | ||
| 966 | load_local_manifests = not self.manifest.HasLocalManifests | 959 | load_local_manifests = not self.manifest.HasLocalManifests |
| 967 | if self._UseSuperproject(opt): | 960 | if git_superproject.UseSuperproject(opt, self.manifest): |
| 968 | new_manifest_name = self._UpdateProjectsRevisionId(opt, args, load_local_manifests) | 961 | new_manifest_name = self._UpdateProjectsRevisionId(opt, args, load_local_manifests) |
| 969 | if not new_manifest_name: | 962 | if not new_manifest_name: |
| 970 | manifest_name = new_manifest_name | 963 | manifest_name = new_manifest_name |
