Skip to content

Commit

Permalink
Factor out function looking for devcontainer files to devcontainer pa…
Browse files Browse the repository at this point in the history
…ckage (loft-sh#1219)
  • Loading branch information
janekbaraniewski authored Aug 14, 2024
1 parent c9501dd commit 69b6795
Show file tree
Hide file tree
Showing 2 changed files with 138 additions and 114 deletions.
117 changes: 3 additions & 114 deletions cmd/helper/get_workspace_config.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,14 @@
package helper

import (
"bufio"
"context"
"encoding/json"
"fmt"
"io/fs"
"os"
"path/filepath"
"strings"
"time"

"github.com/loft-sh/devpod/cmd/flags"
"github.com/loft-sh/devpod/pkg/file"
"github.com/loft-sh/devpod/pkg/git"
"github.com/loft-sh/devpod/pkg/image"
"github.com/loft-sh/devpod/pkg/devcontainer"
"github.com/loft-sh/log"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
Expand Down Expand Up @@ -74,15 +68,15 @@ func (cmd *GetWorkspaceConfigCommand) Run(ctx context.Context, args []string) er
ctx, cancel := context.WithTimeout(context.Background(), cmd.timeout)
defer cancel()

done := make(chan *GetWorkspaceConfigCommandResult, 1)
done := make(chan *devcontainer.GetWorkspaceConfigResult, 1)
errChan := make(chan error, 1)

tmpDir, err := os.MkdirTemp("", "devpod")
if err != nil {
return err
}
go func() {
result, err := findDevcontainerFiles(ctx, rawSource, tmpDir, cmd.maxDepth, logger)
result, err := devcontainer.FindDevcontainerFiles(ctx, rawSource, tmpDir, cmd.maxDepth, logger)
if err != nil {
errChan <- err
return
Expand All @@ -108,108 +102,3 @@ func (cmd *GetWorkspaceConfigCommand) Run(ctx context.Context, args []string) er

return nil
}

func findDevcontainerFiles(ctx context.Context, rawSource, tmpDirPath string, maxDepth int, log log.Logger) (*GetWorkspaceConfigCommandResult, error) {
result := &GetWorkspaceConfigCommandResult{ConfigPaths: []string{}}

// local path
isLocalPath, _ := file.IsLocalDir(rawSource)
if isLocalPath {
log.Debug("Local directory detected")
result.IsLocal = true
initialDepth := strings.Count(rawSource, string(filepath.Separator))
err := filepath.WalkDir(rawSource, func(path string, info fs.DirEntry, err error) error {
if err != nil {
return err
}
depth := strings.Count(path, string(filepath.Separator)) - initialDepth
if info.IsDir() && depth > maxDepth {
return filepath.SkipDir
}

if isDevcontainerFilename(path) {
relPath, err := filepath.Rel(rawSource, path)
if err != nil {
log.Warnf("Unable to get relative path for %s: %s", path, err.Error())
return nil
}
result.ConfigPaths = append(result.ConfigPaths, relPath)
}

return nil
})
if err != nil {
return nil, err
}

return result, nil
}

// git repo
gitRepository, gitPRReference, gitBranch, gitCommit, gitSubDir := git.NormalizeRepository(rawSource)
if strings.HasSuffix(rawSource, ".git") || git.PingRepository(gitRepository) {
log.Debug("Git repository detected")
result.IsGitRepository = true

gitInfo := git.NewGitInfo(gitRepository, gitBranch, gitCommit, gitPRReference, gitSubDir)
log.Debugf("Cloning git repository into %s", tmpDirPath)
err := git.CloneRepository(ctx, gitInfo, tmpDirPath, "", true, git.NewCloner(git.ShallowCloneStrategy), log.Writer(logrus.DebugLevel, false), log)
if err != nil {
return nil, err
}

log.Debug("Listing git file tree")
ref := "HEAD"
// checkout on branch if available
if gitBranch != "" {
ref = gitBranch
}
// git ls-tree -r --full-name --name-only $REF
lsArgs := []string{"ls-tree", "-r", "--full-name", "--name-only", ref}
lsCmd := git.CommandContext(ctx, lsArgs...)
lsCmd.Dir = tmpDirPath
stdout, err := lsCmd.StdoutPipe()
if err != nil {
return nil, err
}
err = lsCmd.Start()
if err != nil {
return nil, err
}

scanner := bufio.NewScanner(stdout)
for scanner.Scan() {
path := scanner.Text()
depth := strings.Count(path, string(filepath.Separator))
if depth > maxDepth {
continue
}
if isDevcontainerFilename(path) {
result.ConfigPaths = append(result.ConfigPaths, path)
}
}

err = lsCmd.Wait()
if err != nil {
return nil, err
}

return result, nil
}

// container image
_, err := image.GetImage(ctx, rawSource)
if err == nil {
log.Debug("Container image detected")
result.IsImage = true
// Doesn't matter, we just want to know if it's an image
// not going to poke around in the image fs
return result, nil
}

return result, nil
}

func isDevcontainerFilename(path string) bool {
return filepath.Base(path) == ".devcontainer.json" || filepath.Base(path) == "devcontainer.json"
}
135 changes: 135 additions & 0 deletions pkg/devcontainer/helpers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package devcontainer

import (
"bufio"
"context"
"io/fs"
"path/filepath"
"strings"

"github.com/loft-sh/devpod/pkg/file"
"github.com/loft-sh/devpod/pkg/git"
"github.com/loft-sh/devpod/pkg/image"
"github.com/loft-sh/log"
"github.com/sirupsen/logrus"
)

type GetWorkspaceConfigResult struct {
IsImage bool `json:"isImage"`
IsGitRepository bool `json:"isGitRepository"`
IsLocal bool `json:"isLocal"`
ConfigPaths []string `json:"configPaths"`
}

func FindDevcontainerFiles(ctx context.Context, rawSource, tmpDirPath string, maxDepth int, log log.Logger) (*GetWorkspaceConfigResult, error) {
result := &GetWorkspaceConfigResult{ConfigPaths: []string{}}

// local path
isLocalPath, _ := file.IsLocalDir(rawSource)
if isLocalPath {
return FindFilesInLocalDir(result, rawSource, maxDepth, log)
}

// git repo
gitRepository, gitPRReference, gitBranch, gitCommit, gitSubDir := git.NormalizeRepository(rawSource)
if strings.HasSuffix(rawSource, ".git") || git.PingRepository(gitRepository) {
log.Debug("Git repository detected")
return FindFilesInGitRepo(ctx, result, gitRepository, gitPRReference, gitBranch, gitCommit, gitSubDir, tmpDirPath, maxDepth, log)
}

// container image
_, err := image.GetImage(ctx, rawSource)
if err == nil {
log.Debug("Container image detected")
result.IsImage = true
// Doesn't matter, we just want to know if it's an image
// not going to poke around in the image fs
return result, nil
}

return result, nil
}

func FindFilesInLocalDir(result *GetWorkspaceConfigResult, rawSource string, maxDepth int, log log.Logger) (*GetWorkspaceConfigResult, error) {
log.Debug("Local directory detected")
result.IsLocal = true
initialDepth := strings.Count(rawSource, string(filepath.Separator))
err := filepath.WalkDir(rawSource, func(path string, info fs.DirEntry, err error) error {
if err != nil {
return err
}
depth := strings.Count(path, string(filepath.Separator)) - initialDepth
if info.IsDir() && depth > maxDepth {
return filepath.SkipDir
}

if isDevcontainerFilename(path) {
relPath, err := filepath.Rel(rawSource, path)
if err != nil {
log.Warnf("Unable to get relative path for %s: %s", path, err.Error())
return nil
}
result.ConfigPaths = append(result.ConfigPaths, relPath)
}

return nil
})
if err != nil {
return nil, err
}

return result, nil
}

func FindFilesInGitRepo(ctx context.Context, result *GetWorkspaceConfigResult, gitRepository, gitPRReference, gitBranch, gitCommit, gitSubDir, tmpDirPath string, maxDepth int, log log.Logger) (*GetWorkspaceConfigResult, error) {
result.IsGitRepository = true

gitInfo := git.NewGitInfo(gitRepository, gitBranch, gitCommit, gitPRReference, gitSubDir)
log.Debugf("Cloning git repository into %s", tmpDirPath)
err := git.CloneRepository(ctx, gitInfo, tmpDirPath, "", true, git.NewCloner(git.ShallowCloneStrategy), log.Writer(logrus.DebugLevel, false), log)
if err != nil {
return nil, err
}

log.Debug("Listing git file tree")
ref := "HEAD"
// checkout on branch if available
if gitBranch != "" {
ref = gitBranch
}
// git ls-tree -r --full-name --name-only $REF
lsArgs := []string{"ls-tree", "-r", "--full-name", "--name-only", ref}
lsCmd := git.CommandContext(ctx, lsArgs...)
lsCmd.Dir = tmpDirPath
stdout, err := lsCmd.StdoutPipe()
if err != nil {
return nil, err
}
err = lsCmd.Start()
if err != nil {
return nil, err
}

scanner := bufio.NewScanner(stdout)
for scanner.Scan() {
path := scanner.Text()
depth := strings.Count(path, string(filepath.Separator))
if depth > maxDepth {
continue
}
if isDevcontainerFilename(path) {
result.ConfigPaths = append(result.ConfigPaths, path)
}
}

err = lsCmd.Wait()
if err != nil {
return nil, err
}

return result, nil
}

func isDevcontainerFilename(path string) bool {
return filepath.Base(path) == ".devcontainer.json" || filepath.Base(path) == "devcontainer.json"
}

0 comments on commit 69b6795

Please sign in to comment.