Skip to content

Commit 9ed5db0

Browse files
committed
pkgdev manifest: add --if-modified
Restrict targets for manifest to only targets that have uncommitted modifications. Resolves: #65 Signed-off-by: Arthur Zamarin <arthurzam@gentoo.org>
1 parent 5b16129 commit 9ed5db0

4 files changed

Lines changed: 86 additions & 7 deletions

File tree

completion/bash/pkgdev

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ _pkgdev() {
9898
-f --force
9999
-m --mirrors
100100
-d --distdir
101+
--if-modified
101102
"
102103

103104
case "${prev}" in

completion/zsh/_pkgdev

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ case $state in
5959
{'(--distdir)-d','(-d)--distdir'}'[target download directory]:distdir:_files -/' \
6060
{'(--force)-f','(-f)--force'}'[forcibly remanifest packages]' \
6161
{'(--mirrors)-m','(-m)--mirrors'}'[enable fetching from Gentoo mirrors]' \
62+
'--if-modified[only check packages that have uncommitted modifications]' \
6263
&& ret=0
6364
;;
6465
(mask)

src/pkgdev/scripts/pkgdev_manifest.py

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import os
2+
import re
3+
import subprocess
24

35
from pkgcore.operations import observer as observer_mod
46
from pkgcore.restrictions import packages
57
from pkgcore.util.parserestrict import parse_match
68
from snakeoil.cli import arghparse
79

8-
from .. import cli
10+
from .. import cli, git
911
from .argparsers import cwd_repo_argparser
1012

1113
manifest = cli.ArgumentParser(
@@ -43,26 +45,51 @@
4345
default because manifest generation is often performed when adding new
4446
ebuilds with distfiles that aren't on Gentoo mirrors yet.
4547
""")
48+
manifest_opts.add_argument(
49+
'--if-modified', dest='if_modified', help='Only check packages that have uncommitted modifications',
50+
action='store_true',
51+
docs="""
52+
In addition to matching the specified restriction, restrict to targets
53+
which are marked as modified by git, including untracked files.
54+
""")
4655

4756

48-
@manifest.bind_final_check
49-
def _manifest_validate(parser, namespace):
50-
targets = namespace.target if namespace.target else [namespace.cwd]
57+
def _restrict_targets(repo, targets):
5158
restrictions = []
52-
5359
for target in targets:
5460
if os.path.exists(target):
5561
try:
56-
restrictions.append(namespace.repo.path_restrict(target))
62+
restrictions.append(repo.path_restrict(target))
5763
except ValueError as e:
5864
manifest.error(e)
5965
else:
6066
try:
6167
restrictions.append(parse_match(target))
6268
except ValueError:
6369
manifest.error(f'invalid atom: {target!r}')
70+
return packages.OrRestriction(*restrictions)
71+
72+
73+
def _restrict_modified_files(repo):
74+
ebuild_re = re.compile(r'^[ MTARC?]{2} (?P<path>[^/]+/[^/]+/[^/]+\.ebuild)$')
75+
p = git.run('status', '--porcelain=v1', '-z', "*.ebuild",
76+
cwd=repo.location, stdout=subprocess.PIPE)
77+
78+
restrictions = []
79+
for line in p.stdout.strip('\x00').split('\x00'):
80+
if mo := ebuild_re.match(line):
81+
restrictions.append(repo.path_restrict(mo.group('path')))
82+
return packages.OrRestriction(*restrictions)
83+
84+
85+
@manifest.bind_final_check
86+
def _manifest_validate(parser, namespace):
87+
targets = namespace.target if namespace.target else [namespace.cwd]
6488

65-
namespace.restriction = packages.OrRestriction(*restrictions)
89+
namespace.restriction = _restrict_targets(namespace.repo, targets)
90+
if namespace.if_modified:
91+
namespace.restriction = packages.AndRestriction(namespace.restriction,
92+
_restrict_modified_files(namespace.repo))
6693

6794

6895
@manifest.bind_main_func

tests/scripts/test_pkgdev_manifest.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from functools import partial
2+
from typing import Set
23
from unittest.mock import patch
34

45
import pytest
@@ -44,6 +45,55 @@ def test_atom_target(self, repo, capsys, tool):
4445
matches = [x.cpvstr for x in repo.itermatch(options.restriction)]
4546
assert matches == ['cat/pkg-0']
4647

48+
def test_if_modified_target(self, repo, make_git_repo, tool):
49+
def manifest_matches() -> Set[str]:
50+
repo.sync()
51+
with chdir(repo.location):
52+
options, _ = tool.parse_args(['manifest', '--if-modified'])
53+
return {x.cpvstr for x in repo.itermatch(options.restriction)}
54+
55+
git_repo = make_git_repo(repo.location)
56+
repo.create_ebuild('cat/oldpkg-0')
57+
git_repo.add_all('cat/oldpkg-0')
58+
59+
# New package
60+
repo.create_ebuild('cat/newpkg-0')
61+
assert manifest_matches() == {'cat/newpkg-0'}
62+
git_repo.add_all('cat/newpkg-0')
63+
64+
# Untracked file
65+
ebuild_path = repo.create_ebuild('cat/newpkg-1')
66+
assert manifest_matches() == {'cat/newpkg-1'}
67+
68+
# Staged file
69+
git_repo.add(ebuild_path, commit=False)
70+
assert manifest_matches() == {'cat/newpkg-1'}
71+
72+
# No modified files
73+
git_repo.add_all('cat/newpkg-1')
74+
assert manifest_matches() == set()
75+
76+
# Modified file
77+
ebuild_path = repo.create_ebuild('cat/newpkg-1', eapi=8)
78+
assert manifest_matches() == {'cat/newpkg-1'}
79+
git_repo.add_all('cat/newpkg-1: eapi 8')
80+
81+
# Renamed file
82+
git_repo.remove(ebuild_path, commit=False)
83+
ebuild_path = repo.create_ebuild('cat/newpkg-2')
84+
git_repo.add(ebuild_path, commit=False)
85+
assert manifest_matches() == {'cat/newpkg-2'}
86+
git_repo.add_all('cat/newpkg-2: rename')
87+
88+
# Deleted file
89+
git_repo.remove(ebuild_path, commit=False)
90+
assert manifest_matches() == set()
91+
92+
# Deleted package
93+
ebuild_path = repo.create_ebuild('cat/newpkg-0')
94+
git_repo.remove(ebuild_path, commit=False)
95+
assert manifest_matches() == set()
96+
4797
def test_non_repo_dir_target(self, tmp_path, repo, capsys, tool):
4898
with pytest.raises(SystemExit) as excinfo, \
4999
chdir(repo.location):

0 commit comments

Comments
 (0)