Skip to content

Commit 572f347

Browse files
authored
Merge pull request #174 from covexo/sync-improvements
Sync improvements
2 parents 477adb9 + d2ad98c commit 572f347

10 files changed

Lines changed: 387 additions & 266 deletions

File tree

cmd/status_sync.go

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import (
1515
"github.com/spf13/cobra"
1616
)
1717

18-
var initialSyncCompleted = regexp.MustCompile(`^\[Sync\] Initial sync completed\. Processed (\d+) changes$`)
1918
var syncStopped = regexp.MustCompile(`^\[Sync\] Sync stopped$`)
2019
var downstreamChanges = regexp.MustCompile(`^\[Downstream\] Successfully processed (\d+) change\(s\)$`)
2120
var upstreamChanges = regexp.MustCompile(`^\[Upstream\] Successfully processed (\d+) change\(s\)$`)
@@ -180,12 +179,6 @@ func updateSyncMap(syncMap map[string]*syncStatus, jsonMap map[string]string) er
180179
syncMap[identifier].Status = "Error"
181180
syncMap[identifier].Error = message
182181
syncMap[identifier].LastActivityTime = time
183-
} else if matches := initialSyncCompleted.FindStringSubmatch(message); len(matches) == 2 {
184-
syncMap[identifier].LastActivity = "Initially transferred " + matches[1] + " changes"
185-
syncMap[identifier].LastActivityTime = time
186-
187-
changes, _ := strconv.Atoi(matches[1])
188-
syncMap[identifier].TotalChanges += changes
189182
} else if matches := downstreamChanges.FindStringSubmatch(message); len(matches) == 2 {
190183
syncMap[identifier].LastActivity = "Downloaded " + matches[1] + " changes"
191184
syncMap[identifier].LastActivityTime = time

cmd/up.go

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -156,16 +156,12 @@ func (cmd *UpCmd) Run(cobraCmd *cobra.Command, args []string) {
156156
}
157157
}
158158

