diff --git a/cmd/bob/baseimageconf.go b/cmd/bob/baseimageconf.go index 030b70c..05cf85b 100644 --- a/cmd/bob/baseimageconf.go +++ b/cmd/bob/baseimageconf.go @@ -8,6 +8,7 @@ import ( "github.com/function61/gokit/encoding/jsonfile" "github.com/function61/gokit/os/osutil" + "github.com/function61/turbobob/pkg/bobfile" ) const ( @@ -16,9 +17,9 @@ const ( // base image conf JSON - able to provide hints for useful commands, setting up cache paths etc. type BaseImageConfig struct { - DevShellCommands []DevShellCommand `json:"dev_shell_commands"` - PathsToCache []string `json:"paths_to_cache"` // will be set up as symlinks to a persistent mountpoint, so that subsequent containers benefit from cache - Langserver *LangserverSpec `json:"langserver"` + DevShellCommands []bobfile.DevShellCommand `json:"dev_shell_commands"` + PathsToCache []string `json:"paths_to_cache"` // will be set up as symlinks to a persistent mountpoint, so that subsequent containers benefit from cache + Langserver *LangserverSpec `json:"langserver"` FileDescriptionBoilerplate string `json:"for_description_of_this_file_see"` // URL to Bob homepage @@ -54,7 +55,7 @@ func loadBaseImageConfWhenInsideContainer() (*BaseImageConfig, error) { // non-optional because the implementation makes it a bit hard to check if the file exists // (vs. Docker run error), and our current callsite needs non-optional anyway -func loadNonOptionalBaseImageConf(builder BuilderSpec) (*BaseImageConfig, error) { +func loadNonOptionalBaseImageConf(builder bobfile.BuilderSpec) (*BaseImageConfig, error) { dockerImage, err := func() (string, error) { kind, data, err := parseBuilderUsesType(builder.Uses) if err != nil { diff --git a/cmd/bob/build.go b/cmd/bob/build.go index 6e1e077..2dcdbda 100644 --- a/cmd/bob/build.go +++ b/cmd/bob/build.go @@ -11,12 +11,13 @@ import ( "time" "github.com/function61/gokit/os/osutil" + "github.com/function61/turbobob/pkg/bobfile" "github.com/function61/turbobob/pkg/versioncontrol" "github.com/spf13/cobra" ) type BuildContext struct { - Bobfile *Bobfile + Bobfile *bobfile.Bobfile OriginDir string // where the repo exists WorkspaceDir string // where the revision is being built PublishArtefacts bool @@ -31,7 +32,7 @@ type BuildContext struct { IsDefaultBranch bool // whether we are in "main" / "master" or equivalent branch } -func runBuilder(builder BuilderSpec, buildCtx *BuildContext, opDesc string, cmdToRun []string) error { +func runBuilder(builder bobfile.BuilderSpec, buildCtx *BuildContext, opDesc string, cmdToRun []string) error { wd, errWd := os.Getwd() if errWd != nil { return errWd @@ -125,7 +126,7 @@ func runBuilder(builder BuilderSpec, buildCtx *BuildContext, opDesc string, cmdT return nil } -func buildAndPushOneDockerImage(dockerImage DockerImageSpec, buildCtx *BuildContext) error { +func buildAndPushOneDockerImage(dockerImage bobfile.DockerImageSpec, buildCtx *BuildContext) error { tagWithoutVersion := dockerImage.Image tag := tagWithoutVersion + ":" + buildCtx.RevisionId.FriendlyRevisionId tagLatest := tagWithoutVersion + ":latest" @@ -362,7 +363,7 @@ func build(buildCtx *BuildContext) error { } // three-pass process. the flow is well documented in *BuilderCommands* type - pass := func(opDesc string, getCommand func(cmds BuilderCommands) []string) error { + pass := func(opDesc string, getCommand func(cmds bobfile.BuilderCommands) []string) error { for _, builder := range buildCtx.Bobfile.Builders { if buildCtx.BuilderNameFilter != "" && builder.Name != buildCtx.BuilderNameFilter { continue @@ -381,9 +382,9 @@ func build(buildCtx *BuildContext) error { return nil } - preparePass := func(cmds BuilderCommands) []string { return cmds.Prepare } - buildPass := func(cmds BuilderCommands) []string { return cmds.Build } - publishPass := func(cmds BuilderCommands) []string { return cmds.Publish } + preparePass := func(cmds bobfile.BuilderCommands) []string { return cmds.Prepare } + buildPass := func(cmds bobfile.BuilderCommands) []string { return cmds.Build } + publishPass := func(cmds bobfile.BuilderCommands) []string { return cmds.Publish } if err := pass("prepare", preparePass); err != nil { return err // err context ok @@ -426,7 +427,7 @@ func constructBuildContext( fastBuild bool, areWeInCi bool, ) (*BuildContext, error) { - bobfile, err := readBobfile() + bobfile, err := bobfile.Read() if err != nil { return nil, err } @@ -579,7 +580,7 @@ func buildInsideEntry() *cobra.Command { } func buildInside(fastBuild bool) error { - bobfile, err := readBobfile() + bobfile, err := bobfile.Read() if err != nil { return err } diff --git a/cmd/bob/dev.go b/cmd/bob/dev.go index 577c8b0..44a8ff4 100644 --- a/cmd/bob/dev.go +++ b/cmd/bob/dev.go @@ -11,12 +11,13 @@ import ( "github.com/function61/gokit/encoding/jsonfile" "github.com/function61/gokit/os/osutil" + "github.com/function61/turbobob/pkg/bobfile" "github.com/function61/turbobob/pkg/versioncontrol" "github.com/spf13/cobra" ) func devCommand(builderName string, envsAreRequired bool, ignoreNag bool) ([]string, error) { - bobfile, err := readBobfile() + bobfile, err := bobfile.Read() if err != nil { return nil, err } @@ -264,7 +265,7 @@ func revisionIdForDev() *versioncontrol.RevisionId { } } -func buildArchOnlyForCurrentlyRunningArch(archesToBuildFor OsArchesSpec) OsArchesSpec { +func buildArchOnlyForCurrentlyRunningArch(archesToBuildFor bobfile.OsArchesSpec) bobfile.OsArchesSpec { devMachineArch := osArchCodeToOsArchesSpec(currentRunningGoOsArchToOsArchCode()) // to speed up dev, build only for the arch we're running now, but only if arches diff --git a/cmd/bob/devingress.go b/cmd/bob/devingress.go index 46e5db6..e3f0a51 100644 --- a/cmd/bob/devingress.go +++ b/cmd/bob/devingress.go @@ -4,13 +4,15 @@ import ( "fmt" "os" "strings" + + "github.com/function61/turbobob/pkg/bobfile" ) // uses Traefik-compliant notation to set up HTTP ingress to route traffic to the dev container func setupDevIngress( - builder *BuilderSpec, + builder *bobfile.BuilderSpec, ingressSettings devIngressSettings, - bobfile *Bobfile, + bobfile *bobfile.Bobfile, ) ([]string, string) { if builder.DevHttpIngress == "" { return nil, "" diff --git a/cmd/bob/devshim.go b/cmd/bob/devshim.go index 9463b2f..9d2bd51 100644 --- a/cmd/bob/devshim.go +++ b/cmd/bob/devshim.go @@ -12,6 +12,7 @@ import ( "github.com/function61/gokit/encoding/jsonfile" "github.com/function61/gokit/os/osutil" + "github.com/function61/turbobob/pkg/bobfile" "github.com/spf13/cobra" ) @@ -72,9 +73,9 @@ func shimSetup() error { return err } - bobfile, err := readBobfile() + bobfile, err := bobfile.Read() if err != nil { - return fmt.Errorf("readBobfile: %w", err) + return err } shimConf, err := readShimConfig() @@ -147,7 +148,7 @@ func shimSetup() error { } // so we can recall frequently needed commands fast + sets up HISTFILE ENV var -func injectHistory(builder BuilderSpec, alreadyDone bool, baseImgConf BaseImageConfig) error { +func injectHistory(builder bobfile.BuilderSpec, alreadyDone bool, baseImgConf BaseImageConfig) error { userHomeDir, err := os.UserHomeDir() if err != nil { return err diff --git a/cmd/bob/docker.go b/cmd/bob/docker.go index 75d9429..5391cea 100644 --- a/cmd/bob/docker.go +++ b/cmd/bob/docker.go @@ -10,6 +10,7 @@ import ( "strings" . "github.com/function61/gokit/builtin" + "github.com/function61/turbobob/pkg/bobfile" "github.com/function61/turbobob/pkg/dockertag" "github.com/function61/turbobob/pkg/versioncontrol" ) @@ -24,21 +25,21 @@ func isDevContainerRunning(containerName string) bool { return strings.TrimRight(string(result), "\n") == "true" } -func devContainerName(bobfile *Bobfile, builder BuilderSpec) string { +func devContainerName(bobfile *bobfile.Bobfile, builder bobfile.BuilderSpec) string { return containerNameInternal("dev", bobfile, builder) } -func langServerContainerName(bobfile *Bobfile, builder BuilderSpec) string { +func langServerContainerName(bobfile *bobfile.Bobfile, builder bobfile.BuilderSpec) string { return containerNameInternal("langserver", bobfile, builder) } // do not use directly -func containerNameInternal(kind string, bobfile *Bobfile, builder BuilderSpec) string { +func containerNameInternal(kind string, bobfile *bobfile.Bobfile, builder bobfile.BuilderSpec) string { return fmt.Sprintf("tb%s-%s-%s", kind, bobfile.ProjectName, builder.Name) } -func builderImageName(bobfile *Bobfile, builder BuilderSpec) string { +func builderImageName(bobfile *bobfile.Bobfile, builder bobfile.BuilderSpec) string { builderType, ref, err := parseBuilderUsesType(builder.Uses) if err != nil { panic(err) @@ -54,7 +55,7 @@ func builderImageName(bobfile *Bobfile, builder BuilderSpec) string { } } -func buildBuilder(bobfile *Bobfile, builder *BuilderSpec) error { +func buildBuilder(bobfile *bobfile.Bobfile, builder *bobfile.BuilderSpec) error { imageName := builderImageName(bobfile, *builder) builderUsesType, dockerfilePath, err := parseBuilderUsesType(builder.Uses) @@ -114,9 +115,9 @@ func buildBuilder(bobfile *Bobfile, builder *BuilderSpec) error { func dockerRelayEnvVars( dockerArgs []string, revisionId *versioncontrol.RevisionId, - builder BuilderSpec, + builder bobfile.BuilderSpec, envsAreRequired bool, - osArches OsArchesSpec, + osArches bobfile.OsArchesSpec, fastbuild bool, debug bool, ) ([]string, error) { @@ -166,7 +167,7 @@ func dockerRelayEnvVars( return dockerArgs, nil } -func loginToDockerRegistry(dockerImage DockerImageSpec, cache *dockerRegistryLoginCache) error { +func loginToDockerRegistry(dockerImage bobfile.DockerImageSpec, cache *dockerRegistryLoginCache) error { credentialsObtainer := getDockerCredentialsObtainer(dockerImage) creds, err := credentialsObtainer.Obtain() if err != nil { @@ -179,7 +180,7 @@ func loginToDockerRegistry(dockerImage DockerImageSpec, cache *dockerRegistryLog tagParsed := dockertag.Parse(dockerImage.Image) if tagParsed == nil { - return ErrUnableToParseDockerTag + return bobfile.ErrUnableToParseDockerTag } registryDefaulted := tagParsed.Registry diff --git a/cmd/bob/dockercredentials.go b/cmd/bob/dockercredentials.go index dd6a755..b496396 100644 --- a/cmd/bob/dockercredentials.go +++ b/cmd/bob/dockercredentials.go @@ -4,6 +4,8 @@ import ( "errors" "os" "regexp" + + "github.com/function61/turbobob/pkg/bobfile" ) type DockerCredentials struct { @@ -28,7 +30,7 @@ func (d *credsFromENV) Obtain() (*DockerCredentials, error) { credsParts := credsFromENVRe.FindStringSubmatch(serialized) if len(credsParts) != 3 { - return nil, ErrInvalidDockerCredsEnvFormat + return nil, bobfile.ErrInvalidDockerCredsEnvFormat } return &DockerCredentials{ @@ -37,7 +39,7 @@ func (d *credsFromENV) Obtain() (*DockerCredentials, error) { }, nil } -func getDockerCredentialsObtainer(dockerImage DockerImageSpec) DockerCredentialObtainer { +func getDockerCredentialsObtainer(dockerImage bobfile.DockerImageSpec) DockerCredentialObtainer { if dockerImage.AuthType == nil { return &credsFromENV{} } diff --git a/cmd/bob/init.go b/cmd/bob/init.go index 23ddffb..f7499eb 100644 --- a/cmd/bob/init.go +++ b/cmd/bob/init.go @@ -9,6 +9,7 @@ import ( . "github.com/function61/gokit/builtin" "github.com/function61/gokit/os/osutil" + "github.com/function61/turbobob/pkg/bobfile" "github.com/spf13/cobra" ) @@ -82,26 +83,26 @@ func writeDefaultBobfile(producesDockerImage bool) error { // guess project name from current workdir's basename projectName := filepath.Base(cwd) - dockerImages := []DockerImageSpec{} + dockerImages := []bobfile.DockerImageSpec{} if producesDockerImage { - dockerImages = append(dockerImages, DockerImageSpec{ + dockerImages = append(dockerImages, bobfile.DockerImageSpec{ Image: "yourcompany/" + projectName, DockerfilePath: "Dockerfile", }) } - defaults := Bobfile{ - FileDescriptionBoilerplate: fileDescriptionBoilerplate, - VersionMajor: currentVersionMajor, + defaults := bobfile.Bobfile{ + FileDescriptionBoilerplate: bobfile.FileDescriptionBoilerplate, + VersionMajor: bobfile.CurrentVersionMajor, ProjectName: projectName, - Builders: []BuilderSpec{ + Builders: []bobfile.BuilderSpec{ { Name: "default", Uses: "dockerfile://build-default.Dockerfile", MountSource: "", MountDestination: "/app", PassEnvs: []string{}, - Commands: BuilderCommands{ + Commands: bobfile.BuilderCommands{ Dev: []string{"bash"}, }, DevProTips: []string{}, @@ -115,14 +116,14 @@ func writeDefaultBobfile(producesDockerImage bool) error { return writeBobfileIfNotExists(defaults) } -func writeBobfileIfNotExists(content Bobfile) error { - exists, errExistsCheck := osutil.Exists(bobfileName) +func writeBobfileIfNotExists(content bobfile.Bobfile) error { + exists, errExistsCheck := osutil.Exists(bobfile.Name) if errExistsCheck != nil { return errExistsCheck } if exists { - return ErrInitBobfileExists + return bobfile.ErrInitBobfileExists } asJson, errJson := json.MarshalIndent(&content, "", "\t") @@ -130,12 +131,12 @@ func writeBobfileIfNotExists(content Bobfile) error { return errJson } - if err := os.MkdirAll(filepath.Dir(bobfileName), 0755); err != nil { + if err := os.MkdirAll(filepath.Dir(bobfile.Name), 0755); err != nil { return err } return ioutil.WriteFile( - bobfileName, + bobfile.Name, []byte(fmt.Sprintf("%s\n", asJson)), osutil.FileMode(osutil.OwnerRW, osutil.GroupRW, osutil.OtherNone)) } diff --git a/cmd/bob/initguess.go b/cmd/bob/initguess.go index d815b49..e784481 100644 --- a/cmd/bob/initguess.go +++ b/cmd/bob/initguess.go @@ -9,6 +9,7 @@ import ( "path/filepath" . "github.com/function61/gokit/builtin" + "github.com/function61/turbobob/pkg/bobfile" "github.com/moby/buildkit/frontend/dockerfile/instructions" "github.com/moby/buildkit/frontend/dockerfile/parser" ) @@ -63,16 +64,16 @@ func initGuessFromDockerfile() error { return err } - return writeBobfileIfNotExists(Bobfile{ - FileDescriptionBoilerplate: fileDescriptionBoilerplate, - VersionMajor: currentVersionMajor, + return writeBobfileIfNotExists(bobfile.Bobfile{ + FileDescriptionBoilerplate: bobfile.FileDescriptionBoilerplate, + VersionMajor: bobfile.CurrentVersionMajor, ProjectName: projectName, - Builders: []BuilderSpec{ + Builders: []bobfile.BuilderSpec{ { Name: "default", Uses: "docker://" + builderStage.BaseName, MountDestination: copyCommand.DestPath, - Commands: BuilderCommands{ + Commands: bobfile.BuilderCommands{ Build: buildCommand, Dev: []string{"bash"}, // just a guess }, diff --git a/cmd/bob/langserver.go b/cmd/bob/langserver.go index ec668e7..b201e3c 100644 --- a/cmd/bob/langserver.go +++ b/cmd/bob/langserver.go @@ -13,6 +13,7 @@ import ( "github.com/function61/gokit/os/osutil" "github.com/function61/gokit/sliceutil" + "github.com/function61/turbobob/pkg/bobfile" "github.com/spf13/cobra" ) @@ -58,13 +59,13 @@ func langserverRunShim(ctx context.Context, langs []string) error { mountDir := workdir // access chosen project's details (so we know which programming language's langserver to start) - bobfile, err := readBobfile() + projectFile, err := bobfile.Read() if err != nil { return err } - langserverCmd, builder, err := func() ([]string, *BuilderSpec, error) { - for _, builder := range bobfile.Builders { + langserverCmd, builder, err := func() ([]string, *bobfile.BuilderSpec, error) { + for _, builder := range projectFile.Builders { // FIXME: this assumes baseImageConf, err := loadNonOptionalBaseImageConf(builder) if err != nil { @@ -82,7 +83,7 @@ func langserverRunShim(ctx context.Context, langs []string) error { return nil, nil, fmt.Errorf( "%s doesn't define a compatible language server for %v", - bobfile.ProjectName, + projectFile.ProjectName, langs) }() if err != nil { @@ -99,7 +100,7 @@ func langserverRunShim(ctx context.Context, langs []string) error { "--rm", // so resources get released. (this process is ephemeral in nature) "--shm-size=512M", "--interactive", // use stdin (it is the transport for one direction in LSP) - "--name=" + langServerContainerName(bobfile, *builder), + "--name=" + langServerContainerName(projectFile, *builder), "--volume", fmt.Sprintf("%s:%s", workdir, mountDir), dockerImage, }, langserverCmd...) diff --git a/cmd/bob/osarchcodes.go b/cmd/bob/osarchcodes.go index 7093062..52c1086 100644 --- a/cmd/bob/osarchcodes.go +++ b/cmd/bob/osarchcodes.go @@ -1,5 +1,9 @@ package main +import ( + "github.com/function61/turbobob/pkg/bobfile" +) + // looks like "linux-amd64" (JSON keys in OsArchesSpec). need to add to // - OsArchesSpec // - AsBuildEnvVariables() @@ -8,31 +12,31 @@ package main type OsArchCode string // TODO: a test that guarantees that this is in sync with OsArchesSpec? -func osArchCodeToOsArchesSpec(code OsArchCode) OsArchesSpec { +func osArchCodeToOsArchesSpec(code OsArchCode) bobfile.OsArchesSpec { switch code { case "neutral": - return OsArchesSpec{Neutral: true} + return bobfile.OsArchesSpec{Neutral: true} case "linux-neutral": - return OsArchesSpec{LinuxNeutral: true} + return bobfile.OsArchesSpec{LinuxNeutral: true} case "linux-amd64": - return OsArchesSpec{LinuxAmd64: true} + return bobfile.OsArchesSpec{LinuxAmd64: true} case "linux-arm": - return OsArchesSpec{LinuxArm: true} + return bobfile.OsArchesSpec{LinuxArm: true} case "linux-arm64": - return OsArchesSpec{LinuxArm64: true} + return bobfile.OsArchesSpec{LinuxArm64: true} case "windows-neutral": - return OsArchesSpec{WindowsNeutral: true} + return bobfile.OsArchesSpec{WindowsNeutral: true} case "windows-amd64": - return OsArchesSpec{WindowsAmd64: true} + return bobfile.OsArchesSpec{WindowsAmd64: true} case "darwin-amd64": - return OsArchesSpec{DarwinAmd64: true} + return bobfile.OsArchesSpec{DarwinAmd64: true} default: - return OsArchesSpec{} + return bobfile.OsArchesSpec{} } } // TODO: a test that guarantees that this is in sync with OsArchesSpec? -func osArchesIntersects(a OsArchesSpec, b OsArchesSpec) bool { +func osArchesIntersects(a bobfile.OsArchesSpec, b bobfile.OsArchesSpec) bool { return a.Neutral && b.Neutral || a.LinuxNeutral && b.LinuxNeutral || a.LinuxAmd64 && b.LinuxAmd64 || diff --git a/cmd/bob/quality.go b/cmd/bob/quality.go index de7ba83..243e461 100644 --- a/cmd/bob/quality.go +++ b/cmd/bob/quality.go @@ -5,9 +5,11 @@ import ( "fmt" "os" "strings" + + "github.com/function61/turbobob/pkg/bobfile" ) -func qualityCheckBuilderUsesExpect(rules map[string]string, bobfile *Bobfile) error { +func qualityCheckBuilderUsesExpect(rules map[string]string, bobfile *bobfile.Bobfile) error { for _, builder := range bobfile.Builders { for substring, expectFull := range rules { if strings.Contains(builder.Uses, substring) && builder.Uses != expectFull { diff --git a/cmd/bob/subrepo.go b/cmd/bob/subrepo.go index 6f1b94f..9092dde 100644 --- a/cmd/bob/subrepo.go +++ b/cmd/bob/subrepo.go @@ -4,10 +4,11 @@ import ( "fmt" "github.com/function61/gokit/os/osutil" + "github.com/function61/turbobob/pkg/bobfile" "github.com/function61/turbobob/pkg/versioncontrol" ) -func ensureSubrepoCloned(destination string, subrepo SubrepoSpec) error { +func ensureSubrepoCloned(destination string, subrepo bobfile.SubrepoSpec) error { exists, err := osutil.Exists(destination) if err != nil { return err diff --git a/cmd/bob/tips.go b/cmd/bob/tips.go index 4e8e9c9..717e6b4 100644 --- a/cmd/bob/tips.go +++ b/cmd/bob/tips.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/function61/gokit/os/osutil" + "github.com/function61/turbobob/pkg/bobfile" "github.com/scylladb/termtables" "github.com/spf13/cobra" ) @@ -20,7 +21,7 @@ func tipsEntry() *cobra.Command { } func tips() error { - bobfile, err := readBobfile() + bobfile, err := bobfile.Read() if err != nil { return err } diff --git a/cmd/bob/utils.go b/cmd/bob/utils.go index e658534..18630cb 100644 --- a/cmd/bob/utils.go +++ b/cmd/bob/utils.go @@ -1,12 +1,15 @@ package main import ( + "errors" "fmt" "io" "os" "os/exec" "strings" "sync" + + "github.com/function61/turbobob/pkg/bobfile" ) func passthroughStdoutAndStderr(cmd *exec.Cmd) *exec.Cmd { @@ -20,7 +23,11 @@ func isEnvVarPresent(key string) bool { return os.Getenv(key) != "" } -func allDevShellCommands(devShellCommands []DevShellCommand) []string { +func envVarMissingErr(envKey string) error { + return errors.New("ENV var missing: " + envKey) +} + +func allDevShellCommands(devShellCommands []bobfile.DevShellCommand) []string { commands := []string{} for _, command := range devShellCommands { commands = append(commands, command.Command) @@ -40,6 +47,16 @@ func must(input builderUsesType, _ string, err error) builderUsesType { return input } +func findBuilder(projectFile *bobfile.Bobfile, builderName string) (*bobfile.BuilderSpec, error) { + for _, builder := range projectFile.Builders { + if builder.Name == builderName { + return &builder, nil + } + } + + return nil, bobfile.ErrBuilderNotFound +} + func withLogLineGroup(group string, work func() error) error { if !runningInGitHubActions() { printHeading(group) diff --git a/cmd/bob/workspace.go b/cmd/bob/workspace.go index 8f489f1..24fc3f8 100755 --- a/cmd/bob/workspace.go +++ b/cmd/bob/workspace.go @@ -12,6 +12,7 @@ import ( "os" "github.com/function61/gokit/os/osutil" + "github.com/function61/turbobob/pkg/bobfile" "github.com/spf13/cobra" ) @@ -97,7 +98,7 @@ func workspaceLaunchFileBrowser() error { } func workspaceRenameToSelectedProject() error { - bobfile, err := readBobfile() + bobfile, err := bobfile.Read() if err != nil { return err } diff --git a/cmd/bob/bobfile.go b/pkg/bobfile/bobfile.go similarity index 92% rename from cmd/bob/bobfile.go rename to pkg/bobfile/bobfile.go index 5f0f25b..51510ea 100644 --- a/cmd/bob/bobfile.go +++ b/pkg/bobfile/bobfile.go @@ -1,4 +1,5 @@ -package main +// Project configuration file for Turbo Bob +package bobfile import ( "errors" @@ -13,12 +14,12 @@ import ( ) const ( - bobfileName = ".config/turbobob.json" - fileDescriptionBoilerplate = "https://github.com/function61/turbobob" + Name = ".config/turbobob.json" + FileDescriptionBoilerplate = "https://github.com/function61/turbobob" ) const ( - currentVersionMajor = 1 + CurrentVersionMajor = 1 ) type Bobfile struct { @@ -166,9 +167,11 @@ type DockerImageSpec struct { // FIXME: Bobfile should actually be read only after correct // revision has been checked out from VCs -func readBobfile() (*Bobfile, error) { +func Read() (*Bobfile, error) { + withErr := func(err error) (*Bobfile, error) { return nil, fmt.Errorf("bobfile.Read: %w", err) } + bobfileFile, err := func() (io.ReadCloser, error) { - bobfileFile, err := os.Open(bobfileName) + bobfileFile, err := os.Open(Name) if err != nil && errors.Is(err, fs.ErrNotExist) { // try old filename return os.Open("turbobob.json") } @@ -177,28 +180,28 @@ func readBobfile() (*Bobfile, error) { }() if err != nil { if errors.Is(err, fs.ErrNotExist) { - return nil, ErrBobfileNotFound + return withErr(ErrBobfileNotFound) } else { - return nil, err + return withErr(err) } } defer bobfileFile.Close() bobfile := &Bobfile{} if err := jsonfile.UnmarshalDisallowUnknownFields(bobfileFile, bobfile); err != nil { - return nil, err + return withErr(err) } - if bobfile.VersionMajor != currentVersionMajor { - return nil, ErrUnsupportedBobfileVersion + if bobfile.VersionMajor != CurrentVersionMajor { + return withErr(ErrUnsupportedBobfileVersion) } - if bobfile.FileDescriptionBoilerplate != fileDescriptionBoilerplate { - return nil, ErrIncorrectFileDescriptionBp + if bobfile.FileDescriptionBoilerplate != FileDescriptionBoilerplate { + return withErr(ErrIncorrectFileDescriptionBp) } if err := validateBuilders(bobfile); err != nil { - return nil, ErrorWrap("validateBuilders", err) + return withErr(ErrorWrap("validateBuilders", err)) } for _, subrepo := range bobfile.Subrepos { @@ -207,7 +210,7 @@ func readBobfile() (*Bobfile, error) { // the value is missing, the func does not get called. IOW unmarshaling can still // end up in broken data, so we must check it manually.. if err := ErrorIfUnset(subrepo.Kind == "", "subrepo.Kind"); err != nil { - return nil, err + return withErr(err) } } @@ -235,13 +238,3 @@ func validateBuilders(bobfile *Bobfile) error { return nil } - -func findBuilder(bobfile *Bobfile, builderName string) (*BuilderSpec, error) { - for _, builder := range bobfile.Builders { - if builder.Name == builderName { - return &builder, nil - } - } - - return nil, ErrBuilderNotFound -} diff --git a/cmd/bob/errors.go b/pkg/bobfile/errors.go similarity index 78% rename from cmd/bob/errors.go rename to pkg/bobfile/errors.go index c7b90d7..a6386a5 100644 --- a/cmd/bob/errors.go +++ b/pkg/bobfile/errors.go @@ -1,4 +1,4 @@ -package main +package bobfile import ( "errors" @@ -14,6 +14,11 @@ var ( ErrIncorrectFileDescriptionBp = errors.New("you are not supposed to change FileDescriptionBoilerplate") ) -func envVarMissingErr(envKey string) error { - return errors.New("ENV var missing: " + envKey) +// tech debt: can't update to newer Go to use this func from gokit +func firstNonEmpty(a, b string) string { + if a != "" { + return a + } else { + return b + } }