pFad - Phone/Frame/Anonymizer/Declutterfier! Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

URL: http://github.com/pre-commit/pre-commit/commit/ddbee32ad0722a0bc216bc29ee29a1885454bd78

f="https://github.githubassets.com/assets/global-d18f184ea1a06a2c.css" /> add --jobs option to autoupdate · pre-commit/pre-commit@ddbee32 · GitHub
Skip to content

Commit ddbee32

Browse files
committed
add --jobs option to autoupdate
1 parent bab5f70 commit ddbee32

4 files changed

Lines changed: 73 additions & 44 deletions

File tree

pre_commit/commands/autoupdate.py

Lines changed: 56 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from __future__ import annotations
22

3+
import concurrent.futures
34
import os.path
45
import re
56
import tempfile
@@ -10,6 +11,7 @@
1011
import pre_commit.constants as C
1112
from pre_commit import git
1213
from pre_commit import output
14+
from pre_commit import xargs
1315
from pre_commit.clientlib import InvalidManifestError
1416
from pre_commit.clientlib import load_config
1517
from pre_commit.clientlib import load_manifest
@@ -71,7 +73,7 @@ def update(self, tags_only: bool, freeze: bool) -> RevInfo:
7173
try:
7274
manifest = load_manifest(os.path.join(tmp, C.MANIFEST_FILE))
7375
except InvalidManifestError as e:
74-
raise RepositoryCannotBeUpdatedError(str(e))
76+
raise RepositoryCannotBeUpdatedError(f'[{self.repo}] {e}')
7577
else:
7678
hook_ids = frozenset(hook['id'] for hook in manifest)
7779

