Skip to content

Commit

Permalink
feat(buildtool): add the gofixpath subcommand (ooni#1484)
Browse files Browse the repository at this point in the history
This subcommand executes another command ensuring a PATH lookup for this
subcommand resolves "go" as the version of Go specified in the
`GOVERSION` file. This is a building block for
ooni/probe#2664.
  • Loading branch information
bassosimone authored and Murphy-OrangeMud committed Feb 13, 2024
1 parent c1ea612 commit e435d33
Show file tree
Hide file tree
Showing 6 changed files with 136 additions and 5 deletions.
32 changes: 32 additions & 0 deletions .github/workflows/gofixpath.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Ensures that ./internal/cmd/buildtool gofixpath {command} [arguments] downloads the correct
# version of go and executes {command} with [arguments] with "go" being the right version.

name: gofixpath
on:
push:
branches:
- "release/**"
- "fullbuild"
- "gofixpathbuild"
- "master"
tags:
- "v*"
pull_request:
schedule:
- cron: "17 7 * * *"

jobs:
build_with_specific_go_version:
strategy:
matrix:
goversion: ["1.19", "1.20", "1.21"] # when releasing check whether we need to update this array
system: [ubuntu-latest, macos-latest]
runs-on: "${{ matrix.system }}"
steps:
- uses: actions/checkout@v3

- uses: actions/setup-go@v4
with:
go-version: "${{ matrix.goversion }}"

- run: go run ./internal/cmd/buildtool gofixpath -- go run ./internal/cmd/buildtool generic miniooni
76 changes: 76 additions & 0 deletions internal/cmd/buildtool/gofixpath.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package main

import (
"fmt"
"path/filepath"

"github.com/apex/log"
"github.com/ooni/probe-cli/v3/internal/cmd/buildtool/internal/buildtoolmodel"
"github.com/ooni/probe-cli/v3/internal/must"
"github.com/ooni/probe-cli/v3/internal/runtimex"
"github.com/ooni/probe-cli/v3/internal/shellx"
"github.com/spf13/cobra"
)

// gofixpathSubcommand returns the gofixpath [cobra.Command].
func gofixpathSubcommand() *cobra.Command {
return &cobra.Command{
Use: "gofixpath",
Short: "Executes a command ensuring the expected version of Go comes first in PATH lookup",
Run: func(cmd *cobra.Command, args []string) {
gofixpathMain(&buildDeps{}, args...)
},
Args: cobra.MinimumNArgs(1),
}
}

// gofixpathMain ensures the correct version of Go is in path, otherwise
// installs such a version, configure the PATH correctly, and then executes
// whatever argument passed to the command with the correct PATH.
func gofixpathMain(deps buildtoolmodel.Dependencies, args ...string) {
// create empty environment
envp := &shellx.Envp{}

// install and configure the correct go version if needed
if !golangCorrectVersionCheckP("GOVERSION") {
// read the version of Go we would like to use
expected := string(must.FirstLineBytes(must.ReadFile("GOVERSION")))

// install the wrapper command
packageName := fmt.Sprintf("golang.org/dl/go%s@latest", expected)
must.Run(log.Log, "go", "install", "-v", packageName)

// run the wrapper to download the distribution
gobinproxy := filepath.Join(
string(must.FirstLineBytes(must.RunOutput(log.Log, "go", "env", "GOPATH"))),
"bin",
fmt.Sprintf("go%s", expected),
)
must.Run(log.Log, gobinproxy, "download")

// add the path to the SDK binary dir
//
// Note: because gomobile wants to execute "go" we must provide the
// path to a directory that contains a command named "go" and we cannot
// just use the gobinproxy binary
sdkbinpath := filepath.Join(
string(must.FirstLineBytes(must.RunOutput(log.Log, gobinproxy, "env", "GOROOT"))),
"bin",
)

// prepend to PATH
envp.Append("PATH", cdepsPrependToPath(sdkbinpath))
}

// create shellx configuration
config := &shellx.Config{
Logger: log.Log,
Flags: shellx.FlagShowStdoutStderr,
}

// create argv
argv := runtimex.Try1(shellx.NewArgv(args[0], args[1:]...)) // safe because cobra.MinimumNArgs(1)

// execute the child command
runtimex.Try0(shellx.RunEx(config, argv, envp))
}
13 changes: 10 additions & 3 deletions internal/cmd/buildtool/golang.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,23 @@ import (
"github.com/ooni/probe-cli/v3/internal/runtimex"
)

// golangCheck checks whether the "go" binary is the correct version
func golangCheck(filename string) {
// golangCorrectVersionCheckP returns whether we're using the correct golang version.
func golangCorrectVersionCheckP(filename string) bool {
expected := string(must.FirstLineBytes(must.ReadFile(filename)))
firstline := string(must.FirstLineBytes(must.RunOutput(log.Log, "go", "version")))
vec := strings.Split(firstline, " ")
runtimex.Assert(len(vec) == 4, "expected four tokens")
if got := vec[2]; got != "go"+expected {
log.Fatalf("expected go%s but got %s", expected, got)
log.Warnf("expected go%s but got %s", expected, got)
return false
}
log.Infof("using go%s", expected)
return true
}

// golangCheck checks whether the "go" binary is the correct version
func golangCheck(filename string) {
runtimex.Assert(golangCorrectVersionCheckP(filename), "invalid Go version")
}

// golangGOPATH returns the GOPATH value.
Expand Down
18 changes: 16 additions & 2 deletions internal/cmd/buildtool/golang_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,20 @@ import (
)

func TestGolangCheck(t *testing.T) {
// make sure the code does not panic when it runs
golangCheck(filepath.Join("..", "..", "..", "GOVERSION"))
t.Run("successful case using the correct go version", func(t *testing.T) {
golangCheck(filepath.Join("..", "..", "..", "GOVERSION"))
})

t.Run("invalid Go version where we expect a panic", func(t *testing.T) {
var panicked bool
func() {
defer func() {
panicked = recover() != nil
}()
golangCheck(filepath.Join("testdata", "GOVERSION"))
}()
if !panicked {
t.Fatal("should have panicked")
}
})
}
1 change: 1 addition & 0 deletions internal/cmd/buildtool/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ func main() {
root.AddCommand(androidSubcommand())
root.AddCommand(darwinSubcommand())
root.AddCommand(genericSubcommand())
root.AddCommand(gofixpathSubcommand())
root.AddCommand(iosSubcommand())
root.AddCommand(linuxSubcommand())
root.AddCommand(oohelperdSubcommand())
Expand Down
1 change: 1 addition & 0 deletions internal/cmd/buildtool/testdata/GOVERSION
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1.17.11

0 comments on commit e435d33

Please sign in to comment.