|
7 | 7 | safelibs.py port [libname ...] |
8 | 8 | safelibs.py port --jobs 4 |
9 | 9 | safelibs.py port [libname ...] --filter-upgradeable |
| 10 | + safelibs.py port [libname ...] --filter-tag 04-test |
10 | 11 | safelibs.py port --from-validator |
11 | 12 | safelibs.py port [libname ...] -L [logfile] |
12 | 13 | safelibs.py port [libname ...] --from 01-recon |
@@ -1418,6 +1419,27 @@ def _find_last_tagged_phase_index(workdir, libname, phases, log_handle=None): |
1418 | 1419 | return matches[-1] |
1419 | 1420 |
|
1420 | 1421 |
|
| 1422 | +def _tag_in_history(workdir, libname, phase, log_handle=None): |
| 1423 | + """Return True if libname/phase is reachable from HEAD in workdir.""" |
| 1424 | + if not _workdir_has_git_history(workdir, log_handle=log_handle): |
| 1425 | + return False |
| 1426 | + tag = f"{libname}/{phase}" |
| 1427 | + result = subprocess.run( |
| 1428 | + ["git", "tag", "--merged", "HEAD", "--list", tag], |
| 1429 | + cwd=workdir, |
| 1430 | + capture_output=True, |
| 1431 | + text=True, |
| 1432 | + ) |
| 1433 | + if result.returncode != 0: |
| 1434 | + _emit( |
| 1435 | + f"Failed to check tag {tag} in {workdir}: {result.stderr.strip()}", |
| 1436 | + log_handle=log_handle, |
| 1437 | + stream=sys.stderr, |
| 1438 | + ) |
| 1439 | + return False |
| 1440 | + return tag in result.stdout.splitlines() |
| 1441 | + |
| 1442 | + |
1421 | 1443 | def _workdir_has_git_history(workdir, log_handle=None): |
1422 | 1444 | if not os.path.exists(os.path.join(workdir, ".git")): |
1423 | 1445 | return False |
@@ -1945,6 +1967,16 @@ def _build_parser(): |
1945 | 1967 | "when it does not." |
1946 | 1968 | ), |
1947 | 1969 | ) |
| 1970 | + parser.add_argument( |
| 1971 | + "--filter-tag", |
| 1972 | + dest="filter_tag", |
| 1973 | + metavar="PHASE", |
| 1974 | + default=None, |
| 1975 | + help=( |
| 1976 | + "For 'port', skip libraries whose port checkout does not have a " |
| 1977 | + "<libname>/PHASE tag reachable from HEAD (e.g. '04-test')." |
| 1978 | + ), |
| 1979 | + ) |
1948 | 1980 | parser.add_argument( |
1949 | 1981 | "--from-validator", |
1950 | 1982 | action="store_true", |
@@ -2871,6 +2903,26 @@ def _round_robin_ports(args, scripts, phases, log_handle=None, log_path=None): |
2871 | 2903 | ) |
2872 | 2904 | sys.exit(1) |
2873 | 2905 |
|
| 2906 | + filter_tag = getattr(args, "filter_tag", None) |
| 2907 | + if filter_tag: |
| 2908 | + kept_repos = [] |
| 2909 | + for repo in repos: |
| 2910 | + if _tag_in_history(repo["workdir"], repo["libname"], filter_tag, log_handle=log_handle): |
| 2911 | + kept_repos.append(repo) |
| 2912 | + else: |
| 2913 | + _emit( |
| 2914 | + f"--filter-tag: skipping {repo['libname']} " |
| 2915 | + f"(no {repo['libname']}/{filter_tag} tag reachable from HEAD).", |
| 2916 | + log_handle=log_handle, |
| 2917 | + ) |
| 2918 | + _emit( |
| 2919 | + f"--filter-tag {filter_tag}: kept {len(kept_repos)} of {len(repos)} known port(s).", |
| 2920 | + log_handle=log_handle, |
| 2921 | + ) |
| 2922 | + if not kept_repos: |
| 2923 | + return |
| 2924 | + repos = kept_repos |
| 2925 | + |
2874 | 2926 | if jobs <= 1: |
2875 | 2927 | _emit( |
2876 | 2928 | f"Round-robin porting {len(repos)} known port(s).", |
@@ -3076,6 +3128,38 @@ def _run_pipeline(args, log_handle=None, log_path=None): |
3076 | 3128 | ) |
3077 | 3129 | sys.exit(1) |
3078 | 3130 |
|
| 3131 | + filter_tag = getattr(args, "filter_tag", None) |
| 3132 | + if filter_tag and _find_phase_index(phases, filter_tag) is None: |
| 3133 | + _emit( |
| 3134 | + f"Unknown phase '{filter_tag}' for --filter-tag. Available: {phases}", |
| 3135 | + log_handle=log_handle, |
| 3136 | + stream=sys.stderr, |
| 3137 | + ) |
| 3138 | + sys.exit(1) |
| 3139 | + |
| 3140 | + if filter_tag and libnames: |
| 3141 | + ports_dir = os.path.abspath(getattr(args, "ports_dir", DEFAULT_PORTS_DIR)) |
| 3142 | + github_prefix = getattr(args, "github_prefix", DEFAULT_PORT_REPO_PREFIX) |
| 3143 | + kept = [] |
| 3144 | + for libname in libnames: |
| 3145 | + workdir = _default_port_workdir(libname, ports_dir, github_prefix) |
| 3146 | + if _tag_in_history(workdir, libname, filter_tag, log_handle=log_handle): |
| 3147 | + kept.append(libname) |
| 3148 | + else: |
| 3149 | + _emit( |
| 3150 | + f"--filter-tag: skipping {libname} " |
| 3151 | + f"(no {libname}/{filter_tag} tag reachable from HEAD).", |
| 3152 | + log_handle=log_handle, |
| 3153 | + ) |
| 3154 | + _emit( |
| 3155 | + f"--filter-tag {filter_tag}: kept {len(kept)} of {len(libnames)} library(ies).", |
| 3156 | + log_handle=log_handle, |
| 3157 | + ) |
| 3158 | + if not kept: |
| 3159 | + return |
| 3160 | + libnames = kept |
| 3161 | + args.libname = list(libnames) |
| 3162 | + |
3079 | 3163 | if not libnames: |
3080 | 3164 | _round_robin_ports(args, scripts, phases, log_handle=log_handle, log_path=log_path) |
3081 | 3165 | return |
@@ -3122,6 +3206,8 @@ def main(): |
3122 | 3206 | ) |
3123 | 3207 | if args.filter_upgradeable: |
3124 | 3208 | parser.error("--filter-upgradeable can only be used with action 'port'") |
| 3209 | + if args.filter_tag: |
| 3210 | + parser.error("--filter-tag can only be used with action 'port'") |
3125 | 3211 | if args.create_github: |
3126 | 3212 | parser.error("--create-github can only be used with action 'port'") |
3127 | 3213 | if args.push_github: |
|
0 commit comments