diff options
| -rw-r--r-- | man/repo-gc.1 | 43 | ||||
| -rw-r--r-- | man/repo-manifest.1 | 20 | ||||
| -rw-r--r-- | man/repo.1 | 5 | ||||
| -rw-r--r-- | subcmds/gc.py | 127 |
4 files changed, 193 insertions, 2 deletions
diff --git a/man/repo-gc.1 b/man/repo-gc.1 new file mode 100644 index 00000000..e465a253 --- /dev/null +++ b/man/repo-gc.1 | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | .\" DO NOT MODIFY THIS FILE! It was generated by help2man. | ||
| 2 | .TH REPO "1" "December 2024" "repo gc" "Repo Manual" | ||
| 3 | .SH NAME | ||
| 4 | repo \- repo gc - manual page for repo gc | ||
| 5 | .SH SYNOPSIS | ||
| 6 | .B repo | ||
| 7 | \fI\,gc\/\fR | ||
| 8 | .SH DESCRIPTION | ||
| 9 | Summary | ||
| 10 | .PP | ||
| 11 | Cleaning up internal repo state. | ||
| 12 | .SH OPTIONS | ||
| 13 | .TP | ||
| 14 | \fB\-h\fR, \fB\-\-help\fR | ||
| 15 | show this help message and exit | ||
| 16 | .TP | ||
| 17 | \fB\-n\fR, \fB\-\-dry\-run\fR | ||
| 18 | do everything except actually delete | ||
| 19 | .TP | ||
| 20 | \fB\-y\fR, \fB\-\-yes\fR | ||
| 21 | answer yes to all safe prompts | ||
| 22 | .SS Logging options: | ||
| 23 | .TP | ||
| 24 | \fB\-v\fR, \fB\-\-verbose\fR | ||
| 25 | show all output | ||
| 26 | .TP | ||
| 27 | \fB\-q\fR, \fB\-\-quiet\fR | ||
| 28 | only show errors | ||
| 29 | .SS Multi\-manifest options: | ||
| 30 | .TP | ||
| 31 | \fB\-\-outer\-manifest\fR | ||
| 32 | operate starting at the outermost manifest | ||
| 33 | .TP | ||
| 34 | \fB\-\-no\-outer\-manifest\fR | ||
| 35 | do not operate on outer manifests | ||
| 36 | .TP | ||
| 37 | \fB\-\-this\-manifest\-only\fR | ||
| 38 | only operate on this (sub)manifest | ||
| 39 | .TP | ||
| 40 | \fB\-\-no\-this\-manifest\-only\fR, \fB\-\-all\-manifests\fR | ||
| 41 | operate on this manifest and its submanifests | ||
| 42 | .PP | ||
| 43 | Run `repo help gc` to view the detailed manual. | ||
diff --git a/man/repo-manifest.1 b/man/repo-manifest.1 index 10ec2e75..2ee23e64 100644 --- a/man/repo-manifest.1 +++ b/man/repo-manifest.1 | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | .\" DO NOT MODIFY THIS FILE! It was generated by help2man. | 1 | .\" DO NOT MODIFY THIS FILE! It was generated by help2man. |
| 2 | .TH REPO "1" "April 2024" "repo manifest" "Repo Manual" | 2 | .TH REPO "1" "December 2024" "repo manifest" "Repo Manual" |
| 3 | .SH NAME | 3 | .SH NAME |
| 4 | repo \- repo manifest - manual page for repo manifest | 4 | repo \- repo manifest - manual page for repo manifest |
| 5 | .SH SYNOPSIS | 5 | .SH SYNOPSIS |
| @@ -192,11 +192,13 @@ CDATA #IMPLIED> | |||
| 192 | <!ATTLIST extend\-project remote CDATA #IMPLIED> | 192 | <!ATTLIST extend\-project remote CDATA #IMPLIED> |
| 193 | <!ATTLIST extend\-project dest\-branch CDATA #IMPLIED> | 193 | <!ATTLIST extend\-project dest\-branch CDATA #IMPLIED> |
| 194 | <!ATTLIST extend\-project upstream CDATA #IMPLIED> | 194 | <!ATTLIST extend\-project upstream CDATA #IMPLIED> |
| 195 | <!ATTLIST extend\-project base\-rev CDATA #IMPLIED> | ||
| 195 | .IP | 196 | .IP |
| 196 | <!ELEMENT remove\-project EMPTY> | 197 | <!ELEMENT remove\-project EMPTY> |
| 197 | <!ATTLIST remove\-project name CDATA #IMPLIED> | 198 | <!ATTLIST remove\-project name CDATA #IMPLIED> |
| 198 | <!ATTLIST remove\-project path CDATA #IMPLIED> | 199 | <!ATTLIST remove\-project path CDATA #IMPLIED> |
| 199 | <!ATTLIST remove\-project optional CDATA #IMPLIED> | 200 | <!ATTLIST remove\-project optional CDATA #IMPLIED> |
| 201 | <!ATTLIST remove\-project base\-rev CDATA #IMPLIED> | ||
| 200 | .IP | 202 | .IP |
| 201 | <!ELEMENT repo\-hooks EMPTY> | 203 | <!ELEMENT repo\-hooks EMPTY> |
| 202 | <!ATTLIST repo\-hooks in\-project CDATA #REQUIRED> | 204 | <!ATTLIST repo\-hooks in\-project CDATA #REQUIRED> |
| @@ -495,6 +497,14 @@ project. Same syntax as the corresponding element of `project`. | |||
| 495 | Attribute `upstream`: If specified, overrides the upstream of the original | 497 | Attribute `upstream`: If specified, overrides the upstream of the original |
| 496 | project. Same syntax as the corresponding element of `project`. | 498 | project. Same syntax as the corresponding element of `project`. |
| 497 | .PP | 499 | .PP |
| 500 | Attribute `base\-rev`: If specified, adds a check against the revision to be | ||
| 501 | extended. Manifest parse will fail and give a list of mismatch extends if the | ||
| 502 | revisions being extended have changed since base\-rev was set. Intended for use | ||
| 503 | with layered manifests using hash revisions to prevent patch branches hiding | ||
| 504 | newer upstream revisions. Also compares named refs like branches or tags but is | ||
| 505 | misleading if branches are used as base\-rev. Same syntax as the corresponding | ||
| 506 | element of `project`. | ||
| 507 | .PP | ||
| 498 | Element annotation | 508 | Element annotation |
| 499 | .PP | 509 | .PP |
| 500 | Zero or more annotation elements may be specified as children of a project or | 510 | Zero or more annotation elements may be specified as children of a project or |
| @@ -556,6 +566,14 @@ Logic otherwise behaves like both are specified. | |||
| 556 | Attribute `optional`: Set to true to ignore remove\-project elements with no | 566 | Attribute `optional`: Set to true to ignore remove\-project elements with no |
| 557 | matching `project` element. | 567 | matching `project` element. |
| 558 | .PP | 568 | .PP |
| 569 | Attribute `base\-rev`: If specified, adds a check against the revision to be | ||
| 570 | removed. Manifest parse will fail and give a list of mismatch removes if the | ||
| 571 | revisions being removed have changed since base\-rev was set. Intended for use | ||
| 572 | with layered manifests using hash revisions to prevent patch branches hiding | ||
| 573 | newer upstream revisions. Also compares named refs like branches or tags but is | ||
| 574 | misleading if branches are used as base\-rev. Same syntax as the corresponding | ||
| 575 | element of `project`. | ||
| 576 | .PP | ||
| 559 | Element repo\-hooks | 577 | Element repo\-hooks |
| 560 | .PP | 578 | .PP |
| 561 | NB: See the [practical documentation](./repo\-hooks.md) for using repo hooks. | 579 | NB: See the [practical documentation](./repo\-hooks.md) for using repo hooks. |
| @@ -1,5 +1,5 @@ | |||
| 1 | .\" DO NOT MODIFY THIS FILE! It was generated by help2man. | 1 | .\" DO NOT MODIFY THIS FILE! It was generated by help2man. |
| 2 | .TH REPO "1" "April 2024" "repo" "Repo Manual" | 2 | .TH REPO "1" "December 2024" "repo" "Repo Manual" |
| 3 | .SH NAME | 3 | .SH NAME |
| 4 | repo \- repository management tool built on top of git | 4 | repo \- repository management tool built on top of git |
| 5 | .SH SYNOPSIS | 5 | .SH SYNOPSIS |
| @@ -79,6 +79,9 @@ Download and checkout a change | |||
| 79 | forall | 79 | forall |
| 80 | Run a shell command in each project | 80 | Run a shell command in each project |
| 81 | .TP | 81 | .TP |
| 82 | gc | ||
| 83 | Cleaning up internal repo state. | ||
| 84 | .TP | ||
| 82 | grep | 85 | grep |
| 83 | Print lines matching a pattern | 86 | Print lines matching a pattern |
| 84 | .TP | 87 | .TP |
diff --git a/subcmds/gc.py b/subcmds/gc.py new file mode 100644 index 00000000..f12f56f1 --- /dev/null +++ b/subcmds/gc.py | |||
| @@ -0,0 +1,127 @@ | |||
| 1 | # Copyright (C) 2024 The Android Open Source Project | ||
| 2 | # | ||
| 3 | # Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 4 | # you may not use this file except in compliance with the License. | ||
| 5 | # You may obtain a copy of the License at | ||
| 6 | # | ||
| 7 | # http://www.apache.org/licenses/LICENSE-2.0 | ||
| 8 | # | ||
| 9 | # Unless required by applicable law or agreed to in writing, software | ||
| 10 | # distributed under the License is distributed on an "AS IS" BASIS, | ||
| 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 12 | # See the License for the specific language governing permissions and | ||
| 13 | # limitations under the License. | ||
| 14 | |||
| 15 | import os | ||
| 16 | from typing import Set | ||
| 17 | |||
| 18 | from command import Command | ||
| 19 | import platform_utils | ||
| 20 | from progress import Progress | ||
| 21 | |||
| 22 | |||
| 23 | class Gc(Command): | ||
| 24 | COMMON = True | ||
| 25 | helpSummary = "Cleaning up internal repo state." | ||
| 26 | helpUsage = """ | ||
| 27 | %prog | ||
| 28 | """ | ||
| 29 | |||
| 30 | def _Options(self, p): | ||
| 31 | p.add_option( | ||
| 32 | "-n", | ||
| 33 | "--dry-run", | ||
| 34 | dest="dryrun", | ||
| 35 | default=False, | ||
| 36 | action="store_true", | ||
| 37 | help="do everything except actually delete", | ||
| 38 | ) | ||
| 39 | p.add_option( | ||
| 40 | "-y", | ||
| 41 | "--yes", | ||
| 42 | default=False, | ||
| 43 | action="store_true", | ||
| 44 | help="answer yes to all safe prompts", | ||
| 45 | ) | ||
| 46 | |||
| 47 | def _find_git_to_delete( | ||
| 48 | self, to_keep: Set[str], start_dir: str | ||
| 49 | ) -> Set[str]: | ||
| 50 | """Searches no longer needed ".git" directories. | ||
| 51 | |||
| 52 | Scans the file system starting from `start_dir` and removes all | ||
| 53 | directories that end with ".git" that are not in the `to_keep` set. | ||
| 54 | """ | ||
| 55 | to_delete = set() | ||
| 56 | for root, dirs, _ in platform_utils.walk(start_dir): | ||
| 57 | for directory in dirs: | ||
| 58 | if not directory.endswith(".git"): | ||
| 59 | continue | ||
| 60 | |||
| 61 | path = os.path.join(root, directory) | ||
| 62 | if path not in to_keep: | ||
| 63 | to_delete.add(path) | ||
| 64 | |||
| 65 | return to_delete | ||
| 66 | |||
| 67 | def Execute(self, opt, args): | ||
| 68 | projects = self.GetProjects( | ||
| 69 | args, all_manifests=not opt.this_manifest_only | ||
| 70 | ) | ||
| 71 | print(f"Scanning filesystem under {self.repodir}...") | ||
| 72 | |||
| 73 | project_paths = set() | ||
| 74 | project_object_paths = set() | ||
| 75 | |||
| 76 | for project in projects: | ||
| 77 | project_paths.add(project.gitdir) | ||
| 78 | project_object_paths.add(project.objdir) | ||
| 79 | |||
| 80 | to_delete = self._find_git_to_delete( | ||
| 81 | project_paths, os.path.join(self.repodir, "projects") | ||
| 82 | ) | ||
| 83 | |||
| 84 | to_delete.update( | ||
| 85 | self._find_git_to_delete( | ||
| 86 | project_object_paths, | ||
| 87 | os.path.join(self.repodir, "project-objects"), | ||
| 88 | ) | ||
| 89 | ) | ||
| 90 | |||
| 91 | if not to_delete: | ||
| 92 | print("Nothing to clean up.") | ||
| 93 | return | ||
| 94 | |||
| 95 | print("Identified the following projects are no longer used:") | ||
| 96 | print("\n".join(to_delete)) | ||
| 97 | print("\n") | ||
| 98 | if not opt.yes: | ||
| 99 | print( | ||
| 100 | "If you proceed, any local commits in those projects will be " | ||
| 101 | "destroyed!" | ||
| 102 | ) | ||
| 103 | ask = input("Proceed? [y/N] ") | ||
| 104 | if ask.lower() != "y": | ||
| 105 | return 1 | ||
| 106 | |||
| 107 | pm = Progress( | ||
| 108 | "Deleting", | ||
| 109 | len(to_delete), | ||
| 110 | delay=False, | ||
| 111 | quiet=opt.quiet, | ||
| 112 | show_elapsed=True, | ||
| 113 | elide=True, | ||
| 114 | ) | ||
| 115 | |||
| 116 | for path in to_delete: | ||
| 117 | if opt.dryrun: | ||
| 118 | print(f"\nWould have deleted ${path}") | ||
| 119 | else: | ||
| 120 | tmp_path = os.path.join( | ||
| 121 | os.path.dirname(path), | ||
| 122 | f"to_be_deleted_{os.path.basename(path)}", | ||
| 123 | ) | ||
| 124 | platform_utils.rename(path, tmp_path) | ||
| 125 | platform_utils.rmtree(tmp_path) | ||
| 126 | pm.update(msg=path) | ||
| 127 | pm.end() | ||
