Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion cmd/miqt-docker/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ interactive terminal; or one of the following special tasks:
Environment variables:
DOCKER Override the path to docker
MIQTDOCKER_UID Run the docker command under a custom uid or uid:gid
MIQTDOCKER_FLAGS Add extra flags to the docker command
MIQTDOCKER_PERM Specify volume mount permissions (e.g. 'ro', 'rw', or 'Z')

Available container environments: (use - as wildcard character)
native (Run natively without docker)
Expand Down Expand Up @@ -252,8 +254,24 @@ func getDockerRunArgsForGlob(dockerfiles []fs.DirEntry, containerNameGlob string
mountDir = strings.ReplaceAll(mountDir, `\`, `/`)
}

// Extra user-supplied docker flags
// Prepopulate some things that the user may want to replace/override
if extraFlags := os.Getenv(`MIQTDOCKER_FLAGS`); extraFlags != "" {
fullCommand = append(fullCommand, StringFields(extraFlags)...)
} else {
// Default MIQTDOCKER_FLAGS:
// `--security-opt label=disable` - required for SELinux compatibility on Bazzite (#316)
fullCommand = append(fullCommand, `--security-opt`, `label=disable`)
}

// Volume mount permissions (e.g. 'rw', 'ro', 'Z')
volumeMountPermissions := ``
if setPerms := os.Getenv(`MIQTDOCKER_PERM`); setPerms != "" {
volumeMountPermissions = `:` + setPerms
}

fullCommand = append(fullCommand,
`-v`, basedir+`:`+mountDir,
`-v`, basedir+`:`+mountDir+volumeMountPermissions,
`-w`, path.Join(mountDir, relCwd),

// Final standard docker commands
Expand Down
58 changes: 58 additions & 0 deletions cmd/miqt-docker/stringfields.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package main

// StringFields tokenizes an input string into an array of separate fields. It
// supports quotes. It doesn't parse escape sequences.
func StringFields(input string) []string {

var ret []string = make([]string, 0)
var tmp string
flush := func() {
if len(tmp) > 0 {
ret = append(ret, tmp)
tmp = ""
}
}

type parseState int
const (
Normal parseState = iota
InsideDoubleQuotes
InsideSingleQuotes
)
var state parseState = Normal

for _, r := range input {
if state == Normal {
if r == '"' {
state = InsideDoubleQuotes
} else if r == '\'' {
state = InsideSingleQuotes
} else if r == ' ' || r == '\t' || r == '\n' || r == '\r' {
flush()
} else {
tmp += string(r)
}

} else if state == InsideDoubleQuotes {
if r == '"' {
state = Normal // Don't flush yet, might be switching quote types mid-field
} else {
tmp += string(r)
}

} else if state == InsideSingleQuotes {
if r == '\'' {
state = Normal
} else {
tmp += string(r)
}

} else {
panic("invalid state") // unreachable
}
}

flush() // any incomplete fields

return ret
}
51 changes: 51 additions & 0 deletions cmd/miqt-docker/stringfields_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package main

import (
"fmt"
"testing"
)

func TestStringFields(t *testing.T) {
type testCase struct {
input string
expect []string
}

cases := []testCase{
// blank string = no fields
{"", []string{}},

// Spaces are trimmed
{" ", []string{}},
{" ", []string{}},
{"hello", []string{"hello"}},
{" hello ", []string{"hello"}},

// Other types of whitespace
{" \t \r hello \n ", []string{"hello"}},

// Multiple tokens
{"hello world", []string{"hello", "world"}},

// Quotes
{`"hello" world`, []string{"hello", "world"}},
{`"hello" 'world'`, []string{"hello", "world"}},

// Switching quote types inside a single token
{`"he"'ll'o world`, []string{"hello", "world"}},

// Leftover unquoted text
{`"leftover`, []string{"leftover"}},

// Real world expected use case
{`--security-opt label:disable --user 1000:0`, []string{"--security-opt", "label:disable", "--user", "1000:0"}},
}

for _, tc := range cases {
got := StringFields(tc.input)

if fmt.Sprintf("%#v", got) != fmt.Sprintf("%#v", tc.expect) {
t.Errorf("StringFields(%q); got %#v, want %#v", tc.input, got, tc.expect)
}
}
}