diff options
Diffstat (limited to 'subcmds/status.py')
| -rw-r--r-- | subcmds/status.py | 239 |
1 files changed, 129 insertions, 110 deletions
diff --git a/subcmds/status.py b/subcmds/status.py index 572c72f7..6e0026f9 100644 --- a/subcmds/status.py +++ b/subcmds/status.py | |||
| @@ -24,12 +24,12 @@ import platform_utils | |||
| 24 | 24 | ||
| 25 | 25 | ||
| 26 | class Status(PagedCommand): | 26 | class Status(PagedCommand): |
| 27 | COMMON = True | 27 | COMMON = True |
| 28 | helpSummary = "Show the working tree status" | 28 | helpSummary = "Show the working tree status" |
| 29 | helpUsage = """ | 29 | helpUsage = """ |
| 30 | %prog [<project>...] | 30 | %prog [<project>...] |
| 31 | """ | 31 | """ |
| 32 | helpDescription = """ | 32 | helpDescription = """ |
| 33 | '%prog' compares the working tree to the staging area (aka index), | 33 | '%prog' compares the working tree to the staging area (aka index), |
| 34 | and the most recent commit on this branch (HEAD), in each project | 34 | and the most recent commit on this branch (HEAD), in each project |
| 35 | specified. A summary is displayed, one line per file where there | 35 | specified. A summary is displayed, one line per file where there |
| @@ -76,109 +76,128 @@ the following meanings: | |||
| 76 | d: deleted ( in index, not in work tree ) | 76 | d: deleted ( in index, not in work tree ) |
| 77 | 77 | ||
| 78 | """ | 78 | """ |
| 79 | PARALLEL_JOBS = DEFAULT_LOCAL_JOBS | 79 | PARALLEL_JOBS = DEFAULT_LOCAL_JOBS |
| 80 | 80 | ||
| 81 | def _Options(self, p): | 81 | def _Options(self, p): |
| 82 | p.add_option('-o', '--orphans', | 82 | p.add_option( |
| 83 | dest='orphans', action='store_true', | 83 | "-o", |
| 84 | help="include objects in working directory outside of repo projects") | 84 | "--orphans", |
| 85 | 85 | dest="orphans", | |
| 86 | def _StatusHelper(self, quiet, local, project): | 86 | action="store_true", |
| 87 | """Obtains the status for a specific project. | 87 | help="include objects in working directory outside of repo " |
| 88 | 88 | "projects", | |
| 89 | Obtains the status for a project, redirecting the output to | 89 | ) |
| 90 | the specified object. | 90 | |
| 91 | 91 | def _StatusHelper(self, quiet, local, project): | |
| 92 | Args: | 92 | """Obtains the status for a specific project. |
| 93 | quiet: Where to output the status. | 93 | |
| 94 | local: a boolean, if True, the path is relative to the local | 94 | Obtains the status for a project, redirecting the output to |
| 95 | (sub)manifest. If false, the path is relative to the | 95 | the specified object. |
| 96 | outermost manifest. | 96 | |
| 97 | project: Project to get status of. | 97 | Args: |
| 98 | 98 | quiet: Where to output the status. | |
| 99 | Returns: | 99 | local: a boolean, if True, the path is relative to the local |
| 100 | The status of the project. | 100 | (sub)manifest. If false, the path is relative to the outermost |
| 101 | """ | 101 | manifest. |
| 102 | buf = io.StringIO() | 102 | project: Project to get status of. |
| 103 | ret = project.PrintWorkTreeStatus(quiet=quiet, output_redir=buf, | 103 | |
| 104 | local=local) | 104 | Returns: |
| 105 | return (ret, buf.getvalue()) | 105 | The status of the project. |
| 106 | 106 | """ | |
| 107 | def _FindOrphans(self, dirs, proj_dirs, proj_dirs_parents, outstring): | 107 | buf = io.StringIO() |
| 108 | """find 'dirs' that are present in 'proj_dirs_parents' but not in 'proj_dirs'""" | 108 | ret = project.PrintWorkTreeStatus( |
| 109 | status_header = ' --\t' | 109 | quiet=quiet, output_redir=buf, local=local |
| 110 | for item in dirs: | 110 | ) |
| 111 | if not platform_utils.isdir(item): | 111 | return (ret, buf.getvalue()) |
| 112 | outstring.append(''.join([status_header, item])) | 112 | |
| 113 | continue | 113 | def _FindOrphans(self, dirs, proj_dirs, proj_dirs_parents, outstring): |
| 114 | if item in proj_dirs: | 114 | """find 'dirs' that are present in 'proj_dirs_parents' but not in 'proj_dirs'""" # noqa: E501 |
| 115 | continue | 115 | status_header = " --\t" |
| 116 | if item in proj_dirs_parents: | 116 | for item in dirs: |
| 117 | self._FindOrphans(glob.glob('%s/.*' % item) + | 117 | if not platform_utils.isdir(item): |
| 118 | glob.glob('%s/*' % item), | 118 | outstring.append("".join([status_header, item])) |
| 119 | proj_dirs, proj_dirs_parents, outstring) | 119 | continue |
| 120 | continue | 120 | if item in proj_dirs: |
| 121 | outstring.append(''.join([status_header, item, '/'])) | 121 | continue |
| 122 | 122 | if item in proj_dirs_parents: | |
| 123 | def Execute(self, opt, args): | 123 | self._FindOrphans( |
| 124 | all_projects = self.GetProjects(args, all_manifests=not opt.this_manifest_only) | 124 | glob.glob("%s/.*" % item) + glob.glob("%s/*" % item), |
| 125 | 125 | proj_dirs, | |
| 126 | def _ProcessResults(_pool, _output, results): | 126 | proj_dirs_parents, |
| 127 | ret = 0 | 127 | outstring, |
| 128 | for (state, output) in results: | 128 | ) |
| 129 | if output: | 129 | continue |
| 130 | print(output, end='') | 130 | outstring.append("".join([status_header, item, "/"])) |
| 131 | if state == 'CLEAN': | 131 | |
| 132 | ret += 1 | 132 | def Execute(self, opt, args): |
| 133 | return ret | 133 | all_projects = self.GetProjects( |
| 134 | 134 | args, all_manifests=not opt.this_manifest_only | |
| 135 | counter = self.ExecuteInParallel( | 135 | ) |
| 136 | opt.jobs, | 136 | |
| 137 | functools.partial(self._StatusHelper, opt.quiet, opt.this_manifest_only), | 137 | def _ProcessResults(_pool, _output, results): |
| 138 | all_projects, | 138 | ret = 0 |
| 139 | callback=_ProcessResults, | 139 | for state, output in results: |
| 140 | ordered=True) | 140 | if output: |
| 141 | 141 | print(output, end="") | |
| 142 | if not opt.quiet and len(all_projects) == counter: | 142 | if state == "CLEAN": |
| 143 | print('nothing to commit (working directory clean)') | 143 | ret += 1 |
| 144 | 144 | return ret | |
| 145 | if opt.orphans: | 145 | |
| 146 | proj_dirs = set() | 146 | counter = self.ExecuteInParallel( |
| 147 | proj_dirs_parents = set() | 147 | opt.jobs, |
| 148 | for project in self.GetProjects(None, missing_ok=True, all_manifests=not opt.this_manifest_only): | 148 | functools.partial( |
| 149 | relpath = project.RelPath(local=opt.this_manifest_only) | 149 | self._StatusHelper, opt.quiet, opt.this_manifest_only |
| 150 | proj_dirs.add(relpath) | 150 | ), |
| 151 | (head, _tail) = os.path.split(relpath) | 151 | all_projects, |
| 152 | while head != "": | 152 | callback=_ProcessResults, |
| 153 | proj_dirs_parents.add(head) | 153 | ordered=True, |
| 154 | (head, _tail) = os.path.split(head) | 154 | ) |
| 155 | proj_dirs.add('.repo') | 155 | |
| 156 | 156 | if not opt.quiet and len(all_projects) == counter: | |
| 157 | class StatusColoring(Coloring): | 157 | print("nothing to commit (working directory clean)") |
| 158 | def __init__(self, config): | 158 | |
| 159 | Coloring.__init__(self, config, 'status') | 159 | if opt.orphans: |
| 160 | self.project = self.printer('header', attr='bold') | 160 | proj_dirs = set() |
| 161 | self.untracked = self.printer('untracked', fg='red') | 161 | proj_dirs_parents = set() |
| 162 | 162 | for project in self.GetProjects( | |
| 163 | orig_path = os.getcwd() | 163 | None, missing_ok=True, all_manifests=not opt.this_manifest_only |
| 164 | try: | 164 | ): |
| 165 | os.chdir(self.manifest.topdir) | 165 | relpath = project.RelPath(local=opt.this_manifest_only) |
| 166 | 166 | proj_dirs.add(relpath) | |
| 167 | outstring = [] | 167 | (head, _tail) = os.path.split(relpath) |
| 168 | self._FindOrphans(glob.glob('.*') + | 168 | while head != "": |
| 169 | glob.glob('*'), | 169 | proj_dirs_parents.add(head) |
| 170 | proj_dirs, proj_dirs_parents, outstring) | 170 | (head, _tail) = os.path.split(head) |
| 171 | 171 | proj_dirs.add(".repo") | |
| 172 | if outstring: | 172 | |
| 173 | output = StatusColoring(self.client.globalConfig) | 173 | class StatusColoring(Coloring): |
| 174 | output.project('Objects not within a project (orphans)') | 174 | def __init__(self, config): |
| 175 | output.nl() | 175 | Coloring.__init__(self, config, "status") |
| 176 | for entry in outstring: | 176 | self.project = self.printer("header", attr="bold") |
| 177 | output.untracked(entry) | 177 | self.untracked = self.printer("untracked", fg="red") |
| 178 | output.nl() | 178 | |
| 179 | else: | 179 | orig_path = os.getcwd() |
| 180 | print('No orphan files or directories') | 180 | try: |
| 181 | 181 | os.chdir(self.manifest.topdir) | |
| 182 | finally: | 182 | |
| 183 | # Restore CWD. | 183 | outstring = [] |
| 184 | os.chdir(orig_path) | 184 | self._FindOrphans( |
| 185 | glob.glob(".*") + glob.glob("*"), | ||
| 186 | proj_dirs, | ||
| 187 | proj_dirs_parents, | ||
| 188 | outstring, | ||
| 189 | ) | ||
| 190 | |||
| 191 | if outstring: | ||
| 192 | output = StatusColoring(self.client.globalConfig) | ||
| 193 | output.project("Objects not within a project (orphans)") | ||
| 194 | output.nl() | ||
| 195 | for entry in outstring: | ||
| 196 | output.untracked(entry) | ||
| 197 | output.nl() | ||
| 198 | else: | ||
| 199 | print("No orphan files or directories") | ||
| 200 | |||
| 201 | finally: | ||
| 202 | # Restore CWD. | ||
| 203 | os.chdir(orig_path) | ||
