diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3bdd12f..f62b299 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -96,8 +96,8 @@ jobs: args: -app-id calc.sha${{ github.sha }} - os: darwin args: -app-id calc.sha${{ github.sha }} - # Only macos-13 is supported as macos-14 is running in a VM on Mac M1 which are incompatible with docker/podman - host: macos-13 + # macos versions running in a VM on Mac M1 are incompatible with docker/podman + host: macos-15-intel - os: web ## Currently not easily supported from GitHub actions. @@ -143,7 +143,7 @@ jobs: - name: Install Docker if: ${{ runner.os == 'macos' }} - uses: douglascamata/setup-docker-macos-action@v1-alpha + uses: douglascamata/setup-docker-macos-action@v1.1.0 - name: Build working-directory: calculator @@ -173,8 +173,8 @@ jobs: args: -app-id calc.sha${{ github.sha }} - os: darwin args: -app-id calc.sha${{ github.sha }} - # Only macos-13 is supported as macos-14 is running in a VM on Mac M1 which are incompatible with docker/podman - host: macos-13 + # macos versions running in a VM on Mac M1 are incompatible with docker/podman + host: macos-15-intel ## Currently not easily supported from GitHub actions. ## https://github.com/fyne-io/fyne-cross/pull/104#issuecomment-1099494308 @@ -219,7 +219,7 @@ jobs: - name: Install Docker if: ${{ runner.os == 'macos' }} - uses: douglascamata/setup-docker-macos-action@v1-alpha + uses: douglascamata/setup-docker-macos-action@v1.1.0 - name: Build working-directory: terminal diff --git a/go.mod b/go.mod index c5e6ca7..7b064e2 100644 --- a/go.mod +++ b/go.mod @@ -10,6 +10,7 @@ require ( github.com/mholt/archiver/v3 v3.5.1 github.com/stretchr/testify v1.10.0 github.com/urfave/cli/v2 v2.27.7 + golang.org/x/mod v0.15.0 golang.org/x/sync v0.6.0 golang.org/x/sys v0.18.0 k8s.io/api v0.28.15 diff --git a/go.sum b/go.sum index a98d5d6..5560bb6 100644 --- a/go.sum +++ b/go.sum @@ -127,6 +127,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8= +golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= diff --git a/internal/cloud/kubernetes.go b/internal/cloud/kubernetes.go index d45a957..14184aa 100644 --- a/internal/cloud/kubernetes.go +++ b/internal/cloud/kubernetes.go @@ -1,6 +1,7 @@ package cloud import ( + "bytes" "context" "fmt" "os" @@ -182,7 +183,7 @@ func (k8s *K8sClient) NewPod(ctx context.Context, name string, image string, nam }, nil } -func (p *Pod) Run(ctx context.Context, workDir string, cmdArgs []string) error { +func (p *Pod) exec(ctx context.Context, workDir string, cmdArgs []string) (remotecommand.Executor, error) { api := p.client.kubectl.CoreV1() if workDir != "" && workDir != p.workDir { @@ -212,19 +213,40 @@ func (p *Pod) Run(ctx context.Context, workDir string, cmdArgs []string) error { option, scheme.ParameterCodec, ) - exec, err := remotecommand.NewSPDYExecutor(p.client.config, "POST", req.URL()) + + return remotecommand.NewSPDYExecutor(p.client.config, "POST", req.URL()) +} + +func (p *Pod) Run(ctx context.Context, workDir string, cmdArgs []string) error { + exec, err := p.exec(ctx, workDir, cmdArgs) if err != nil { return err } logWrapper("Executing command %v", cmdArgs) - err = exec.StreamWithContext(ctx, remotecommand.StreamOptions{ + return exec.StreamWithContext(ctx, remotecommand.StreamOptions{ Stdin: os.Stdin, Stdout: os.Stderr, Stderr: os.Stderr, Tty: false, }) - return err +} + +func (p *Pod) Command(ctx context.Context, workDir string, cmdArgs []string) (string, error) { + exec, err := p.exec(ctx, workDir, cmdArgs) + if err != nil { + return "", err + } + + logWrapper("Executing command %v", cmdArgs) + buf := &bytes.Buffer{} + err = exec.StreamWithContext(ctx, remotecommand.StreamOptions{ + Stdin: os.Stdin, + Stdout: buf, + Stderr: os.Stderr, + Tty: false, + }) + return buf.String(), err } func (p *Pod) Close() error { diff --git a/internal/command/command.go b/internal/command/command.go index 77ec75b..23c1817 100644 --- a/internal/command/command.go +++ b/internal/command/command.go @@ -10,6 +10,7 @@ import ( "github.com/fyne-io/fyne-cross/internal/icon" "github.com/fyne-io/fyne-cross/internal/log" "github.com/fyne-io/fyne-cross/internal/volume" + "golang.org/x/mod/semver" "golang.org/x/sys/execabs" ) @@ -159,32 +160,46 @@ func checkFyneBinHost(ctx Context) (string, error) { return "", fmt.Errorf("missed requirement: fyne. To install: `go install fyne.io/fyne/v2/cmd/fyne@latest` and add $GOPATH/bin to $PATH") } - if debugging() { - out, err := execabs.Command(fyne, "version").Output() - if err != nil { - return fyne, fmt.Errorf("could not get fyne cli %s version: %v", fyne, err) + return fyne, nil +} + +func fyneCommandVersion(fyne string, ctx Context, image containerImage) string { + out, _ := image.Command(ctx.Volume, options{}, []string{fyne, "version"}) + for _, line := range strings.Split(string(out), "\n") { + _, ver, found := strings.Cut(line, "fyne cli version: ") + if found { + return strings.TrimSuffix(ver, "\r") } - log.Debugf("%s", out) } + return "" +} - return fyne, nil +func fyneCommandVersionCompare(fyne, ver string, ctx Context, image containerImage) int { + return semver.Compare(fyneCommandVersion(fyne, ctx, image), ver) } func fyneCommand(binary, command, icon string, ctx Context, image containerImage) []string { target := image.Target() + appBuildOpt := "-app-build" + appVersionOpt := "-app-version" + if fyneCommandVersionCompare(binary, "v2.0.0", ctx, image) >= 0 { + appBuildOpt = "-appBuild" + appVersionOpt = "-appVersion" + } + args := []string{ binary, command, "-os", target, "-name", ctx.Name, "-icon", icon, - "-appBuild", ctx.AppBuild, - "-appVersion", ctx.AppVersion, + appBuildOpt, ctx.AppBuild, + appVersionOpt, ctx.AppVersion, } // add appID to command, if any if ctx.AppID != "" { - args = append(args, "-appID", ctx.AppID) + args = append(args, "-id", ctx.AppID) } // add tags to command, if any diff --git a/internal/command/container.go b/internal/command/container.go index 6d300cf..7939a20 100644 --- a/internal/command/container.go +++ b/internal/command/container.go @@ -29,6 +29,7 @@ type baseEngine struct { type containerImage interface { Run(vol volume.Volume, opts options, cmdArgs []string) error + Command(vol volume.Volume, opts options, cmdArgs []string) (string, error) Prepare() error Finalize(packageName string) error @@ -224,6 +225,18 @@ func fynePackage(ctx Context, image containerImage) error { return nil } +// concatNonEmptyNamedArgs returns name and value pairs, filtering out pairs with empty value +func concatNonEmptyNamedArgs(args ...string) []string { + r := []string{} + for n := 0; n < len(args)/2; n++ { + if args[n*2+1] == "" { + continue + } + r = append(r, args[n*2], args[n*2+1]) + } + return r +} + // fyneRelease package and release the application using the fyne cli tool // Note: at the moment this is used only for the android builds func fyneRelease(ctx Context, image containerImage) error { @@ -232,24 +245,30 @@ func fyneRelease(ctx Context, image containerImage) error { return err } + keyStoreOpt := "-key-store" + keyStorePassOpt := "-key-store-pass" + keyPassOpt := "-key-pass" + keyNameOpt := "-key-name" + + if fyneCommandVersionCompare(fyneBin, "v2.0.0", ctx, image) >= 0 { + keyStoreOpt = "-keyStore" + keyStorePassOpt = "-keyStorePass" + keyPassOpt = "-keyPass" + keyNameOpt = "-keyName" + } + // workDir default value workDir := ctx.WorkDirContainer() switch image.OS() { case androidOS: workDir = volume.JoinPathContainer(workDir, ctx.Package) - if ctx.Keystore != "" { - args = append(args, "-keyStore", ctx.Keystore) - } - if ctx.KeystorePass != "" { - args = append(args, "-keyStorePass", ctx.KeystorePass) - } - if ctx.KeyPass != "" { - args = append(args, "-keyPass", ctx.KeyPass) - } - if ctx.KeyName != "" { - args = append(args, "-keyName", ctx.KeyName) - } + args = append(args, concatNonEmptyNamedArgs( + keyStoreOpt, ctx.Keystore, + keyStorePassOpt, ctx.KeystorePass, + keyPassOpt, ctx.KeyPass, + keyNameOpt, ctx.KeyName, + )...) case iosOS: if ctx.Certificate != "" { args = append(args, "-certificate", ctx.Certificate) diff --git a/internal/command/container_test.go b/internal/command/container_test.go new file mode 100644 index 0000000..93d2af6 --- /dev/null +++ b/internal/command/container_test.go @@ -0,0 +1,20 @@ +package command + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_concatNonEmptyNamedArgs(t *testing.T) { + assert.Equal(t, []string{"-foo", "42", "-baz", "64"}, concatNonEmptyNamedArgs( + "-foo", "42", + "-bar", "", + "-baz", "64", + ), "filter empty argument/value pair") + assert.Equal(t, []string{"-foo", "42"}, concatNonEmptyNamedArgs( + "-foo", "42", + "-bar", "", + "-baz", + ), "trailing/incomplete/boolean argument") +} diff --git a/internal/command/docker.go b/internal/command/docker.go index 8fb6865..dfa9472 100644 --- a/internal/command/docker.go +++ b/internal/command/docker.go @@ -187,6 +187,14 @@ func (i *localContainerImage) Run(vol volume.Volume, opts options, cmdArgs []str return cmd.Run() } +func (i *localContainerImage) Command(vol volume.Volume, opts options, cmdArgs []string) (string, error) { + cmd := i.cmd(vol, opts, cmdArgs) + cmd.Stdout = nil + log.Debug(cmd) + out, err := cmd.Output() + return string(out), err +} + // pullImage attempts to pull a newer version of the docker image func (i *localContainerImage) Prepare() error { if !i.runner.pull { diff --git a/internal/command/kubernetes.go b/internal/command/kubernetes.go index 20eac43..2948326 100644 --- a/internal/command/kubernetes.go +++ b/internal/command/kubernetes.go @@ -154,6 +154,10 @@ func (i *kubernetesContainerImage) Run(vol volume.Volume, opts options, cmdArgs return i.pod.Run(context.Background(), opts.WorkDir, cmdArgs) } +func (i *kubernetesContainerImage) Command(vol volume.Volume, opts options, cmdArgs []string) (string, error) { + return i.pod.Command(context.Background(), opts.WorkDir, cmdArgs) +} + func AddAWSParameters(aws *cloud.AWSSession, command string, s ...string) []string { r := []string{command}