Skip to content

Commit

Permalink
Add DevContainers functionality to Finch
Browse files Browse the repository at this point in the history
Signed-off-by: Sam Chew <[email protected]>
  • Loading branch information
chews93319 committed Sep 27, 2024
1 parent d02333e commit 9672022
Show file tree
Hide file tree
Showing 10 changed files with 255 additions and 162 deletions.
45 changes: 45 additions & 0 deletions cmd/finch/nerdctl.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ type nerdctlCommandCreator struct {
fc *config.Finch
}

type (
argHandler func(systemDeps NerdctlCommandSystemDeps, args []string, index int) error
commandHandler func(systemDeps NerdctlCommandSystemDeps, args []string) error
)

func newNerdctlCommandCreator(
ncc command.NerdctlCmdCreator,
ecc command.Creator,
Expand Down Expand Up @@ -196,6 +201,20 @@ var dockerCompatCmds = map[string]string{
"buildx": "build version",
}

var aliasMap = map[string]string{
"build": "image build",
"run": "container run",
"cp": "container cp",
}

var commandHandlerMap = map[string]commandHandler{}

var argHandlerMap = map[string]map[string]argHandler{
"image build": {
"--load": handleDockerBuildLoad,
},
}

var cmdFlagSetMap = map[string]map[string]sets.Set[string]{
"container run": {
"shortBoolFlags": sets.New[string]("-d", "-i", "-t"),
Expand All @@ -219,3 +238,29 @@ var cmdFlagSetMap = map[string]map[string]sets.Set[string]{
"shortArgFlags": sets.New[string]("-e", "-h", "-m", "-u", "-w", "-p", "-l", "-v"),
},
}

// converts "docker build --load" flag to "nerdctl build --output=type=docker"

Check failure on line 242 in cmd/finch/nerdctl.go

View workflow job for this annotation

GitHub Actions / lint

Comment should end in a period (godot)
func handleDockerBuildLoad(systemDeps NerdctlCommandSystemDeps, nerdctlCmdArgs []string, index int) error {

Check failure on line 243 in cmd/finch/nerdctl.go

View workflow job for this annotation

GitHub Actions / lint

unused-parameter: parameter 'systemDeps' seems to be unused, consider removing or renaming it as _ (revive)
nerdctlCmdArgs[index] = "--output=type=docker"

return nil
}

func handleBuildx(cmdName *string, args []string, logger flog.Logger) ([]string, error) {
if cmdName != nil && *cmdName == "buildx" {
subCmd := args[0]
buildxSubcommands := []string{"bake", "create", "debug", "du", "imagetools", "inspect", "ls", "prune", "rm", "stop", "use", "version"}

if slices.Contains(buildxSubcommands, subCmd) {
return args, fmt.Errorf("Unsupported buildx command: %s", subCmd)

Check failure on line 255 in cmd/finch/nerdctl.go

View workflow job for this annotation

GitHub Actions / lint

ST1005: error strings should not be capitalized (stylecheck)
}

logger.Warnln("buildx is not supported. Attempting to utilize standard buildkit instead...")
if subCmd == "build" {
args = args[1:]
}
*cmdName = "build"
}
// else, continue with the original command
return args, nil
}
79 changes: 74 additions & 5 deletions cmd/finch/nerdctl_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@ func convertToWSLPath(_ NerdctlCommandSystemDeps, _ string) (string, error) {
return "", nil
}

var aliasMap = map[string]string{
"run": "container run",
}
var osAliasMap = map[string]string{}

var argHandlerMap = map[string]map[string]argHandler{}
var osArgHandlerMap = map[string]map[string]argHandler{
"container run": {
"--mount": handleBindMounts,
},
}

var commandHandlerMap = map[string]commandHandler{}
var osCommandHandlerMap = map[string]commandHandler{}

func (nc *nerdctlCommand) GetCmdArgs() []string {
return []string{"shell", limaInstanceName, "sudo", "-E"}
Expand All @@ -46,3 +48,70 @@ func resolveIP(host string, logger flog.Logger, _ command.Creator) (string, erro
}
return host, nil
}

// removes the consistency key-value entity from --mount
func handleBindMounts(systemDeps NerdctlCommandSystemDeps, nerdctlCmdArgs []string, index int) error {
prefix := nerdctlCmdArgs[index]
var (
v string
found bool
before string
)
if strings.Contains(nerdctlCmdArgs[index], "=") {
before, v, found = strings.Cut(prefix, "=")
} else {
if (index + 1) < len(nerdctlCmdArgs) {
v = nerdctlCmdArgs[index+1]
} else {
return fmt.Errorf("invalid positional parameter for %s", prefix)
}
}

// This is where the 'consistency=cached' strings should be removed....
// "consistency will be one of the keys in the following map"

// eg --mount type=bind,source="$(pwd)"/target,target=/app,readonly
// eg --mount type=bind,source=/Users/stchew/projs/arbtest_devcontainers_extensions,target=/workspaces/arbtest_devcontainers_extensions,consistency=cached
// https://docs.docker.com/storage/bind-mounts/#choose-the--v-or---mount-flag order does not matter, so convert to a map
entries := strings.Split(v, ",")
m := make(map[string]string)
ro := []string{}
for _, e := range entries {
parts := strings.Split(e, "=")
if len(parts) < 2 {
ro = append(ro, parts...)
} else {
m[strings.TrimSpace(parts[0])] = strings.TrimSpace(parts[1])
}
}
// Check if type is bind mount, else return
if m["type"] != "bind" {
return nil
}

// Remove 'consistency' key-value pair
delete(m, "consistency")

// Convert to string representation
s := mapToString(m)
// append read-only key if present
if len(ro) > 0 {
s = s + "," + strings.Join(ro, ",")
}
if found {
nerdctlCmdArgs[index] = fmt.Sprintf("%s=%s", before, s)
} else {
nerdctlCmdArgs[index+1] = s
}

return nil
}

func mapToString(m map[string]string) string {
var parts []string
for k, v := range m {
part := fmt.Sprintf("%s=%s", k, v)
parts = append(parts, part)
}
return strings.Join(parts, ",")
}
2 changes: 1 addition & 1 deletion cmd/finch/nerdctl_darwin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1271,7 +1271,7 @@ func TestNerdctlCommand_run_miscCommand(t *testing.T) {
ncsd.EXPECT().LookupEnv("COSIGN_PASSWORD").Return("", false)
ncsd.EXPECT().LookupEnv("COMPOSE_FILE").Return("", false)
c := mocks.NewCommand(ctrl)
lcc.EXPECT().Create("shell", limaInstanceName, "sudo", "-E", nerdctlCmdName, "build", "-t", "demo", ".").Return(c)
lcc.EXPECT().Create("shell", limaInstanceName, "sudo", "-E", nerdctlCmdName, "image", "build", "-t", "demo", ".").Return(c)
c.EXPECT().Run()
},
},
Expand Down
30 changes: 30 additions & 0 deletions cmd/finch/nerdctl_native.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
package main

import (
"maps"

"golang.org/x/exp/slices"

"github.com/runfinch/finch/pkg/command"
Expand All @@ -20,6 +22,28 @@ func (nc *nerdctlCommand) run(cmdName string, args []string) error {
nc.logger.SetLevel(flog.Debug)
}

// accumulate distributed map entities
maps.Copy(aliasMap, osAliasMap)
maps.Copy(commandHandlerMap, osCommandHandlerMap)
for k := range osArgHandlerMap {
_, ok := argHandlerMap[k]
if ok {
maps.Copy(argHandlerMap[k], osArgHandlerMap[k])
} else {
argHandlerMap[k] = make(map[string]argHandler)
maps.Copy(argHandlerMap[k], osArgHandlerMap[k])
}
}

// special handling if cmdName == "buildx"; before the alias reassignment
var err error
if cmdName == "buildx" {
args, err = handleBuildx(&cmdName, args, nc.logger)
if err != nil {
return err
}
}

cmdArgs := append([]string{cmdName}, args...)
if nc.shouldReplaceForHelp(cmdName, args) {
return nc.ncc.RunWithReplacingStdout(
Expand All @@ -30,3 +54,9 @@ func (nc *nerdctlCommand) run(cmdName string, args []string) error {

return nc.ncc.Create(cmdArgs...).Run()
}

var osAliasMap = map[string]string{}

var osArgHandlerMap = map[string]map[string]argHandler{}

var osCommandHandlerMap = map[string]commandHandler{}
Loading

0 comments on commit 9672022

Please sign in to comment.