@@ -91,11 +93,24 @@ def _check_hooks_still_exist_at_rev(
9193
hooks_missing = hooks - info.hook_ids
9294
if hooks_missing:
9395
raise RepositoryCannotBeUpdatedError(
94-
f'Cannot update because the update target is missing these '
95-
f'hooks:\n{", ".join(sorted(hooks_missing))}',
96+
f'[{info.repo}] Cannot update because the update target is '
97+
f'missing these hooks: {", ".join(sorted(hooks_missing))}',
9698
)
9799

98100

101+
def _update_one(
102+
i: int,
103+
repo: dict[str, Any],
104+
*,
105+
tags_only: bool,
106+
freeze: bool,
107+
) -> tuple[int, RevInfo, RevInfo]:
108+
old = RevInfo.from_config(repo)
109+
new = old.update(tags_only=tags_only, freeze=freeze)
110+
_check_hooks_still_exist_at_rev(repo, new)
111+
return i, old, new
112+
113+
99114
REV_LINE_RE = re.compile(r'^(\s+)rev:(\s*)([\'"]?)([^\s#]+)(.*)(\r?\n)$')
100115

101116

@@ -147,45 +162,50 @@ def autoupdate(
147162
tags_only: bool,
148163
freeze: bool,
149164
repos: Sequence[str] = (),
165+
jobs: int = 1,
150166
) -> int:
151167
"""Auto-update the pre-commit config to the latest versions of repos."""
152168
migrate_config(config_file, quiet=True)
153-
retv = 0
154-
rev_infos: list[RevInfo | None] = []
155169
changed = False
170+
retv = 0
156171

157-
config = load_config(config_file)
158-
for repo_config in config['repos']:
159-
if repo_config['repo'] in {LOCAL, META}:
160-
continue
161-
162-
info = RevInfo.from_config(repo_config)
163-
if repos and info.repo not in repos:
164-
rev_infos.append(None)
165-
continue
166-
167-
output.write(f'Updating {info.repo} ... ')
168-
try:
169-
new_info = info.update(tags_only=tags_only, freeze=freeze)
170-
_check_hooks_still_exist_at_rev(repo_config, new_info)
171-
except RepositoryCannotBeUpdatedError as error:
172-
output.write_line(error.args[0])
173-
rev_infos.append(None)
174-
retv = 1
175-
continue
176-
177-
if new_info.rev != info.rev:
178-
changed = True
179-
if new_info.frozen:
180-
updated_to = f'{new_info.frozen} (frozen)'
172+
config_repos = [
173+
repo for repo in load_config(config_file)['repos']
174+
if repo['repo'] not in {LOCAL, META}
175+
]
176+
177+
rev_infos: list[RevInfo | None] = [None] * len(config_repos)
178+
jobs = jobs or xargs.cpu_count() # 0 => number of cpus
179+
jobs = min(jobs, len(repos) or len(config_repos)) # max 1-per-thread
180+
jobs = max(jobs, 1) # at least one thread
181+
with concurrent.futures.ThreadPoolExecutor(jobs) as exe:
182+
futures = [
183+
exe.submit(
184+
_update_one,
185+
i, repo, tags_only=tags_only, freeze=freeze,
186+
)
187+
for i, repo in enumerate(config_repos)
188+
if not repos or repo['repo'] in repos
189+
]
190+
for future in concurrent.futures.as_completed(futures):
191+
try:
192+
i, old, new = future.result()
193+
except RepositoryCannotBeUpdatedError as e:
194+
output.write_line(str(e))
195+
retv = 1
181196
else:
182-
updated_to = new_info.rev
183-
msg = f'updating {info.rev} -> {updated_to}.'
184-
output.write_line(msg)
185-
rev_infos.append(new_info)
186-
else:
187-
output.write_line('already up to date.')
188-
rev_infos.append(None)
197+
if new.rev != old.rev:
198+
changed = True
199+
if new.frozen:
200+
new_s = f'{new.frozen} (frozen)'
201+
else:
202+
new_s = new.rev
203+
msg = f'updating {old.rev} -> {new_s}'
204+
rev_infos[i] = new
205+
else:
206+
msg = 'already up to date!'
207+
208+
output.write_line(f'[{old.repo}] {msg}')
189209

190210
if changed:
191211
_write_new_config(config_file, rev_infos)

pre_commit/lang_base.py

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
from __future__ import annotations
22

33
import contextlib
4-
import multiprocessing
54
import os
65
import random
76
import re
@@ -15,9 +14,9 @@
1514

1615
import pre_commit.constants as C
1716
from pre_commit import parse_shebang
17+
from pre_commit import xargs
1818
from pre_commit.prefix import Prefix
1919
from pre_commit.util import cmd_output_b
20-
from pre_commit.xargs import xargs
2120

2221
FIXED_RANDOM_SEED = 1542676187
2322

@@ -140,10 +139,7 @@ def target_concurrency() -> int:
140139
if 'TRAVIS' in os.environ:
141140
return 2
142141
else:
143-
try:
144-
return multiprocessing.cpu_count()
145-
except NotImplementedError:
146-
return 1
142+
return xargs.cpu_count()
147143

148144

149145
def _shuffled(seq: Sequence[str]) -> list[str]:
@@ -171,7 +167,7 @@ def run_xargs(
171167
# ordering.
172168
file_args = _shuffled(file_args)
173169
jobs = target_concurrency()
174-
return xargs(cmd, file_args, target_concurrency=jobs, color=color)
170+
return xargs.xargs(cmd, file_args, target_concurrency=jobs, color=color)
175171

176172

177173
def hook_cmd(entry: str, args: Sequence[str]) -> tuple[str, ...]:

pre_commit/main.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,9 +226,13 @@ def _add_cmd(name: str, *, help: str) -> argparse.ArgumentParser:
226226
help='Store "frozen" hashes in `rev` instead of tag names',
227227
)
228228
autoupdate_parser.add_argument(
229-
'--repo', dest='repos', action='append', metavar='REPO',
229+
'--repo', dest='repos', action='append', metavar='REPO', default=[],
230230
help='Only update this repository -- may be specified multiple times.',
231231
)
232+
autoupdate_parser.add_argument(
233+
'-j', '--jobs', type=int, default=1,
234+
help='Number of threads to use. (default %(default)s).',
235+
)
232236

233237
_add_cmd('clean', help='Clean out pre-commit files.')
234238

@@ -372,6 +376,7 @@ def _add_cmd(name: str, *, help: str) -> argparse.ArgumentParser:
372376
tags_only=not args.bleeding_edge,
373377
freeze=args.freeze,
374378
repos=args.repos,
379+
jobs=args.jobs,
375380
)
376381
elif args.command == 'clean':
377382
return clean(store)

pre_commit/xargs.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import concurrent.futures
44
import contextlib
55
import math
6+
import multiprocessing
67
import os
78
import subprocess
89
import sys
@@ -22,6 +23,13 @@
2223
TRet = TypeVar('TRet')
2324

2425

26+
def cpu_count() -> int:
27+
try:
28+
return multiprocessing.cpu_count()
29+
except NotImplementedError:
30+
return 1
31+
32+
2533
def _environ_size(_env: MutableMapping[str, str] | None = None) -> int:
2634
environ = _env if _env is not None else getattr(os, 'environb', os.environ)
2735
size = 8 * len(environ) # number of pointers in `envp`

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad © 2024 Your Company Name. All rights reserved.





Check this box to remove all script contents from the fetched content.



Check this box to remove all images from the fetched content.


Check this box to remove all CSS styles from the fetched content.


Check this box to keep images inefficiently compressed and original size.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy