1 package sync
2
3 import (
4 taro "archive/tar"
5 "bytes"
6 "context"
7 "fmt"
8 "io"
9 "os"
10 "os/exec"
11 "path/filepath"
12 "strings"
13
14 "github.com/redhat-developer/odo/pkg/log"
15 "github.com/redhat-developer/odo/pkg/testingutil/filesystem"
16 "github.com/redhat-developer/odo/pkg/util"
17
18 dfutil "github.com/devfile/library/v2/pkg/util"
19 gitignore "github.com/sabhiram/go-gitignore"
20
21 "k8s.io/klog"
22 )
23
24
25
26
27
28
29 func (a SyncClient) CopyFile(ctx context.Context, localPath string, compInfo ComponentInfo, targetPath string, copyFiles []string, globExps []string, ret util.IndexerRet) error {
30
31
32
33 dest := filepath.ToSlash(filepath.Join(targetPath, filepath.Base(localPath)))
34 targetPath = filepath.ToSlash(targetPath)
35
36 klog.V(4).Infof("CopyFile arguments: localPath %s, dest %s, targetPath %s, copyFiles %s, globalExps %s", localPath, dest, targetPath, copyFiles, globExps)
37 reader, writer := io.Pipe()
38
39 go func() {
40 defer writer.Close()
41
42 err := makeTar(localPath, dest, writer, copyFiles, globExps, ret, filesystem.DefaultFs{})
43 if err != nil {
44 log.Errorf("Error while creating tar: %#v", err)
45 os.Exit(1)
46 }
47 }()
48
49 err := a.ExtractProjectToComponent(ctx, compInfo.ContainerName, compInfo.PodName, targetPath, reader)
50 if err != nil {
51 return err
52 }
53
54 return nil
55 }
56
57
58 func (a SyncClient) ExtractProjectToComponent(ctx context.Context, containerName, podName, targetPath string, stdin io.Reader) error {
59
60 cmdArr := []string{"tar", "xf", "-", "-C", targetPath, "--no-same-owner"}
61 var stdout bytes.Buffer
62 var stderr bytes.Buffer
63 klog.V(3).Infof("Executing command %s", strings.Join(cmdArr, " "))
64 err := a.platformClient.ExecCMDInContainer(ctx, containerName, podName, cmdArr, &stdout, &stderr, stdin, false)
65 if err != nil {
66 log.Errorf("Command '%s' in container failed.\n", strings.Join(cmdArr, " "))
67 log.Errorf("stdout: %s\n", stdout.String())
68 log.Errorf("stderr: %s\n", stderr.String())
69 log.Errorf("err: %s\n", err.Error())
70 if exiterr, ok := err.(*exec.ExitError); ok {
71 log.Errorf("exit err: %s\n", string(exiterr.Stderr))
72 }
73 }
74 return err
75 }
76
77
78 func checkFileExistWithFS(fileName string, fs filesystem.Filesystem) bool {
79 _, err := fs.Stat(fileName)
80 return !os.IsNotExist(err)
81 }
82
83
84
85 func makeTar(srcPath, destPath string, writer io.Writer, files []string, globExps []string, ret util.IndexerRet, fs filesystem.Filesystem) error {
86
87 tarWriter := taro.NewWriter(writer)
88 defer tarWriter.Close()
89 srcPath = filepath.Clean(srcPath)
90
91
92
93
94 destPath = filepath.ToSlash(filepath.Clean(destPath))
95 uniquePaths := make(map[string]bool)
96 klog.V(4).Infof("makeTar arguments: srcPath: %s, destPath: %s, files: %+v", srcPath, destPath, files)
97 if len(files) != 0 {
98 ignoreMatcher := gitignore.CompileIgnoreLines(globExps...)
99 for _, fileName := range files {
100
101 if _, ok := uniquePaths[fileName]; ok {
102 continue
103 } else {
104 uniquePaths[fileName] = true
105 }
106
107 if checkFileExistWithFS(fileName, fs) {
108
109 rel, err := filepath.Rel(srcPath, fileName)
110 if err != nil {
111 return err
112 }
113
114 matched := ignoreMatcher.MatchesPath(rel)
115 if matched {
116 continue
117 }
118
119
120
121
122
123 fileAbsolutePath, err := dfutil.GetAbsPath(fileName)
124 if err != nil {
125 return err
126 }
127 klog.V(4).Infof("Got abs path: %s", fileAbsolutePath)
128 klog.V(4).Infof("Making %s relative to %s", srcPath, fileAbsolutePath)
129
130
131
132 destFile, err := filepath.Rel(filepath.FromSlash(srcPath), filepath.FromSlash(fileAbsolutePath))
133 if err != nil {
134 return err
135 }
136
137
138 srcFile := filepath.Join(filepath.Base(srcPath), destFile)
139
140 if value, ok := ret.NewFileMap[destFile]; ok && value.RemoteAttribute != "" {
141 destFile = value.RemoteAttribute
142 }
143
144 klog.V(4).Infof("makeTar srcFile: %s", srcFile)
145 klog.V(4).Infof("makeTar destFile: %s", destFile)
146
147
148 err = linearTar(filepath.Dir(srcPath), srcFile, filepath.Dir(destPath), destFile, tarWriter, fs)
149 if err != nil {
150 return err
151 }
152 }
153 }
154 }
155
156 return nil
157 }
158
159
160 func linearTar(srcBase, srcFile, destBase, destFile string, tw *taro.Writer, fs filesystem.Filesystem) error {
161 if destFile == "" {
162 return fmt.Errorf("linear Tar error, destFile cannot be empty")
163 }
164
165 klog.V(4).Infof("recursiveTar arguments: srcBase: %s, srcFile: %s, destBase: %s, destFile: %s", srcBase, srcFile, destBase, destFile)
166
167
168
169 destBase = filepath.ToSlash(destBase)
170 destFile = filepath.ToSlash(destFile)
171 klog.V(4).Infof("Corrected destinations: base: %s file: %s", destBase, destFile)
172
173 joinedPath := filepath.Join(srcBase, srcFile)
174
175 stat, err := fs.Stat(joinedPath)
176 if err != nil {
177 return err
178 }
179
180 if stat.IsDir() {
181 files, err := fs.ReadDir(joinedPath)
182 if err != nil {
183 return err
184 }
185 if len(files) == 0 {
186
187 hdr, _ := taro.FileInfoHeader(stat, joinedPath)
188 hdr.Name = destFile
189 if err := tw.WriteHeader(hdr); err != nil {
190 return err
191 }
192 }
193 return nil
194 } else if stat.Mode()&os.ModeSymlink != 0 {
195
196 hdr, _ := taro.FileInfoHeader(stat, joinedPath)
197 target, err := os.Readlink(joinedPath)
198 if err != nil {
199 return err
200 }
201
202 hdr.Linkname = target
203 hdr.Name = destFile
204 if err := tw.WriteHeader(hdr); err != nil {
205 return err
206 }
207 } else {
208
209 hdr, err := taro.FileInfoHeader(stat, joinedPath)
210 if err != nil {
211 return err
212 }
213 hdr.Name = destFile
214
215 err = tw.WriteHeader(hdr)
216 if err != nil {
217 return err
218 }
219
220 f, err := fs.Open(joinedPath)
221 if err != nil {
222 return err
223 }
224 defer f.Close()
225
226 if _, err := io.Copy(tw, f); err != nil {
227 return err
228 }
229
230 return f.Close()
231 }
232
233 return nil
234 }
235
View as plain text