Skip to content

Commit c28f215

Browse files
authored
Merge branch 'master' into improve-config
2 parents 4816c18 + 9d94484 commit c28f215

12 files changed

Lines changed: 813 additions & 263 deletions

File tree

docs/docs/advanced/architecture.md

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,6 @@ The DevSpace CLI will deploy the Helm chart specified under [chart/](/docs/confi
2222

2323
**Note:** If you do not have a [Helm chart](/docs/configuration/chart.html) yet, the DevSpace CLI will automatically create one for you.
2424

25-
## 2-Way Code Sync
26-
The DevSpace CLI will establish a bi-directional code synchronization between your local source code directory and the main dev pod inside your DevSpace. The synchonization has the following characteristics:
27-
28-
- No server-side component is required to use the sync mechanism.
29-
- The sync algorithm keeps track of all (remote and local) files within an in-built, local database.
30-
- The code sync works with any container filesystem (i.e. ephemeral storage and mounted volumes).
31-
- The code sync is lightning fast and very reliable. It detects remote changes as well as local changes quickly and synchronizes them respectively.
32-
- The sync algorithm only requires the following stardard POSIX commands to be available inside your development container: sleep, mkdir, rm, mv, cat, ls, printf, echo, kill, tar, sh
33-
34-
**Note:** You can configure the sync path mappings via [.devspace/config.yaml](/docs/configuration/config.yaml.html).
35-
3625
## Terminal Proxy
3726
The terminal proxy opens a terminal within your dev container and connects your local command-line to it. This way, you can directly run commands inside your DevSpace and stream the response directly to your local computer.
3827

docs/docs/advanced/sync.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
---
2+
title: Source Code Synchronization
3+
---
4+
5+
# Code Synchronization
6+
The DevSpace CLI synchronization mechanism is written from scratch and made for kubernetes development with hot reloading. While current other kubernetes development solutions (like draft, skaffold and telepresence) help the developer with the problem how to test and deploy cloud-native applications in kubernetes clusters, actual iterative development, testing and hot reloading of cloud-native applications within kubernetes is still an annoying problem. Especially for developers of programming languages that support hot reload development environments, such as nodejs, this is a hassle. The DevSpace CLI has a syncing mechanism that is able to sync local file changes to remote containers directly without the need of restarting the container, a deployment pipeline or a docker build. This greatly accelerates development, debugging and testing directly in remote containers.
7+
8+
Our main requirements to the sync mechanism were:
9+
- Easy to integrate, no cluster dependencies, client-only implementation
10+
- Should work in every kubernetes cluster
11+
- Should work with most containers, without installing additional binaries or changing the Dockerfile
12+
- Should work with every container filesystem (i.e. ephemeral storage and mounted volumes)
13+
- File watchers and hot reload tools like nodemon should recognize sync changes like on local filesystem
14+
- Fast and reliable
15+
16+
If synchronization is configured (check with `devspace list sync`), the DevSpace CLI will establish a bi-directional code synchronization between the specified local folders and the remote container folders. It automatically recognizes any changes within the specified folders during the session and will update the corresponding files locally and remotely in the background. You can check the latest sync activity by running the command `devspace status sync` or take a look at the `sync.log` in `.devspace/logs`.
17+
18+
## Sync Requirements
19+
No server-side component for code synchronization is required, the sync is client-only. The synchronization mechanism works with any container filesystem and no special binaries have to be installed into the containers. File watchers running within the containers like nodemon will also recognize changes made by the synchronization mechanism.
20+
21+
Some basic POSIX binaries have to be present in the container (which usually exist in most containers): `sh, tar, cd, sleep, find, stat, mkdir, rm, cat, printf, echo, kill`
22+
23+
## Excluding Files and Folders
24+
You are able to fully or partly exclude certain files and folders from synchronization. Take a look at [.devspace/config.yaml](/docs/configuration/config.yaml.html) for more information where to specify the ignore rules in the configuration. The exclude path syntax is the [.gitignore](https://git-scm.com/docs/gitignore) syntax.
25+
26+
There are 3 different options for each sync path to exclude files and folders:
27+
1. excludePaths: Matched paths are completely ignored during synchronization
28+
2. downloadExcludePaths: Local changes are uploaded, but remote changes are not downloaded
29+
3. uploadExcludePaths: Local changes are not uploaded, but remote changes are downloaded
30+
31+
## Initial Sync
32+
If synchronization is started, the sync initially compares the remote folder and the local folder and merges the contents with the following rules:
33+
- If a file or folder exists remote, but not locally, then download file / folder
34+
- If a file or folder exists locally, but not remote, then upload file / folder
35+
- If a file is newer locally than remote then upload the file (The opposite case is not true, older local files are not overriden by newer remote files)
36+
37+
## Performance Notes
38+
The sync mechanism is normally very reliable and fast. Syncing several thousand files is usually not a problem. Changes are packed together and compressed before synchronization, which improves performance especially for transferring text files. Transferring large compressed binary files is possible, however can affect performance negatively. Rename operations are currently recognized as a separate remove and create operation, which in normal workflows has at most a minor performance impact, however renaming huge folders with tens of thousands of files can impact performance negatively and should be avoided. Remote changes can sometimes have a delay of 1-2 seconds till they are downloaded, depending on how big the synchronized folder is. It should be generally avoided to sync the complete container filesystem.

docs/docs/getting-started/installation.md

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,18 @@ del "%Temp%\install-devspace.bat"
1919
**Note:** After running the install script, you should reopen the terminal window to refresh the environment variables.
2020

2121
### For Linux
22-
1. Run this install script with **root privileges**:
22+
1. Run the command:
2323
```bash
24-
tmpdir=$(dirname $(mktemp -u))
25-
curl -s "https://raw.githubusercontent.com/covexo/devspace/master/scripts/installer-linux.sh" >"$tmpdir/install-devspace.sh"
26-
"$tmpdir/install-devspace.sh" "/usr/bin/devspace"
27-
rm -r "$tmpdir"
24+
curl --silent "https://api.github.com/repos/covexo/devspace/releases/latest" | sed -nr 's!.*"(https://github.com[^"]*devspace-linux-amd64)".*!\1!p' | xargs -n 1 curl -L -o devspace && chmod +x devspace && sudo mv devspace /usr/local/bin
25+
```
26+
27+
### For Mac
28+
1. Run the command:
29+
```bash
30+
curl --silent "https://api.github.com/repos/covexo/devspace/releases/latest" | sed -nr 's!.*"(https://github.com[^"]*devspace-darwin-amd64)".*!\1!p' | xargs -n 1 curl -L -o devspace && chmod +x devspace && sudo mv devspace /usr/local/bin
2831
```
2932

3033
## Binary Download
3134
An alternative to the install scripts is to:
3235
1. download the latest release from the [GitHub releases page](https://github.com/covexo/devspace/releases)
33-
2. add the binary folder path to the PATH environment variable **OR** run `PATH_TO_YOUR_RELEASE_FILE install` with admin/root priveleges
36+
2. add the binary folder path to your PATH environment variable **OR** run `PATH_TO_YOUR_RELEASE_FILE install` with admin/root priveleges

pkg/devspace/builder/docker/auth.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,16 +42,16 @@ func getDefaultAuthConfig(client client.CommonAPIClient, checkCredStore bool, se
4242
var authconfig types.AuthConfig
4343
var err error
4444

45-
configfile, _ := loadDockerConfig()
46-
4745
if !isDefaultRegistry {
4846
serverAddress = registry.ConvertToHostname(serverAddress)
4947
}
5048

5149
if checkCredStore {
52-
authconfig, err = configfile.GetAuthConfig(serverAddress)
53-
} else {
54-
authconfig = types.AuthConfig{}
50+
configfile, err := loadDockerConfig()
51+
52+
if configfile != nil && err == nil {
53+
authconfig, err = configfile.GetAuthConfig(serverAddress)
54+
}
5555
}
5656

5757
authconfig.ServerAddress = serverAddress

pkg/devspace/sync/downstream.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ func (d *downstream) downloadFiles(files []*fileInformation) (string, error) {
216216

217217
// Each file is represented in one line
218218
for _, element := range files {
219-
if lenFiles <= 3 {
219+
if lenFiles <= 3 || d.config.verbose {
220220
d.config.Logf("[Downstream] Download file %s, size: %d", element.Name, element.Size)
221221
}
222222

@@ -335,7 +335,7 @@ func (d *downstream) removeFilesAndFolders(removeFiles map[string]*fileInformati
335335
absFilepath := filepath.Join(d.config.WatchPath, key)
336336

337337
if shouldRemoveLocal(absFilepath, value, d.config) {
338-
if numRemoveFiles <= 3 {
338+
if numRemoveFiles <= 3 || d.config.verbose {
339339
d.config.Logf("[Downstream] Remove %s", key)
340340
}
341341

@@ -369,7 +369,7 @@ func (d *downstream) createFolders(createFolders []*fileInformation) {
369369

370370
for _, element := range createFolders {
371371
if element.IsDirectory {
372-
if numCreateFolders <= 3 {
372+
if numCreateFolders <= 3 || d.config.verbose {
373373
d.config.Logln("[Downstream] Create folder: " + element.Name)
374374
}
375375

pkg/devspace/sync/evaluater.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ func shouldUpload(relativePath string, stat os.FileInfo, s *SyncConfig, isInitia
4949

5050
// Exclude changes on the upload exclude list
5151
// if s.uploadIgnoreMatcher != nil {
52-
// if s.uploadIgnoreMatcher.MatchesPath(relativePath) {
52+
// if s.uploadIgnoreMatcher.MatchesPath(relativePath) {
5353
// return false
5454
// }
5555
// }

pkg/devspace/sync/file_information.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ func (p parsingError) Error() string {
5656
}
5757

5858
func getFindCommand(destPath string) string {
59-
return "mkdir -p '" + destPath + "' && find '" + destPath + "' -exec stat -c \"%n///%s,%Y,%f,%a,%u,%g\" {} + 2>/dev/null && echo -n \"" + EndAck + "\" || echo \"" + ErrorAck + "\"\n"
59+
return "mkdir -p '" + destPath + "' && find -L '" + destPath + "' -exec stat -c \"%n///%s,%Y,%f,%a,%u,%g\" {} + 2>/dev/null && echo -n \"" + EndAck + "\" || echo \"" + ErrorAck + "\"\n"
6060
}
6161

6262
func parseFileInformation(fileline, destPath string) (*fileInformation, error) {

pkg/devspace/sync/sync_config.go

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,16 @@ type SyncConfig struct {
5050
upstream *upstream
5151
downstream *downstream
5252

53-
silent bool
53+
silent bool
54+
verbose bool
55+
5456
stopOnce sync.Once
5557
stopped bool
5658

5759
// Used for testing
5860
testing bool
5961
errorChan chan error
62+
readyChan chan bool
6063
}
6164

6265
// Logf prints the given information to the synclog with context data
@@ -76,7 +79,11 @@ func (s *SyncConfig) Logln(line interface{}) {
7679
if s.Pod != nil {
7780
syncLog.WithKey("pod", s.Pod.Name).WithKey("local", s.WatchPath).WithKey("container", s.DestPath).Info(line)
7881
} else {
79-
syncLog.WithKey("local", s.WatchPath).WithKey("container", s.DestPath).Info(line)
82+
syncLog.
83+
WithKey("local",
84+
s.WatchPath).
85+
WithKey("container", s.DestPath).
86+
Info(line)
8087
}
8188
}
8289
}
@@ -224,6 +231,10 @@ func (s *SyncConfig) startUpstream() {
224231

225232
defer notify.Stop(s.upstream.events)
226233

234+
if s.readyChan != nil {
235+
s.readyChan <- true
236+
}
237+
227238
err = s.upstream.mainLoop()
228239
if err != nil {
229240
s.Error(err)
@@ -293,10 +304,10 @@ func (s *SyncConfig) diffServerClient(filepath string, sendChanges *[]*fileInfor
293304

294305
delete(downloadChanges, relativePath)
295306

296-
s.fileIndex.fileMapMutex.Lock()
297307
// Exclude changes on the upload exclude list
298308
if s.uploadIgnoreMatcher != nil {
299309
if s.uploadIgnoreMatcher.MatchesPath(relativePath) {
310+
s.fileIndex.fileMapMutex.Lock()
300311
// Add to file map and prevent download if local file is newer than the remote one
301312
if s.fileIndex.fileMap[relativePath] != nil && s.fileIndex.fileMap[relativePath].Mtime < ceilMtime(stat.ModTime()) {
302313
// Add it to the fileMap
@@ -307,11 +318,13 @@ func (s *SyncConfig) diffServerClient(filepath string, sendChanges *[]*fileInfor
307318
IsDirectory: stat.IsDir(),
308319
}
309320
}
321+
s.fileIndex.fileMapMutex.Unlock()
310322

311323
return nil
312324
}
313325
}
314326

327+
s.fileIndex.fileMapMutex.Lock()
315328
shouldUpload := shouldUpload(relativePath, stat, s, true)
316329
s.fileIndex.fileMapMutex.Unlock()
317330

@@ -343,7 +356,7 @@ func (s *SyncConfig) diffDir(filepath string, stat os.FileInfo, sendChanges *[]*
343356
return nil
344357
}
345358

346-
if len(files) == 0 {
359+
if len(files) == 0 && relativePath != "" {
347360
*sendChanges = append(*sendChanges, &fileInformation{
348361
Name: relativePath,
349362
Mtime: ceilMtime(stat.ModTime()),

0 commit comments

Comments
 (0)