-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
install.go
162 lines (139 loc) 路 5.1 KB
/
install.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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
// Copyright 2016-2023, Pulumi Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"fmt"
"io"
"os"
"time"
"github.com/opentracing/opentracing-go"
"github.com/pulumi/pulumi/sdk/v3/go/common/resource/plugin"
"github.com/pulumi/pulumi/sdk/v3/go/common/util/logging"
"github.com/spf13/cobra"
"github.com/pulumi/pulumi/pkg/v3/backend/display"
"github.com/pulumi/pulumi/pkg/v3/engine"
"github.com/pulumi/pulumi/sdk/v3/go/common/diag"
"github.com/pulumi/pulumi/sdk/v3/go/common/util/cmdutil"
"github.com/pulumi/pulumi/sdk/v3/go/common/workspace"
)
func newInstallCmd() *cobra.Command {
var reinstall bool
var noPlugins, noDependencies bool
cmd := &cobra.Command{
Use: "install",
Args: cmdutil.NoArgs,
Short: "Install packages and plugins for the current program",
Long: "Install packages and plugins for the current program.\n" +
"\n" +
"This command is used to manually install packages and plugins required by your program.",
Run: cmdutil.RunFunc(func(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
displayOpts := display.Options{
Color: cmdutil.GetGlobalColorization(),
}
// Load the project
proj, root, err := readProject()
if err != nil {
return err
}
span := opentracing.SpanFromContext(ctx)
projinfo := &engine.Projinfo{Proj: proj, Root: root}
pwd, main, pctx, err := engine.ProjectInfoContext(
projinfo,
nil,
cmdutil.Diag(),
cmdutil.Diag(),
false,
span,
nil,
)
if err != nil {
return err
}
defer pctx.Close()
// First make sure the language plugin is present. We need this to load the required resource plugins.
// TODO: we need to think about how best to version this. For now, it always picks the latest.
runtime := proj.Runtime
programInfo := plugin.NewProgramInfo(pctx.Root, pwd, main, runtime.Options())
lang, err := pctx.Host.LanguageRuntime(runtime.Name(), programInfo)
if err != nil {
return fmt.Errorf("load language plugin %s: %w", runtime.Name(), err)
}
if !noDependencies {
if err = lang.InstallDependencies(programInfo); err != nil {
return fmt.Errorf("installing dependencies: %w", err)
}
}
if !noPlugins {
// Compute the set of plugins the current project needs.
installs, err := lang.GetRequiredPlugins(programInfo)
if err != nil {
return err
}
// Now for each kind, name, version pair, download it from the release website, and install it.
for _, install := range installs {
// PluginSpec.String() just returns the name and version, we want the kind too.
label := fmt.Sprintf("%s plugin %s", install.Kind, install)
// If the plugin already exists, don't download it unless --reinstall was passed.
if !reinstall {
if install.Version != nil {
if workspace.HasPlugin(install) {
logging.V(1).Infof("%s skipping install (existing == match)", label)
continue
}
} else {
if has, _ := workspace.HasPluginGTE(install); has {
logging.V(1).Infof("%s skipping install (existing >= match)", label)
continue
}
}
}
pctx.Diag.Infoerrf(diag.Message("", "%s installing"), label)
// If we got here, actually try to do the download.
withProgress := func(stream io.ReadCloser, size int64) io.ReadCloser {
return workspace.ReadCloserProgressBar(stream, size, "Downloading plugin", displayOpts.Color)
}
retry := func(err error, attempt int, limit int, delay time.Duration) {
pctx.Diag.Warningf(
diag.Message("", "Error downloading plugin: %s\nWill retry in %v [%d/%d]"), err, delay, attempt, limit)
}
r, err := workspace.DownloadToFile(install, withProgress, retry)
if err != nil {
return fmt.Errorf("%s downloading from %s: %w", label, install.PluginDownloadURL, err)
}
defer func() {
err := os.Remove(r.Name())
if err != nil {
pctx.Diag.Warningf(
diag.Message("", "Error removing temporary file %s: %s"), r.Name(), err)
}
}()
payload := workspace.TarPlugin(r)
logging.V(1).Infof("%s installing tarball ...", label)
if err = install.InstallWithContext(ctx, payload, reinstall); err != nil {
return fmt.Errorf("installing %s: %w", label, err)
}
}
}
return nil
}),
}
cmd.PersistentFlags().BoolVar(&reinstall,
"reinstall", false, "Reinstall a plugin even if it already exists")
cmd.PersistentFlags().BoolVar(&noPlugins,
"no-plugins", false, "Skip installing plugins")
cmd.PersistentFlags().BoolVar(&noDependencies,
"no-dependencies", false, "Skip installing dependencies")
return cmd
}