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/66278a9a0b69a69fde820d2b85a7e198eae52981

ref="https://github.githubassets.com/assets/global-d18f184ea1a06a2c.css" /> move logic for gc back to commands.gc · pre-commit/pre-commit@66278a9 · GitHub
Skip to content

Commit 66278a9

Browse files
committed
move logic for gc back to commands.gc
1 parent 1b32c50 commit 66278a9

4 files changed

Lines changed: 100 additions & 92 deletions

File tree

pre_commit/commands/gc.py

Lines changed: 90 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,98 @@
11
from __future__ import annotations
22

3+
import os.path
4+
from typing import Any
5+
6+
import pre_commit.constants as C
37
from pre_commit import output
8+
from pre_commit.clientlib import InvalidConfigError
9+
from pre_commit.clientlib import InvalidManifestError
10+
from pre_commit.clientlib import load_config
11+
from pre_commit.clientlib import load_manifest
12+
from pre_commit.clientlib import LOCAL
13+
from pre_commit.clientlib import META
414
from pre_commit.store import Store
15+
from pre_commit.util import rmtree
16+
17+
18+
def _mark_used_repos(
19+
store: Store,
20+
all_repos: dict[tuple[str, str], str],
21+
unused_repos: set[tuple[str, str]],
22+
repo: dict[str, Any],
23+
) -> None:
24+
if repo['repo'] == META:
25+
return
26+
elif repo['repo'] == LOCAL:
27+
for hook in repo['hooks']:
28+
deps = hook.get('additional_dependencies')
29+
unused_repos.discard((
30+
store.db_repo_name(repo['repo'], deps),
31+
C.LOCAL_REPO_VERSION,
32+
))
33+
else:
34+
key = (repo['repo'], repo['rev'])
35+
path = all_repos.get(key)
36+
# can't inspect manifest if it isn't cloned
37+
if path is None:
38+
return
39+
40+
try:
41+
manifest = load_manifest(os.path.join(path, C.MANIFEST_FILE))
42+
except InvalidManifestError:
43+
return
44+
else:
45+
unused_repos.discard(key)
46+
by_id = {hook['id']: hook for hook in manifest}
47+
48+
for hook in repo['hooks']:
49+
if hook['id'] not in by_id:
50+
continue
51+
52+
deps = hook.get(
53+
'additional_dependencies',
54+
by_id[hook['id']]['additional_dependencies'],
55+
)
56+
unused_repos.discard((
57+
store.db_repo_name(repo['repo'], deps), repo['rev'],
58+
))
59+
60+
61+
def _gc(store: Store) -> int:
62+
with store.exclusive_lock(), store.connect() as db:
63+
store._create_configs_table(db)
64+
65+
repos = db.execute('SELECT repo, ref, path FROM repos').fetchall()
66+
all_repos = {(repo, ref): path for repo, ref, path in repos}
67+
unused_repos = set(all_repos)
68+
69+
configs_rows = db.execute('SELECT path FROM configs').fetchall()
70+
configs = [path for path, in configs_rows]
71+
72+
dead_configs = []
73+
for config_path in configs:
74+
try:
75+
config = load_config(config_path)
76+
except InvalidConfigError:
77+
dead_configs.append(config_path)
78+
continue
79+
else:
80+
for repo in config['repos']:
81+
_mark_used_repos(store, all_repos, unused_repos, repo)
82+
83+
paths = [(path,) for path in dead_configs]
84+
db.executemany('DELETE FROM configs WHERE path = ?', paths)
85+
86+
db.executemany(
87+
'DELETE FROM repos WHERE repo = ? and ref = ?',
88+
sorted(unused_repos),
89+
)
90+
for k in unused_repos:
91+
rmtree(all_repos[k])
92+
93+
return len(unused_repos)
594

695

796
def gc(store: Store) -> int:
8-
output.write_line(f'{store.gc()} repo(s) removed.')
97+
output.write_line(f'{_gc(store)} repo(s) removed.')
998
return 0

pre_commit/store.py

Lines changed: 0 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
from collections.abc import Callable
99
from collections.abc import Generator
1010
from collections.abc import Sequence
11-
from typing import Any
1211

1312
import pre_commit.constants as C
1413
from pre_commit import clientlib
@@ -18,7 +17,6 @@
1817
from pre_commit.util import clean_path_on_failure
1918
from pre_commit.util import cmd_output_b
2019
from pre_commit.util import resource_text
21-
from pre_commit.util import rmtree
2220

2321

