// Copyright 2017-2025 WIT.COM Inc. All rights reserved. // Use of this source code is governed by the GPL 3.0 package main import ( "errors" "fmt" "os" "path/filepath" "strconv" "strings" "go.wit.com/lib/ENV" "go.wit.com/lib/cobol" "go.wit.com/lib/debian" "go.wit.com/lib/fhelp" "go.wit.com/lib/gui/shell" "go.wit.com/lib/protobuf/gitpb" "go.wit.com/log" ) // find packages that need to be built func findBuildDeb() *gitpb.Repos { initForge() var dumbtable [][]string dumbtable = append(dumbtable, []string{"FullPath", "version", "reason"}) found := gitpb.NewRepos() for check := range me.forge.Repos.IterAll() { var reason string if me.forge.Config.IsReadOnly(check.GetNamespace()) { reason = "readonly" continue } if me.forge.Config.IsPrivate(check.GetNamespace()) { if !argv.Build.Debian.Priv { reason = "private" continue } } if !check.IsBinary() { reason = "not-binary" // can't build packages that aren't GO binaries continue } if argv.Build.Debian.Arch != "" { if check.IsGoPlugin() { reason = "plugin" continue } // mask some packages for arch builds if strings.Contains(check.Namespace, "fyne") { reason = "plugin" continue } if strings.Contains(check.Namespace, "toolkit") { reason = "broken" continue } if strings.Contains(check.Namespace, "going2git") { reason = "broken" continue } } if argv.All { // don't check if you need to build, just build everything } else { if shouldBuild(check) == "yes" { // need to build } else { var version string bvers, err := getBuildVersion(check) if err == nil { version = check.DebianCurrentVersion(bvers) } else { version = fmt.Sprintf("err=(%v)", err) } // log.Info(check.FullPath, "not building for reasons: todo: get reason") dumbtable = append(dumbtable, []string{check.FullPath, version, reason}) continue } } found.Append(check) } footer := cobol.SimpleTable(dumbtable) log.Info("simple build table footer:", footer) found.ActualSort() return found } var totalBuilt int func doBuildDeb(all *gitpb.Repos) (string, error) { log.Info("STARTING DEBIAN PACKAGE BUILD") // clean out old deb files globPattern := filepath.Join(me.homedir, "incoming", "*.deb") files, err := filepath.Glob(globPattern) if len(files) > 0 { log.Info(files, err) log.Info("You have files in ~/incoming/") return "incoming/ not empty", errors.New("already have incoming files") } footer := printPackagingTable(all) log.Info("This is what will and will not be built:", footer) me.forge.ConfigRill(16, 16) stats := me.forge.RunOnRepos(all, buildDeb) for s, stat := range stats { if stat.Err != nil { return "ERROR WITH buildDeb " + s, stat.Err } } if totalBuilt == 0 { if argv.DryRun { log.Info("") return "--dry-run TRUE (nothing done)", nil } // nothing built, no need to talk to mirrors return "everything is current", nil } if _, err := shell.RunVerbose([]string{"ls", "-l", "/home/jcarr/incoming"}); err != nil { me.argv.BadExit("aptly failed", nil) } if _, err := fhelp.RunRealtimeError([]string{"do-aptly"}); err != nil { me.argv.BadExit("aptly failed", nil) } return "all .deb built ok", nil } // avoids nil panics func isDebianRelease() bool { if argv.Build == nil { return false } if argv.Build.Debian == nil { return false } return argv.Build.Debian.Release } func shouldBuild(repo *gitpb.Repo) string { // NEVER EVER EVER BUILD DIRTY .deb PACKAGES // versioning with debian will prioritize the 'd' before numbers // so packages will be randomly upgraded based on the git hash // just do a commit. Do not 'fix' this. This is a good idea anyway. // This should be a policy everywhere. if repo.IsDirty() { return "no" } ver := repo.GetCurrentVersion() debname := getDebFilename(repo) if !debian.DebFilenameMatchesVersion(debname, ver) { return "yes" } if argv.All { return "yes" } return "" } func getBuildVersion(repo *gitpb.Repo) (int, error) { _, reponame := filepath.Split(repo.Namespace) if !ENV.InitValid() { log.Info("ENV.Get() InitValid() false", reponame) return 0, ENV.NotInitialized } if ENV.Get(reponame) == "" { // first time for this repo ENV.Set(reponame, log.Sprintf("%s %s", repo.DebianCurrentVersion(0), "0")) err := ENV.Save() log.Info("ENV.Get() was blank", reponame, err) return 0, err } parts := strings.Fields(ENV.Get(reponame)) // log.Printf("ENV.Get() worked var(%s) parts[%v]\n", reponame, parts) if len(parts) != 2 { log.Info("ENV.Get() wierd setting. fix manually:", reponame, parts) return 0, errors.New("fix manually in ~/.config/mirrors/config.text") } i, err := strconv.Atoi(parts[1]) newi := i + 1 if err != nil { log.Info("ENV.Save() strconv.Atoi() err:", reponame, parts, err) } // log.Info("ENV.Get() worked", parts, err, i, newi) ENV.Set(reponame, log.Sprintf("%s %d", repo.DebianCurrentVersion(0), newi)) errors.Join(err, ENV.Save()) if err != nil { log.Info("ENV.Save() err:", reponame, err) } return newi, err } func buildDeb(repo *gitpb.Repo) error { var cmd []string outdir := getOutdir(repo) os.MkdirAll(outdir, 0755) if isDebianRelease() { cmd = []string{"go-deb", "--release", "--namespace", repo.Namespace, "--dir", outdir} } else { cmd = []string{"go-deb", "--namespace", repo.Namespace, "--dir", outdir} } if me.forge.Config.IsPrivate(repo.GetNamespace()) { cmd = []string{"go-deb", "--namespace", repo.Namespace, "--dir", outdir} // return nil } if argv.Build.Debian.Arch != "" { cmd = append(cmd, "--arch", argv.Build.Debian.Arch) } _, reponame := filepath.Split(repo.Namespace) if shouldBuild(repo) != "yes" { // shouldn't build this one return nil } else { if reponame != "autogenpb" { log.Info("WHY BUILD AUTOGEN HERE shouldBuild(repo) said", shouldBuild(repo)) } } // try to use lib/config bvers, err := getBuildVersion(repo) if reponame != "autogenpb" { log.Info("WHY BUILD AUTOGEN HERE", reponame, bvers, err) } if err == nil { log.Info("ENV.Get() gave back new buildId", bvers, repo.Namespace) } else { log.Info("ENV.Get() gave back err new buildId", bvers, err, repo.Namespace) panic("ENV.Get() error") } cmd = append(cmd, "--buildversion", log.Sprintf("%d", bvers)) if argv.Verbose { // log.Info("build cmd:", cmd) cmd = append(cmd, "--verbose") } debname := me.forge.Config.DebName(repo.GetNamespace()) debname += "." + me.forge.GetPackageVersion(repo) + ".deb" if argv.DryRun { log.Info("RUN:", repo.FullPath, debname) log.Info("RUN:", cmd) return nil } log.Info("Building", debname, cmd) if _, err = repo.RunVerboseOnError(cmd); err != nil { log.Info(repo.FullPath, cmd) return err } totalBuilt += 1 log.Info("build worked", cmd, repo.FullPath) return nil } func getOutdir(repo *gitpb.Repo) string { if me.forge.Config.IsPrivate(repo.GetNamespace()) { return "/home/jcarr/incoming-private" } if argv.Force { return "/home/jcarr/incoming" } if repo.GetLastTag() != repo.GetMasterVersion() { return "/home/jcarr/incoming-devel" } if repo.GetCurrentBranchVersion() != repo.GetMasterVersion() { return "/home/jcarr/incoming-devel" } if repo.CheckDirty() { return "/home/jcarr/incoming-dirty-junk" } return "/home/jcarr/incoming" }