-
Notifications
You must be signed in to change notification settings - Fork 121
/
Copy pathlocal.go
193 lines (178 loc) · 6.28 KB
/
local.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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
/*
* Copyright IBM Corporation 2021
*
* 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 environment
import (
"bytes"
"errors"
"fmt"
"io/fs"
"net"
"os"
"os/exec"
"path/filepath"
"github.com/konveyor/move2kube/common"
"github.com/konveyor/move2kube/filesystem"
"github.com/konveyor/move2kube/types"
environmenttypes "github.com/konveyor/move2kube/types/environment"
"github.com/sirupsen/logrus"
)
// Local manages a local machine environment
type Local struct {
EnvInfo
WorkspaceSource string
WorkspaceContext string
GRPCQAReceiver net.Addr
}
// NewLocal creates a new Local environment
func NewLocal(envInfo EnvInfo, grpcQAReceiver net.Addr) (EnvironmentInstance, error) {
logrus.Trace("NewLocal start")
defer logrus.Trace("NewLocal end")
local := &Local{
EnvInfo: envInfo,
GRPCQAReceiver: grpcQAReceiver,
}
if envInfo.Isolated {
var err error
local.WorkspaceContext, err = os.MkdirTemp(local.TempPath, types.AppNameShort)
if err != nil {
return local, fmt.Errorf("failed to create the temp directory at path '%s' with pattern '%s' . Error: %w", local.TempPath, types.AppNameShort, err)
}
local.WorkspaceSource, err = os.MkdirTemp(local.TempPath, workspaceDir)
if err != nil {
return local, fmt.Errorf("failed to create the temp directory at path '%s' with pattern '%s' . Error: %w", local.TempPath, workspaceDir, err)
}
} else {
local.WorkspaceContext = local.Context
local.WorkspaceSource = local.Source
}
if err := local.Reset(); err != nil {
return local, fmt.Errorf("failed to reset the local environment. Error: %w", err)
}
return local, nil
}
// Reset resets the environment to fresh state
func (e *Local) Reset() error {
if e.Isolated {
if err := filesystem.Replicate(e.Context, e.WorkspaceContext); err != nil {
return fmt.Errorf("failed to copy contents from '%s' to directory '%s' . Error: %w", e.Context, e.WorkspaceContext, err)
}
if e.Source != "" {
if err := filesystem.Replicate(e.Source, e.WorkspaceSource); err != nil {
return fmt.Errorf("failed to copy contents from '%s' to directory '%s' . Error: %w", e.Source, e.WorkspaceSource, err)
}
}
}
return nil
}
// Stat returns stat info of the file/dir in the env
func (e *Local) Stat(name string) (fs.FileInfo, error) {
return os.Stat(name)
}
// Exec executes an executable within the environment
func (e *Local) Exec(cmd environmenttypes.Command, envList []string) (stdout string, stderr string, exitcode int, err error) {
if common.DisableLocalExecution {
return "", "", 0, fmt.Errorf("local execution prevented by %s flag", common.DisableLocalExecutionFlag)
}
var outb, errb bytes.Buffer
var execcmd *exec.Cmd
if len(cmd) > 0 {
execcmd = exec.Command(cmd[0], cmd[1:]...)
} else {
return "", "", 0, fmt.Errorf("no command found to execute")
}
execcmd.Dir = e.WorkspaceContext
execcmd.Stdout = &outb
execcmd.Stderr = &errb
execcmd.Env = e.getEnv()
execcmd.Env = append(execcmd.Env, envList...)
if err := execcmd.Run(); err != nil {
var ee *exec.ExitError
var pe *os.PathError
if errors.As(err, &ee) {
exitcode = ee.ExitCode()
err = nil
} else if errors.As(err, &pe) {
logrus.Errorf("PathError during execution of command: %v", pe)
err = pe
} else {
logrus.Errorf("Generic error during execution of command. Error: %q", err)
}
}
return outb.String(), errb.String(), exitcode, err
}
// Destroy destroys all artifacts specific to the environment
func (e *Local) Destroy() error {
if e.Isolated {
if err := os.RemoveAll(e.WorkspaceSource); err != nil {
return fmt.Errorf("failed to remove the workspace source directory '%s' . Error: %w", e.WorkspaceSource, err)
}
if err := os.RemoveAll(e.WorkspaceContext); err != nil {
return fmt.Errorf("failed to remove the workspace context directory '%s' . Error: %w", e.WorkspaceContext, err)
}
}
return nil
}
// Download downloads the path to outside the environment
func (e *Local) Download(sourcePath string) (string, error) {
destPath, err := os.MkdirTemp(e.TempPath, "*")
if err != nil {
return sourcePath, fmt.Errorf("failed to create the temp dir at path '%s' with pattern '*' . Error: %w", e.TempPath, err)
}
ps, err := os.Stat(sourcePath)
if err != nil {
return sourcePath, fmt.Errorf("failed to stat source directory at path '%s' . Error: %w", sourcePath, err)
}
if ps.Mode().IsRegular() {
destPath = filepath.Join(destPath, filepath.Base(sourcePath))
}
if err := filesystem.Replicate(sourcePath, destPath); err != nil {
return sourcePath, fmt.Errorf("failed to replicate in sync output from source path '%s' to destination path '%s' . Error: %w", sourcePath, destPath, err)
}
return destPath, nil
}
// Upload uploads the path from outside the environment into it
func (e *Local) Upload(sourcePath string) (string, error) {
destPath, err := os.MkdirTemp(e.TempPath, "*")
if err != nil {
return destPath, fmt.Errorf("failed to create the temp dir at path '%s' with pattern '*' . Error: %w", e.TempPath, err)
}
ps, err := os.Stat(sourcePath)
if err != nil {
return "", fmt.Errorf("failed to stat source '%s' . Error: %w", sourcePath, err)
}
if ps.Mode().IsRegular() {
destPath = filepath.Join(destPath, filepath.Base(sourcePath))
}
if err := filesystem.Replicate(sourcePath, destPath); err != nil {
return destPath, fmt.Errorf("failed to replicate in sync output from source path '%s' to destination path '%s' . Error: %w", sourcePath, destPath, err)
}
return destPath, nil
}
// GetContext returns the context of Local
func (e *Local) GetContext() string {
return e.WorkspaceContext
}
// GetSource returns the source of Local
func (e *Local) GetSource() string {
return e.WorkspaceSource
}
func (e *Local) getEnv() []string {
environ := os.Environ()
if e.GRPCQAReceiver != nil {
environ = append(environ, GRPCEnvName+"="+e.GRPCQAReceiver.String())
}
return environ
}