package forgepb // for golang repos, this is an attempt to build the package // // Additions to 'go build' that are attempted here: // // * detect packages that are plugins // * run autogenpb packages that have .proto protobuf files // * use some 'standard' ldflags (VERISON, BUILDTIME) // import ( "errors" "fmt" "os" "path/filepath" "strings" "time" "go.wit.com/lib/gui/shell" "go.wit.com/lib/protobuf/gitpb" "go.wit.com/log" ) func (f *Forge) Build(repo *gitpb.Repo, userFlags []string) error { return f.doBuild(repo, userFlags, "build") } func (f *Forge) Install(repo *gitpb.Repo, userFlags []string) error { return f.doBuild(repo, userFlags, "install") } func (f *Forge) doBuild(repo *gitpb.Repo, userFlags []string, goWhat string) error { if repo == nil { log.Warn("forge.doBuild repo == nil") return errors.New("forge.doBuild repo == nil") } if f.IsGoWork() { // when building using a go.work file, never use GO111MODULE=off os.Unsetenv("GO111MODULE") } else { // when building from ~/go/src, always use GO111MODULE=off os.Setenv("GO111MODULE", "off") defer os.Unsetenv("GO111MODULE") } if f.IsGoWork() { // there must be a valid go.mod file if compiling with go.work if err := repo.ValidGoSum(); err != nil { log.Warn("forge.doBuild() failed. run go-mod-clean here?") return err } } if repo.Exists(".forge") { log.Info("custom build instructions") data, _ := repo.ReadFile(".forge") log.Info(".forge =", string(data)) log.Info("todo: do the custom build instructions") return nil } // if not GoPrimitive, autogen each dependent git repo if repo.GoDepsLen() != 0 { // build the protobuf files in all protobuf repos all := repo.GoDeps.SortByGoPath() for all.Scan() { t := all.Next() found := f.FindByGoPath(t.GetGoPath()) if found.GetRepoType() == "protobuf" { if err := f.runAutogenpb(found); err != nil { return err } } } } // get the version version := repo.GetCurrentBranchVersion() if version == "" { version = "forgeErr" } if repo.CheckDirty() { version = version + "-dirty" } cmd := []string{"go"} if repo.GetRepoType() == "plugin" { if goWhat == "install" { log.Info("Can not go install plugins yet. just building to ~/go/lib/") } cmd = append(cmd, "build") } else { cmd = append(cmd, goWhat) } _, fname := filepath.Split(repo.FullPath) homeDir, _ := os.UserHomeDir() soname := fname + "." + version + ".so" linkname := fname + ".so" sopath := filepath.Join(homeDir, "go/lib/go-gui") // if this is a plugin, use buildmode=plugin if repo.GetRepoType() == "plugin" { if goWhat == "install" { fullname := filepath.Join(sopath, soname) cmd = append(cmd, "-buildmode=plugin", "-o", fullname) } else { cmd = append(cmd, "-buildmode=plugin", "-o", soname) } } cmd = append(cmd, "-v") // set standard ldflag options now := time.Now() datestamp := now.UTC().Format("2006/01/02_1504_UTC") // log.Info("datestamp =", datestamp) // add some standard golang flags ldflags := "-X main.VERSION=" + version + " " ldflags += "-X main.BUILDTIME=" + datestamp + " " ldflags += "-X main.GUIVERSION=" + version + "" // todo: git this from the filesystem cmd = append(cmd, "-ldflags", ldflags) // add any flags from the command line // this might not actually work // todo: test this for _, flag := range userFlags { cmd = append(cmd, "-ldflags", "-X "+flag) } testenv := os.Getenv("GO111MODULE") if testenv == "off" { log.Info("GO111MODULE=off", "f.goWork =", f.IsGoWork(), "f.gosrc =", f.GetGoSrc()) } else { log.Info("GO111MODULE=", testenv, "f.goWork =", f.IsGoWork(), "f.gosrc =", f.GetGoSrc()) } log.Info("running:", repo.FullPath) log.Info("running:", cmd) result := repo.RunRealtime(cmd) if result.Exit != 0 { // build failed log.DaemonMode(true) log.Info(strings.Join(result.Stdout, "\n")) log.Info(strings.Join(result.Stderr, "\n")) log.Info("result.Error =", result.Error) log.Info("result.Exit =", result.Exit) log.DaemonMode(false) log.Warn("go build failed", cmd) /* pwd, _ := os.Getwd() log.Warn("go build pwd", pwd) res2 := shell.RunEcho(cmd) if res2.Exit == 0 { log.Info("again failed", res2.Exit) log.Info("again failed cmd", strings.Join(cmd, "a")) log.Info("again failed", strings.Join(res2.Stdout, "\n")) } */ return errors.New("go " + goWhat + " failed: " + fmt.Sprint(result.Error)) } // make symlinks if repo.GetRepoType() == "plugin" { cmd := []string{"ln", "-sf", soname, linkname} if goWhat == "install" { shell.PathRun(sopath, cmd) } else { repo.Run(cmd) } } log.Info(strings.Join(result.Stdout, "\n")) return nil } func (f *Forge) runAutogenpb(repo *gitpb.Repo) error { // log.Info("run autogenpb here:", repo.GetGoPath()) files, err := repo.GetProtoFiles() if err != nil { log.Info("gitpb.GetProtoFiles()", err) return err } for _, s := range files { _, filename := filepath.Split(s) pbfile := strings.TrimSuffix(filename, ".proto") + ".pb.go" cmd := []string{"autogenpb", "--proto", filename} if repo.Exists(pbfile) { // log.Info("skip running:", cmd) continue } log.Info("running:", cmd) r := repo.RunRealtime(cmd) if r.Error != nil { log.Warn("") log.Warn("autogenpb error", r.Error) log.Warn("") log.Warn("You might be missing autogenpb?") log.Warn("") log.Warn("To install it run: go install go.wit.com/apps/autogenpb@latest") log.Warn("") log.Sleep(2) return r.Error } } return nil } // sortcut to find func (f *Forge) FindWorkingDirRepo() *gitpb.Repo { pwd, _ := os.Getwd() basedir := strings.TrimPrefix(pwd, f.GetGoSrc()) basedir = strings.Trim(basedir, "/") return f.FindByGoPath(basedir) }