2422
logger = logging.getLogger('pre_commit')
@@ -235,81 +233,3 @@ def mark_config_used(self, path: str) -> None:
235233
# TODO: eventually remove this and only create in _create
236234
self._create_configs_table(db)
237235
db.execute('INSERT OR IGNORE INTO configs VALUES (?)', (path,))
238-
239-
def _mark_used_repos(
240-
self,
241-
all_repos: dict[tuple[str, str], str],
242-
unused_repos: set[tuple[str, str]],
243-
repo: dict[str, Any],
244-
) -> None:
245-
if repo['repo'] == clientlib.META:
246-
return
247-
elif repo['repo'] == clientlib.LOCAL:
248-
for hook in repo['hooks']:
249-
deps = hook.get('additional_dependencies')
250-
unused_repos.discard((
251-
self.db_repo_name(repo['repo'], deps),
252-
C.LOCAL_REPO_VERSION,
253-
))
254-
else:
255-
key = (repo['repo'], repo['rev'])
256-
path = all_repos.get(key)
257-
# can't inspect manifest if it isn't cloned
258-
if path is None:
259-
return
260-
261-
try:
262-
manifest = clientlib.load_manifest(
263-
os.path.join(path, C.MANIFEST_FILE),
264-
)
265-
except clientlib.InvalidManifestError:
266-
return
267-
else:
268-
unused_repos.discard(key)
269-
by_id = {hook['id']: hook for hook in manifest}
270-
271-
for hook in repo['hooks']:
272-
if hook['id'] not in by_id:
273-
continue
274-
275-
deps = hook.get(
276-
'additional_dependencies',
277-
by_id[hook['id']]['additional_dependencies'],
278-
)
279-
unused_repos.discard((
280-
self.db_repo_name(repo['repo'], deps), repo['rev'],
281-
))
282-
283-
def gc(self) -> int:
284-
with self.exclusive_lock(), self.connect() as db:
285-
self._create_configs_table(db)
286-
287-
repos = db.execute('SELECT repo, ref, path FROM repos').fetchall()
288-
all_repos = {(repo, ref): path for repo, ref, path in repos}
289-
unused_repos = set(all_repos)
290-
291-
configs_rows = db.execute('SELECT path FROM configs').fetchall()
292-
configs = [path for path, in configs_rows]
293-
294-
dead_configs = []
295-
for config_path in configs:
296-
try:
297-
config = clientlib.load_config(config_path)
298-
except clientlib.InvalidConfigError:
299-
dead_configs.append(config_path)
300-
continue
301-
else:
302-
for repo in config['repos']:
303-
self._mark_used_repos(all_repos, unused_repos, repo)
304-
305-
paths = [(path,) for path in dead_configs]
306-
db.executemany('DELETE FROM configs WHERE path = ?', paths)
307-
308-
db.executemany(
309-
'DELETE FROM repos WHERE repo = ? and ref = ?',
310-
sorted(unused_repos),
311-
)
312-
for k in unused_repos:
313-
rmtree(all_repos[k])
314-
315-
return len(unused_repos)

tests/commands/gc_test.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,3 +165,11 @@ def test_invalid_manifest_gcd(tempdir_factory, store, in_git_dir, cap_out):
165165
assert _config_count(store) == 1
166166
assert _repo_count(store) == 0
167167
assert cap_out.get().splitlines()[-1] == '1 repo(s) removed.'
168+
169+
170+
def test_gc_pre_1_14_roll_forward(store, cap_out):
171+
with store.connect() as db: # simulate pre-1.14.0
172+
db.executescript('DROP TABLE configs')
173+
174+
assert not gc(store)
175+
assert cap_out.get() == '0 repo(s) removed.\n'

tests/store_test.py

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -289,18 +289,9 @@ def test_mark_config_as_used_does_not_exist(store):
289289
assert _select_all_configs(store) == []
290290

291291

292-
def _simulate_pre_1_14_0(store):
293-
with store.connect() as db:
294-
db.executescript('DROP TABLE configs')
295-
296-
297-
def test_gc_roll_forward(store):
298-
_simulate_pre_1_14_0(store)
299-
assert store.gc() == 0
300-
301-
302292
def test_mark_config_as_used_roll_forward(store, tmpdir):
303-
_simulate_pre_1_14_0(store)
293+
with store.connect() as db: # simulate pre-1.14.0
294+
db.executescript('DROP TABLE configs')
304295
test_mark_config_as_used(store, tmpdir)
305296

306297

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