-
Notifications
You must be signed in to change notification settings - Fork 1.7k
/
packagemanager.go
147 lines (120 loc) · 4.46 KB
/
packagemanager.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
// Adapted from https://github.com/replit/upm
// Copyright (c) 2019 Neoreason d/b/a Repl.it. All rights reserved.
// SPDX-License-Identifier: MIT
package packagemanager
import (
"fmt"
"path/filepath"
"github.com/pkg/errors"
"github.com/vercel/turbo/cli/internal/fs"
"github.com/vercel/turbo/cli/internal/globby"
"github.com/vercel/turbo/cli/internal/lockfile"
"github.com/vercel/turbo/cli/internal/turbopath"
)
// PackageManager is an abstraction across package managers
type PackageManager struct {
// The descriptive name of the Package Manager.
Name string
// The unique identifier of the Package Manager.
Slug string
// The command used to invoke the Package Manager.
Command string
// The location of the package spec file used by the Package Manager.
Specfile string
// The location of the package lock file used by the Package Manager.
Lockfile string
// The directory in which package assets are stored by the Package Manager.
PackageDir string
// The location of the file that defines the workspace. Empty if workspaces defined in package.json
WorkspaceConfigurationPath string
// The separator that the Package Manger uses to identify arguments that
// should be passed through to the underlying script.
ArgSeparator []string
// Return the list of workspace glob
getWorkspaceGlobs func(rootpath turbopath.AbsoluteSystemPath) ([]string, error)
// Return the list of workspace ignore globs
getWorkspaceIgnores func(pm PackageManager, rootpath turbopath.AbsoluteSystemPath) ([]string, error)
// Detect if Turbo knows how to produce a pruned workspace for the project
canPrune func(cwd turbopath.AbsoluteSystemPath) (bool, error)
// Read a lockfile for a given package manager
UnmarshalLockfile func(rootPackageJSON *fs.PackageJSON, contents []byte) (lockfile.Lockfile, error)
// Prune the given pkgJSON to only include references to the given patches
prunePatches func(pkgJSON *fs.PackageJSON, patches []turbopath.AnchoredUnixPath) error
}
var packageManagers = []PackageManager{
nodejsYarn,
nodejsBerry,
nodejsNpm,
nodejsPnpm,
nodejsPnpm6,
}
// GetPackageManager reads the package manager name sent by the Rust side
func GetPackageManager(name string) (packageManager *PackageManager, err error) {
switch name {
case "yarn":
return &nodejsYarn, nil
case "berry":
return &nodejsBerry, nil
case "npm":
return &nodejsNpm, nil
case "pnpm":
return &nodejsPnpm, nil
case "pnpm6":
return &nodejsPnpm6, nil
default:
return nil, errors.New("Unknown package manager")
}
}
// GetWorkspaces returns the list of package.json files for the current repository.
func (pm PackageManager) GetWorkspaces(rootpath turbopath.AbsoluteSystemPath) ([]string, error) {
globs, err := pm.getWorkspaceGlobs(rootpath)
if err != nil {
return nil, err
}
justJsons := make([]string, len(globs))
for i, space := range globs {
justJsons[i] = filepath.Join(space, "package.json")
}
ignores, err := pm.getWorkspaceIgnores(pm, rootpath)
if err != nil {
return nil, err
}
f, err := globby.GlobFiles(rootpath.ToStringDuringMigration(), justJsons, ignores)
if err != nil {
return nil, err
}
return f, nil
}
// GetWorkspaceIgnores returns an array of globs not to search for workspaces.
func (pm PackageManager) GetWorkspaceIgnores(rootpath turbopath.AbsoluteSystemPath) ([]string, error) {
return pm.getWorkspaceIgnores(pm, rootpath)
}
// CanPrune returns if turbo can produce a pruned workspace. Can error if fs issues occur
func (pm PackageManager) CanPrune(projectDirectory turbopath.AbsoluteSystemPath) (bool, error) {
if pm.canPrune != nil {
return pm.canPrune(projectDirectory)
}
return false, nil
}
// ReadLockfile will read the applicable lockfile into memory
func (pm PackageManager) ReadLockfile(projectDirectory turbopath.AbsoluteSystemPath, rootPackageJSON *fs.PackageJSON) (lockfile.Lockfile, error) {
if pm.UnmarshalLockfile == nil {
return nil, nil
}
contents, err := projectDirectory.UntypedJoin(pm.Lockfile).ReadFile()
if err != nil {
return nil, fmt.Errorf("reading %s: %w", pm.Lockfile, err)
}
lf, err := pm.UnmarshalLockfile(rootPackageJSON, contents)
if err != nil {
return nil, errors.Wrapf(err, "error in %v", pm.Lockfile)
}
return lf, nil
}
// PrunePatchedPackages will alter the provided pkgJSON to only reference the provided patches
func (pm PackageManager) PrunePatchedPackages(pkgJSON *fs.PackageJSON, patches []turbopath.AnchoredUnixPath) error {
if pm.prunePatches != nil {
return pm.prunePatches(pkgJSON, patches)
}
return nil
}