feat(vendor): --exclude plus content-type selection (--types/--exclude-types)

vendor add gains --exclude a,b,c (all mode minus those ids) as the mirror
of --include, for taking the majority of a source while dropping a few
items. Mutual exclusion with --include is a hard error, unknown ids fail
naming the available ones (generalized checkIDEntries).

vendor add and vendor select gain --types (allow-list) and --exclude-types
(deny-list) over the four content types. The filter is stored as the
optional, v2-compatible Selection.exclude_types field and survives vendor
update: new upstream items of an excluded type never enter the work
repository (unlike id expansion, which would silently re-admit them).
--types/--exclude-types replace the filter on select, absent flags keep
it, and --mode all clears it along with include/exclude.

Also fixes materializeTree to create the staging directory for an empty
selection — previously select-to-zero failed at the staging rename.
This commit is contained in:
m3ta-chiron committed 2026-10-02 12:35:39 +02:00
1 parent 1ab97bff43
commit 0c779bc970
9 files changed
+533 -50

No files matched your search

+6 -1
View File
@@ -197,7 +197,7 @@ func computeUpdate(workDir string, lf *lockfile.Lockfile, name string, withColli
}
if src.Selection.Mode == lockfile.ModeInclude {
if err := checkIncludeEntries(items, src.Selection.Include, name); err != nil {
if err := checkIDEntries(items, src.Selection.Include, name, "include"); err != nil {
return nil, err
}
}
@@ -250,6 +250,11 @@ func cleanupStaleStaging(workDir string) {
}
func materializeTree(tree discovery.Tree, selected []discovery.Item, renames map[string]string, dst string) error {
// Create dst even for an empty selection: the caller swaps it in with a
// rename, which fails when nothing materialized the directory.
if err := os.MkdirAll(dst, 0o755); err != nil {
return err
}
for _, it := range selected {
dep := deployedName(it.UpstreamID, renames)
base := filepath.Join(dst, it.Type)