aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/cli/internal/packagemanager/yarn.go
diff options
context:
space:
mode:
author简律纯 <hsiangnianian@outlook.com>2023-04-28 01:36:44 +0800
committer简律纯 <hsiangnianian@outlook.com>2023-04-28 01:36:44 +0800
commitdd84b9d64fb98746a230cd24233ff50a562c39c9 (patch)
treeb583261ef00b3afe72ec4d6dacb31e57779a6faf /cli/internal/packagemanager/yarn.go
parent0b46fcd72ac34382387b2bcf9095233efbcc52f4 (diff)
downloadHydroRoll-dd84b9d64fb98746a230cd24233ff50a562c39c9.tar.gz
HydroRoll-dd84b9d64fb98746a230cd24233ff50a562c39c9.zip
Diffstat (limited to 'cli/internal/packagemanager/yarn.go')
-rw-r--r--cli/internal/packagemanager/yarn.go116
1 files changed, 116 insertions, 0 deletions
diff --git a/cli/internal/packagemanager/yarn.go b/cli/internal/packagemanager/yarn.go
new file mode 100644
index 0000000..8779c5f
--- /dev/null
+++ b/cli/internal/packagemanager/yarn.go
@@ -0,0 +1,116 @@
+package packagemanager
+
+import (
+ "errors"
+ "fmt"
+ "os/exec"
+ "path/filepath"
+ "strings"
+
+ "github.com/Masterminds/semver"
+ "github.com/vercel/turbo/cli/internal/fs"
+ "github.com/vercel/turbo/cli/internal/lockfile"
+ "github.com/vercel/turbo/cli/internal/turbopath"
+)
+
+// NoWorkspacesFoundError is a custom error used so that upstream implementations can switch on it
+type NoWorkspacesFoundError struct{}
+
+func (e *NoWorkspacesFoundError) Error() string {
+ return "package.json: no workspaces found. Turborepo requires Yarn workspaces to be defined in the root package.json"
+}
+
+var nodejsYarn = PackageManager{
+ Name: "nodejs-yarn",
+ Slug: "yarn",
+ Command: "yarn",
+ Specfile: "package.json",
+ Lockfile: "yarn.lock",
+ PackageDir: "node_modules",
+ ArgSeparator: []string{"--"},
+
+ getWorkspaceGlobs: func(rootpath turbopath.AbsoluteSystemPath) ([]string, error) {
+ pkg, err := fs.ReadPackageJSON(rootpath.UntypedJoin("package.json"))
+ if err != nil {
+ return nil, fmt.Errorf("package.json: %w", err)
+ }
+ if len(pkg.Workspaces) == 0 {
+ return nil, &NoWorkspacesFoundError{}
+ }
+ return pkg.Workspaces, nil
+ },
+
+ getWorkspaceIgnores: func(pm PackageManager, rootpath turbopath.AbsoluteSystemPath) ([]string, error) {
+ // function: https://github.com/yarnpkg/yarn/blob/3119382885ea373d3c13d6a846de743eca8c914b/src/config.js#L799
+
+ // Yarn is unique in ignore patterns handling.
+ // The only time it does globbing is for package.json or yarn.json and it scopes the search to each workspace.
+ // For example: `apps/*/node_modules/**/+(package.json|yarn.json)`
+ // The `extglob` `+(package.json|yarn.json)` (from micromatch) after node_modules/** is redundant.
+
+ globs, err := pm.getWorkspaceGlobs(rootpath)
+ if err != nil {
+ // In case of a non-monorepo, the workspaces field is empty and only node_modules in the root should be ignored
+ var e *NoWorkspacesFoundError
+ if errors.As(err, &e) {
+ return []string{"node_modules/**"}, nil
+ }
+
+ return nil, err
+ }
+
+ ignores := make([]string, len(globs))
+
+ for i, glob := range globs {
+ ignores[i] = filepath.Join(glob, "/node_modules/**")
+ }
+
+ return ignores, nil
+ },
+
+ canPrune: func(cwd turbopath.AbsoluteSystemPath) (bool, error) {
+ return true, nil
+ },
+
+ // Versions older than 2.0 are yarn, after that they become berry
+ Matches: func(manager string, version string) (bool, error) {
+ if manager != "yarn" {
+ return false, nil
+ }
+
+ v, err := semver.NewVersion(version)
+ if err != nil {
+ return false, fmt.Errorf("could not parse yarn version: %w", err)
+ }
+ c, err := semver.NewConstraint("<2.0.0-0")
+ if err != nil {
+ return false, fmt.Errorf("could not create constraint: %w", err)
+ }
+
+ return c.Check(v), nil
+ },
+
+ // Detect for yarn needs to identify which version of yarn is running on the system.
+ detect: func(projectDirectory turbopath.AbsoluteSystemPath, packageManager *PackageManager) (bool, error) {
+ specfileExists := projectDirectory.UntypedJoin(packageManager.Specfile).FileExists()
+ lockfileExists := projectDirectory.UntypedJoin(packageManager.Lockfile).FileExists()
+
+ // Short-circuit, definitely not Yarn.
+ if !specfileExists || !lockfileExists {
+ return false, nil
+ }
+
+ cmd := exec.Command("yarn", "--version")
+ cmd.Dir = projectDirectory.ToString()
+ out, err := cmd.Output()
+ if err != nil {
+ return false, fmt.Errorf("could not detect yarn version: %w", err)
+ }
+
+ return packageManager.Matches(packageManager.Slug, strings.TrimSpace(string(out)))
+ },
+
+ UnmarshalLockfile: func(_rootPackageJSON *fs.PackageJSON, contents []byte) (lockfile.Lockfile, error) {
+ return lockfile.DecodeYarnLockfile(contents)
+ },
+}