这是indexloc提供的服务,不要输入任何密码
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions cli/internal/context/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -419,3 +419,32 @@ func (c *Context) resolveDepGraph(wg *errgroup.Group, workspace *fs.PackageJSON,
})
}
}

// InternalDependencies finds all dependencies required by the slice of starting
// packages, as well as the starting packages themselves.
func (c *Context) InternalDependencies(start []string) ([]string, error) {
vertices := make(dag.Set)
for _, v := range start {
vertices.Add(v)
}
s := make(dag.Set)
memoFunc := func(v dag.Vertex, d int) error {
s.Add(v)
return nil
}

if err := c.WorkspaceGraph.DepthFirstWalk(vertices, memoFunc); err != nil {
return nil, err
}

// Use for loop so we can coerce to string
// .List() returns a list of interface{} types, but
// we know they are strings.
targets := make([]string, 0, s.Len())
for _, dep := range s.List() {
targets = append(targets, dep.(string))
}
sort.Strings(targets)

return targets, nil
}
44 changes: 21 additions & 23 deletions cli/internal/prune/prune.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package prune
import (
"bufio"
"fmt"
"strings"

"github.com/vercel/turbo/cli/internal/config"

Expand All @@ -21,13 +22,13 @@ import (
)

type opts struct {
scope string
scope []string
docker bool
outputDir string
}

func addPruneFlags(opts *opts, flags *pflag.FlagSet) {
flags.StringVar(&opts.scope, "scope", "", "Specify package to act as entry point for pruned monorepo (required).")
flags.StringArrayVar(&opts.scope, "scope", nil, "Specify package(s) to act as entry points for pruned monorepo (required).")
flags.BoolVar(&opts.docker, "docker", false, "Output pruned workspace into 'full' and 'json' directories optimized for Docker layer caching.")
flags.StringVar(&opts.outputDir, "out-dir", "out", "Set the root directory for files output by this command")
// No-op the cwd flag while the root level command is not yet cobra
Expand All @@ -53,7 +54,7 @@ func GetCmd(helper *cmdutil.Helper) *cobra.Command {
if err != nil {
return err
}
if opts.scope == "" {
if len(opts.scope) == 0 {
err := errors.New("at least one target must be specified")
base.LogError(err.Error())
return err
Expand Down Expand Up @@ -93,24 +94,28 @@ func (p *prune) prune(opts *opts) error {
if err != nil {
return errors.Wrap(err, "could not construct graph")
}
p.base.Logger.Trace("scope", "value", opts.scope)
target, scopeIsValid := ctx.WorkspaceInfos[opts.scope]
if !scopeIsValid {
return errors.Errorf("invalid scope: package %v not found", opts.scope)
}
outDir := p.base.RepoRoot.UntypedJoin(opts.outputDir)
fullDir := outDir
if opts.docker {
fullDir = fullDir.UntypedJoin("full")
}

p.base.Logger.Trace("target", "value", target.Name)
p.base.Logger.Trace("directory", "value", target.Dir)
p.base.Logger.Trace("external deps", "value", target.UnresolvedExternalDeps)
p.base.Logger.Trace("internal deps", "value", target.InternalDeps)
p.base.Logger.Trace("scope", "value", strings.Join(opts.scope, ", "))
p.base.Logger.Trace("docker", "value", opts.docker)
p.base.Logger.Trace("out dir", "value", outDir.ToString())

for _, scope := range opts.scope {
p.base.Logger.Trace("scope", "value", scope)
target, scopeIsValid := ctx.WorkspaceInfos[scope]
if !scopeIsValid {
return errors.Errorf("invalid scope: package %v not found", scope)
}
p.base.Logger.Trace("target", "value", target.Name)
p.base.Logger.Trace("directory", "value", target.Dir)
p.base.Logger.Trace("external deps", "value", target.UnresolvedExternalDeps)
p.base.Logger.Trace("internal deps", "value", target.InternalDeps)
}

canPrune, err := ctx.PackageManager.CanPrune(p.base.RepoRoot)
if err != nil {
return err
Expand All @@ -122,7 +127,7 @@ func (p *prune) prune(opts *opts) error {
return errors.New("Cannot prune without parsed lockfile")
}

p.base.UI.Output(fmt.Sprintf("Generating pruned monorepo for %v in %v", ui.Bold(opts.scope), ui.Bold(outDir.ToString())))
p.base.UI.Output(fmt.Sprintf("Generating pruned monorepo for %v in %v", ui.Bold(strings.Join(opts.scope, ", ")), ui.Bold(outDir.ToString())))

packageJSONPath := outDir.UntypedJoin("package.json")
if err := packageJSONPath.EnsureDir(); err != nil {
Expand All @@ -143,18 +148,11 @@ func (p *prune) prune(opts *opts) error {
}
}
workspaces := []turbopath.AnchoredSystemPath{}
targets := []string{opts.scope}
internalDeps, err := ctx.WorkspaceGraph.Ancestors(opts.scope)
targets, err := ctx.InternalDependencies(opts.scope)
if err != nil {
return errors.Wrap(err, "could find traverse the dependency graph to find topological dependencies")
}

// Use for loop so we can coerce to string
// .List() returns a list of interface{} types, but
// we know they are strings.
for _, dep := range internalDeps.List() {
targets = append(targets, dep.(string))
return errors.Wrap(err, "could not traverse the dependency graph to find topological dependencies")
}
p.base.Logger.Trace("targets", "value", targets)

lockfileKeys := make([]string, 0, len(rootPackageJSON.TransitiveDeps))
lockfileKeys = append(lockfileKeys, rootPackageJSON.TransitiveDeps...)
Expand Down