159-
if cmd.flags.deploy || shouldRebuild {
159+
// Check if we find a running release pod
160+
pod, err := getRunningDevSpacePod(cmd.helm, cmd.kubectl)
161+
162+
if err != nil || cmd.flags.deploy || shouldRebuild {
160163
cmd.deployChart()
161164
} else {
162-
// Check if we find a running release pod
163-
pod, err := getRunningDevSpacePod(cmd.helm, cmd.kubectl)
164-
165-
if err != nil {
166-
log.Fatalf("Couldn't find running devspace pod: %s", err.Error())
167-
}
168-
169165
cmd.pod = pod
170166
}
171167

pkg/devspace/sync/downstream.go

Lines changed: 19 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"os"
99
"os/exec"
1010
"path"
11+
"path/filepath"
1112
"strconv"
1213
"strings"
1314
"time"
@@ -87,7 +88,9 @@ func (d *downstream) populateFileMap() error {
8788
defer d.config.fileIndex.fileMapMutex.Unlock()
8889

8990
for _, element := range createFiles {
90-
d.config.fileIndex.fileMap[element.Name] = element
91+
if d.config.fileIndex.fileMap[element.Name] == nil {
92+
d.config.fileIndex.fileMap[element.Name] = element
93+
}
9194
}
9295

9396
return nil
@@ -328,36 +331,28 @@ func (d *downstream) removeFilesAndFolders(removeFiles map[string]*fileInformati
328331
d.config.Logf("[Downstream] Remove %d files", numRemoveFiles)
329332
}
330333

331-
// A file is only deleted if the following conditions are met:
332-
// - The file name is present in the d.config.fileMap map
333-
// - The file did not change in terms of size and mtime in the d.config.fileMap since we started the collecting changes process
334-
// - The file is present on the filesystem and did not change in terms of size and mtime on the filesystem
335334
for key, value := range removeFiles {
336-
if value != nil && fileMap[key] != nil {
337-
// Exclude files on the exclude list
338-
if d.config.downloadIgnoreMatcher != nil {
339-
if d.config.downloadIgnoreMatcher.MatchesPath(key) {
340-
delete(fileMap, key)
341-
continue
342-
}
343-
}
335+
absFilepath := filepath.Join(d.config.WatchPath, key)
344336

337+
if shouldRemoveLocal(absFilepath, value, d.config) {
345338
if numRemoveFiles <= 3 {
346339
d.config.Logf("[Downstream] Remove %s", key)
347340
}
348341

349-
if fileMap[key].IsDirectory {
342+
if value.IsDirectory {
350343
deleteSafeRecursive(d.config.WatchPath, key, fileMap, removeFiles, d.config)
351344
} else {
352-
if value.Mtime == fileMap[key].Mtime && value.Size == fileMap[key].Size {
353-
if deleteSafe(path.Join(d.config.WatchPath, key), fileMap[key]) == false {
354-
d.config.Logf("[Downstream] Skip file delete %s", key)
355-
}
345+
err := os.Remove(absFilepath)
346+
if err != nil {
347+
d.config.Logf("[Downstream] Skip file delete %s: %v", key, err)
348+
continue
356349
}
357-
358-
delete(fileMap, key)
359350
}
351+
} else {
352+
d.config.Logf("[Downstream] Skip delete %s", key)
360353
}
354+
355+
delete(fileMap, key)
361356
}
362357
}
363358

@@ -481,7 +476,6 @@ func (d *downstream) evaluateFile(fileline string, createFiles *[]*fileInformati
481476
d.config.fileIndex.fileMapMutex.Lock()
482477
defer d.config.fileIndex.fileMapMutex.Unlock()
483478

484-
fileMap := d.config.fileIndex.fileMap
485479
fileInformation, err := parseFileInformation(fileline, d.config.DestPath)
486480

487481
// Error parsing line
@@ -494,59 +488,11 @@ func (d *downstream) evaluateFile(fileline string, createFiles *[]*fileInformati
494488
return nil
495489
}
496490

497-
// Exclude files on the exclude list
498-
if d.config.ignoreMatcher != nil {
499-
if d.config.ignoreMatcher.MatchesPath(fileInformation.Name) {
500-
return nil
501-
}
502-
}
491+
// File found don't delete it
492+
delete(removeFiles, fileInformation.Name)
503493

504-
// File found, don't delete it
505-
if removeFiles[fileInformation.Name] != nil {
506-
delete(removeFiles, fileInformation.Name)
507-
}
508-
509-
// Update mode, gid & uid if exists
510-
if fileMap[fileInformation.Name] != nil {
511-
fileMap[fileInformation.Name].RemoteMode = fileInformation.RemoteMode
512-
fileMap[fileInformation.Name].RemoteGID = fileInformation.RemoteGID
513-
fileMap[fileInformation.Name].RemoteUID = fileInformation.RemoteUID
514-
}
515-
516-
// Exclude files on the exclude list
517-
if d.config.downloadIgnoreMatcher != nil {
518-
if d.config.downloadIgnoreMatcher.MatchesPath(fileInformation.Name) {
519-
return nil
520-
}
521-
}
522-
523-
// Exclude symlinks
524-
if fileInformation.IsSymbolicLink {
525-
// Add them to the fileMap though
526-
fileMap[fileInformation.Name] = fileInformation
527-
return nil
528-
}
529-
530-
// Does file already exist in the filemap?
531-
if fileMap[fileInformation.Name] != nil {
532-
// Don't override folders that exist in the filemap
533-
if fileInformation.IsDirectory == false {
534-
// Redownload file if mtime is newer than saved one
535-
if fileInformation.Mtime > fileMap[fileInformation.Name].Mtime {
536-
*createFiles = append(*createFiles, fileInformation)
537-
538-
return nil
539-
}
540-
541-
// Redownload file if size changed && file is not older than the one in the fileMap
542-
// the mTime check is necessary, because otherwise we would override older local files that
543-
// are not overridden initially
544-
if fileInformation.Mtime == fileMap[fileInformation.Name].Mtime && fileInformation.Size != fileMap[fileInformation.Name].Size {
545-
*createFiles = append(*createFiles, fileInformation)
546-
}
547-
}
548-
} else {
549-
// We create the file if it doesn't exist in the fileMap
494+
// Should we download the file / folder?
495+
if shouldDownload(fileInformation, d.config) {
550496
*createFiles = append(*createFiles, fileInformation)
551497
}
552498

pkg/devspace/sync/evaluater.go

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
package sync
2+
3+
import (
4+
"os"
5+
)
6+
7+
// s.fileIndex needs to be locked before this function is called
8+
func shouldRemoveRemote(relativePath string, s *SyncConfig) bool {
9+
// Exclude changes on the exclude list
10+
if s.ignoreMatcher != nil {
11+
if s.ignoreMatcher.MatchesPath(relativePath) {
12+
return false
13+
}
14+
}
15+
16+
// Exclude changes on the upload exclude list
17+
if s.uploadIgnoreMatcher != nil {
18+
if s.uploadIgnoreMatcher.MatchesPath(relativePath) {
19+
return false
20+
}
21+
}
22+
23+
// File / Folder was already deleted from map so event was already processed or should not be processed
24+
if s.fileIndex.fileMap[relativePath] == nil {
25+
return false
26+
}
27+
28+
// Exclude symbolic links
29+
if s.fileIndex.fileMap[relativePath].IsSymbolicLink {
30+
return false
31+
}
32+
33+
return true
34+
}
35+
36+
// s.fileIndex needs to be locked before this function is called
37+
func shouldUpload(relativePath string, stat os.FileInfo, s *SyncConfig, isInitial bool) bool {
38+
// Exclude if stat is nil
39+
if stat == nil {
40+
return false
41+
}
42+
43+
// Exclude changes on the exclude list
44+
if s.ignoreMatcher != nil {
45+
if s.ignoreMatcher.MatchesPath(relativePath) {
46+
return false
47+
}
48+
}
49+
50+
// Exclude changes on the upload exclude list
51+
if s.uploadIgnoreMatcher != nil {
52+
if s.uploadIgnoreMatcher.MatchesPath(relativePath) {
53+
// Add to file map and prevent download if local file is newer than the remote one
54+
if s.fileIndex.fileMap[relativePath] != nil && s.fileIndex.fileMap[relativePath].Mtime < ceilMtime(stat.ModTime()) {
55+
fileInformation := &fileInformation{
56+
Name: relativePath,
57+
Mtime: ceilMtime(stat.ModTime()),
58+
Size: stat.Size(),
59+
IsDirectory: stat.IsDir(),
60+
}
61+
62+
// Add it to the fileMap
63+
s.fileIndex.fileMap[relativePath] = fileInformation
64+
}
65+
66+
return false
67+
}
68+
}
69+
70+
// Exclude local symlinks
71+
if stat.Mode()&os.ModeSymlink != 0 {
72+
return false
73+
}
74+
75+
// Check if we already tracked the path
76+
if s.fileIndex.fileMap[relativePath] != nil {
77+
// Folder already exists
78+
if stat.IsDir() {
79+
// We want to initially walk over all files therefore we return true for a directory
80+
// Later on a created directory locally that already exists in the fileMap should be ignored
81+
return isInitial
82+
}
83+
84+
// Exclude symlinks
85+
if s.fileIndex.fileMap[relativePath].IsSymbolicLink {
86+
return false
87+
}
88+
89+
if isInitial {
90+
// File is older locally than remote so don't update remote
91+
if ceilMtime(stat.ModTime()) <= s.fileIndex.fileMap[relativePath].Mtime+1 {
92+
return false
93+
}
94+
} else {
95+
// File did not change or was changed by downstream
96+
if ceilMtime(stat.ModTime()) == s.fileIndex.fileMap[relativePath].Mtime && stat.Size() == s.fileIndex.fileMap[relativePath].Size {
97+
return false
98+
}
99+
}
100+
}
101+
102+
return true
103+
}
104+
105+
// s.fileIndex needs to be locked before this function is called
106+
func shouldDownload(fileInformation *fileInformation, s *SyncConfig) bool {
107+
// Exclude files on the exclude list
108+
if s.ignoreMatcher != nil {
109+
if s.ignoreMatcher.MatchesPath(fileInformation.Name) {
110+
return false
111+
}
112+
}
113+
114+
// Update mode, gid & uid if exists
115+
if s.fileIndex.fileMap[fileInformation.Name] != nil {
116+
s.fileIndex.fileMap[fileInformation.Name].RemoteMode = fileInformation.RemoteMode
117+
s.fileIndex.fileMap[fileInformation.Name].RemoteGID = fileInformation.RemoteGID
118+
s.fileIndex.fileMap[fileInformation.Name].RemoteUID = fileInformation.RemoteUID
119+
}
120+
121+
// Exclude files on the exclude list
122+
if s.downloadIgnoreMatcher != nil {
123+
if s.downloadIgnoreMatcher.MatchesPath(fileInformation.Name) {
124+
return false
125+
}
126+
}
127+
128+
// Exclude symlinks
129+
if fileInformation.IsSymbolicLink {
130+
// Add them to the fileMap though
131+
s.fileIndex.fileMap[fileInformation.Name] = fileInformation
132+
return false
133+
}
134+
135+
// Does file already exist in the filemap?
136+
if s.fileIndex.fileMap[fileInformation.Name] != nil {
137+
// Don't override folders that exist in the filemap
138+
if fileInformation.IsDirectory == false {
139+
// Redownload file if mtime is newer than saved one
140+
if fileInformation.Mtime > s.fileIndex.fileMap[fileInformation.Name].Mtime {
141+
return true
142+
}
143+
144+
// Redownload file if size changed && file is not older than the one in the fileMap
145+
// the mTime check is necessary, because otherwise we would override older local files that
146+
// are not overridden initially
147+
if fileInformation.Mtime == s.fileIndex.fileMap[fileInformation.Name].Mtime && fileInformation.Size != s.fileIndex.fileMap[fileInformation.Name].Size {
148+
return true
149+
}
150+
}
151+
152+
return false
153+
}
154+
155+
return true
156+
}
157+
158+
// s.fileIndex needs to be locked before this function is called
159+
// A file is only deleted if the following conditions are met:
160+
// - The file name is present in the d.config.fileMap map
161+
// - The file did not change in terms of size and mtime in the d.config.fileMap since we started the collecting changes process
162+
// - The file is present on the filesystem and did not change in terms of size and mtime on the filesystem
163+
func shouldRemoveLocal(absFilepath string, fileInformation *fileInformation, s *SyncConfig) bool {
164+
if fileInformation == nil {
165+
return false
166+
}
167+
168+
// Exclude files on the exclude list
169+
if s.downloadIgnoreMatcher != nil {
170+
if s.downloadIgnoreMatcher.MatchesPath(fileInformation.Name) {
171+
return false
172+
}
173+
}
174+
175+
// Only delete if mtime and size did not change
176+
stat, err := os.Stat(absFilepath)
177+
if err != nil {
178+
return false
179+
}
180+
181+
// We don't delete the file if we haven't tracked it
182+
if stat != nil && s.fileIndex.fileMap[fileInformation.Name] != nil {
183+
if stat.IsDir() != s.fileIndex.fileMap[fileInformation.Name].IsDirectory || stat.IsDir() != fileInformation.IsDirectory {
184+
return false
185+
}
186+
187+
if fileInformation.IsDirectory == false {
188+
// We don't delete the file if it has changed in the map since we collected changes
189+
if fileInformation.Mtime == s.fileIndex.fileMap[fileInformation.Name].Mtime && fileInformation.Size == s.fileIndex.fileMap[fileInformation.Name].Size {
190+
// We don't delete the file if it has changed on the filesystem meanwhile
191+
if ceilMtime(stat.ModTime()) <= fileInformation.Mtime {
192+
return true
193+
}
194+
}
195+
} else {
196+
return true
197+
}
198+
}
199+
200+
return false
201+
}

0 commit comments

Comments
 (0)