Compare commits

..

29 Commits

Author SHA1 Message Date
Jeff Carr 6d670cc64f fix for root file permissions 2025-09-21 23:22:09 -05:00
Jeff Carr 475e72018e fixes for wierd package names 2025-09-11 19:08:15 -05:00
Jeff Carr aedb5a3bef make sure arch is set 2025-09-11 18:53:40 -05:00
Jeff Carr cc75c2dd6c fixes for packages without control files 2025-09-11 18:39:59 -05:00
Jeff Carr 95d1f6fc7c more fixes. almost works again 2025-09-11 17:41:59 -05:00
Jeff Carr d011972b70 change around the gui 2025-09-11 16:42:02 -05:00
Jeff Carr 887811f788 try to refector to work against git.Repo 2025-09-11 16:07:19 -05:00
Jeff Carr fecb3ed9c1 work on update 2025-09-11 15:42:03 -05:00
Jeff Carr 7b84ddd64b add Namespace 2025-09-11 15:33:17 -05:00
Jeff Carr 6acc0b4f8b mv 2025-09-11 15:26:29 -05:00
Jeff Carr ec661807da switch over to using gitpb.Repo directly 2025-09-11 15:23:17 -05:00
Jeff Carr 127f36ca1f refactor to store info 2025-09-11 15:03:44 -05:00
Jeff Carr b05b706d8b raw gitpb Repo() scan 2025-09-11 14:21:09 -05:00
Jeff Carr fd199a4404 common forge.Init() 2025-09-11 04:42:36 -05:00
Jeff Carr 572ef15ab1 new forge init() 2025-09-11 03:27:56 -05:00
Jeff Carr 2677e5c0cd fixes. needs a refactor 2025-09-09 09:25:10 -05:00
Jeff Carr 8edefa6dad fix something 2025-09-09 08:40:49 -05:00
Jeff Carr 18422baceb new GUI codebase 2025-09-09 06:02:35 -05:00
Jeff Carr 1418fcb0d1 new GUI interface 2025-09-09 05:54:51 -05:00
Jeff Carr af5205fb36 add bash support 2025-09-08 16:18:30 -05:00
Jeff Carr 6f8349ce5b new func name 2025-09-04 10:32:54 -05:00
Jeff Carr b405cbc7e0 fixes to new ENV common code 2025-09-03 20:50:12 -05:00
Jeff Carr 1970e40d0b wrong paths 2025-02-22 07:35:37 -06:00
Jeff Carr cf2f07f273 new autogenpb 2025-02-20 09:39:16 -06:00
Jeff Carr 8e315cc238 forge this! 2025-02-14 20:41:57 -06:00
Jeff Carr 31eac3d915 try to fix 'release' builds 2025-02-14 17:11:48 -06:00
Jeff Carr da425cfb0f more standard timestamp 2025-01-19 16:07:31 -06:00
Jeff Carr d51f5b385a attempt to fix when not using forge 2025-01-18 07:29:44 -06:00
Jeff Carr 1e5fac4cd8 minor 2025-01-08 10:10:41 -06:00
14 changed files with 765 additions and 698 deletions

View File

@ -3,24 +3,28 @@
VERSION = $(shell git describe --tags)
DATE = $(shell date +%Y.%m.%d)
run: build
./go-deb --repo go.wit.com/apps/autotypist
run: clean goimports vet install
go-deb --gui andlabs gui
junk:
#go-deb --release go.wit.com/apps/go-mod-clean --dir /tmp/
#go-deb go.wit.com/apps/autotypist
#ls -lth /tmp/*deb
vet:
@GO111MODULE=off go vet
@echo this go library package builds okay
auto-build: build
./go-deb --auto --repo go.wit.com/apps/autotypist
./go-deb --repo go.wit.com/apps/autotypist
build:
build: goimports vet
-rm resources/*.so
touch resources/blank.so
-cp -a ~/go/src/go.wit.com/toolkits/*/*.so resources/ # embed the toolkit plugins
GO111MODULE="off" go build -v \
-ldflags "-X main.VERSION=${VERSION} -X main.DATE=${DATE} -X gui.GUIVERSION=${VERSION}"
install:
install: goimports
GO111MODULE="off" go install -v \
-ldflags "-X main.VERSION=${VERSION} -X main.DATE=${DATE} -X gui.GUIVERSION=${VERSION}"
@ -45,21 +49,25 @@ nocui: reset build
./go-deb --gui nocui
clean:
rm -f go.*
rm -f go-deb
rm -f resources/*.so
touch resources/blank.so
build-go-gui-toolkits: build
./go-deb --release --auto --repo go.wit.com/apps/go-gui-toolkits
./go-deb --release --repo go.wit.com/apps/go-gui-toolkits
build-test-failure: build
./go-deb --release --auto --repo go.wit.com/apps/junk
./go-deb --release --repo go.wit.com/apps/junk
build-test-keep-files: build
./go-deb --auto --keep-files --repo go.wit.com/apps/go-deb
./go-deb --keep-files --repo go.wit.com/apps/go-deb
build-release:
go-deb --release --auto --repo go.wit.com/apps/go-deb
go-deb --release --repo go.wit.com/apps/go-deb
debian: build
./go-deb --auto --keep-files --repo go.wit.com/apps/go-deb
./go-deb --keep-files --repo go.wit.com/apps/go-deb
test2:
go-deb go.wit.com/apps/utils/go-gui-toolkits --dir /tmp

View File

@ -1,85 +0,0 @@
package main
import (
"strings"
"time"
"go.wit.com/lib/gadgets"
"go.wit.com/log"
)
func RemoveFirstElement(slice []string) (string, []string) {
if len(slice) == 0 {
return "", slice // Return the original slice if it's empty
}
return slice[0], slice[1:] // Return the slice without the first element
}
// homeDir, _ := os.UserHomeDir()
func (c *controlBox) addRepo(path string) {
path = strings.Trim(path, "/") // trim any extranous '/' chars put in the config file by the user
if path == "" {
log.Warn("addRepo() got empty path", path)
return
}
// if repostatus.VerifyLocalGoRepo(path) {
// log.Verbose("path actually exists", path)
// } else {
// log.Warn("repostatus.VerifyLocalGoRepo() failed for for", path)
// return
// }
c.pathL = gadgets.NewOneLiner(c.grid, "path")
c.pathL.SetText(path)
c.grid.NextRow()
c.lastTag = gadgets.NewOneLiner(c.grid, "lastTag")
c.grid.NextRow()
c.dirtyL = gadgets.NewOneLiner(c.grid, "dirty")
c.grid.NextRow()
c.currentL = gadgets.NewOneLiner(c.grid, "current")
c.grid.NextRow()
c.buildDate = gadgets.NewOneLiner(c.grid, "Build Date")
c.grid.NextRow()
stamp := time.Now().UTC().Format("2006/01/02 15:04:05 UTC")
c.buildDate.SetText(stamp)
c.tagDate = gadgets.NewBasicEntry(c.grid, "git tag Date")
c.grid.NextRow()
cbname := repo.GetCurrentBranchName()
cbversion := repo.GetCurrentBranchVersion()
debversion := repo.DebianCurrentVersion()
if repo.CheckDirty() {
c.dirtyL.SetText("true")
} else {
c.dirtyL.SetText("false")
}
if c.GoPath.String() == "" {
c.GoPath.SetText(repo.GetGoPath())
}
lasttag := repo.GetLastTagVersion()
if argv.Release {
debversion = repo.DebianReleaseVersion()
c.dirtyL.SetText("false")
}
c.Version.SetText(debversion)
c.lastTag.SetText(lasttag)
c.currentL.SetText(cbname + " " + cbversion)
tagDate := c.getDateStamp(lasttag)
c.tagDate.SetText(tagDate)
return
}

73
argv.go
View File

@ -1,39 +1,62 @@
package main
import (
"fmt"
"os"
)
/*
this parses the command line arguements
this enables command line options from other packages like 'gui' and 'log'
*/
import (
"go.wit.com/dev/alexflint/arg"
"go.wit.com/lib/debugger"
"go.wit.com/log"
)
var argv args
type args struct {
Auto bool `arg:"--auto" help:"automatically attempt to make the .deb"`
Ldflags []string `arg:"--ldflags" help:"flags to pass to go build"`
Repo string `arg:"--repo" help:"go get path to the repo"`
OutDir string `arg:"--dir" help:"write .deb file into this directory"`
Release bool `arg:"--release" help:"build a release from the last git tag"`
KeepFiles bool `arg:"--keep-files" help:"keep the build files/"`
Force bool `arg:"--force" default:"false" help:"force overwrite an existing .deb file"`
}
func init() {
arg.MustParse(&argv)
if debugger.ArgDebug() {
log.Info("cmd line --debugger == true")
} else {
log.Info("cmd line --debugger == false")
}
Commit *EmptyCmd `arg:"subcommand:commit" help:"'git commit' but errors out if on wrong branch"`
Show *EmptyCmd `arg:"subcommand:show" help:"show what would be done"`
Gui *EmptyCmd `arg:"subcommand:gui" help:"open the gui"`
Dump *EmptyCmd `arg:"subcommand:dump" help:"dump out the future control file"`
Ldflags []string `arg:"--ldflags" help:"flags to pass to go build"`
OutDir string `arg:"--dir" help:"write .deb file into this directory"`
Release bool `arg:"--release" help:"build a release from the last git tag"`
KeepFiles bool `arg:"--keep-files" help:"keep the build files/"`
Force bool `arg:"--force" default:"false" help:"force overwrite an existing .deb file"`
Verbose bool `arg:"--verbose" help:"show more things"`
}
func (args) Version() string {
return "go-clone " + VERSION + " Built on " + DATE
}
type EmptyCmd struct {
}
func (a args) Description() string {
return `
Example usage:
guireleaser go.wit.com/apps/go-clone --increment --release --dry-run --reason "blerg"
This will pull down the go sources and
the repositories in the go.sum file using git clone`
}
/*
handles shell autocomplete
*/
func (a args) DoAutoComplete(argv []string) {
switch argv[0] {
case "arch":
fmt.Println("riscv64")
case "build":
fmt.Println("user devel release")
case "--gui":
fmt.Println("nocui andlabs")
default:
if argv[0] == ARGNAME {
// list the subcommands here
fmt.Println("arch build gui show --gui")
}
}
os.Exit(0)
}

244
build.go Normal file
View File

@ -0,0 +1,244 @@
package main
import (
"errors"
"fmt"
"os"
"path/filepath"
"time"
"go.wit.com/lib/gui/shell"
"go.wit.com/lib/protobuf/gitpb"
"go.wit.com/log"
)
func buildPackage(repo *gitpb.Repo) (bool, error) {
// TODO: if dirty, set GO111MODULE
// also, if last tag != version
/*
go install -ldflags " \
-X main.GITCOMMIT=${GITCOMMIT} \
-X main.GOVERSION='${GOVERSION}' \
-X main.BUILDTIME='${BUILDTIME}' \
-X main.VERSION=${VERSION}"
*/
// ldflags := "main.GOTAG=" + repo.LastTag()
filename := repo.Control["Package"] // c.Package.String()
if filename == "" {
return false, errors.New("filename is blank")
}
arch := repo.Control["Architecture"] // c.Architecture.String()
if arch == "" {
arch = "amd64" // todo: detect what you are building on
}
version := repo.Control["Version"]
log.Info("version is:", version)
debname := filename + "_" + version + "_" + arch + ".deb"
var fulldebname string
if argv.OutDir == "" {
fulldebname = debname
} else {
fulldebname = filepath.Join(argv.OutDir, debname)
}
if shell.Exists(fulldebname) {
log.Info("debian package already built: " + fulldebname)
return true, errors.New("debian package already built: " + fulldebname)
}
var fullfilename string
_, fullfilename = filepath.Split(filename)
if fullfilename == "" {
log.Info("fullfilename =", fullfilename)
badExit(log.Errorf("binary name was blank"))
}
if fullfilename == "." {
log.Info("fullfilename =", fullfilename)
badExit(log.Errorf("binary name was ."))
}
if shell.Exists(fullfilename) {
repo.RunVerbose([]string{"rm", "-f", fullfilename})
}
if shell.Exists(fullfilename) {
// something wrong
return false, errors.New("binary existed before build")
}
if argv.Release {
os.Unsetenv("GO111MODULE")
cmd := []string{"go"}
cmd = append(cmd, "install")
if argv.Verbose {
cmd = append(cmd, "-v")
cmd = append(cmd, "-x")
}
/*
cmd = append(cmd, "some path"+"@v"+version)
if err := shell.PathExecVerbose("", cmd); err != nil {
badExit(err)
return false, fmt.Errorf("go build err %v", err)
}
*/
cmd = []string{"go"}
cmd = append(cmd, "build")
if argv.Verbose {
cmd = append(cmd, "-v")
cmd = append(cmd, "-x")
}
cmd = append(cmd, "this should be the path")
if err := shell.PathExecVerbose("", cmd); err != nil {
badExit(err)
return false, fmt.Errorf("go build err %v", err)
}
log.Warn("build worked")
} else {
// set the GO111 build var to true. pass the versions to the compiler manually
os.Setenv("GO111MODULE", "off")
cmd := []string{"go", "build"}
// 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 argv.Ldflags {
cmd = append(cmd, "-ldflags", "-X "+flag)
}
err := repo.RunVerbose(cmd)
if err != nil {
return false, fmt.Errorf("go build err %v", err)
}
log.Warn("go build worked")
}
filebase := filepath.Base(repo.Control["pathL"]) // c.pathL.String())
if fullfilename != filebase {
// this exception is for when you want to override a package name
// sometimes that's the best option. This way you can keep your
// name, but the .deb package name can be different so you can
// still apt-get it. For an example, look at the gozookeeper package
fullfilename = filebase
}
if !shell.Exists(fullfilename) {
log.Warn("build failed. filename does not exist", fullfilename)
return false, errors.New("missing " + fullfilename)
}
if shell.Exists("files") {
repo.RunVerbose([]string{"rm", "-rf", "files"})
// log.Info("running sync")
repo.RunVerbose([]string{"sync"})
if shell.Exists("files") {
log.Warn("rm failed for some reason")
return false, errors.New("rm files/")
}
}
repo.RunVerbose([]string{"sync"}) // for some reason the next check fails sometimes?
if shell.Exists("files") {
// probably the 'shell' package id being stupid and not waiting for the process to actually exit
log.Warn("rm failed. files/ still exists. is golang doing these in parallel?")
return false, errors.New("rm files/")
}
if err := os.MkdirAll("files/DEBIAN", os.ModePerm); err != nil {
return false, errors.New("mkdir files/DEBIAN")
}
if err := os.MkdirAll("files/usr/bin", os.ModePerm); err != nil {
log.Warn("mkdir failed")
return false, errors.New("mkdir files/usr/bin")
}
if os.Getenv("GO_DEB_CUSTOM") == "true" {
// skip cp & strip on custom 'control' files
// probably deprecate this
log.Info("REPO GO_DEB_CUSTOM=true means binary is not copied")
} else {
_, fname := filepath.Split(repo.GetFullPath())
cmd := []string{"cp", fname, "files/usr/bin"}
log.Info("REPO FILENAME cp", cmd)
if err := repo.RunVerbose(cmd); err != nil {
log.Warn("cp failed")
return false, err
}
cmd = []string{"strip", "files/usr/bin/" + fname}
if err := repo.RunVerbose(cmd); err != nil {
log.Warn("strip failed")
return false, err
}
}
// put the README in there (if missing, generate it?)
var readme string = ""
if shell.Exists("README.md") {
readme = "README.md"
}
if shell.Exists("README") {
readme = "README"
}
if readme != "" {
path := filepath.Join("files/usr/lib/" + filename)
if err := os.MkdirAll(path, os.ModePerm); err != nil {
return false, errors.New("no files/usr/lib")
}
if err := repo.RunVerbose([]string{"cp", readme, path}); err != nil {
return false, err
}
}
if !writeDebianControlFile(repo) {
return false, errors.New("write control file")
}
if shell.Exists("postinst") {
repo.RunVerbose([]string{"cp", "postinst", "files/DEBIAN/"})
}
// experiment for the toolkit package
// if the git repo has a "./build" script run it before packaging
// this way the user can put custom files in the .deb package
if shell.Exists("build") {
log.Info(repo.FullPath, "FOUND ./build HERE")
repo.RunVerbose([]string{"./build"})
} else {
log.Info(repo.FullPath, "NOT FOUND ./build HERE")
}
cmd := []string{"dpkg-deb", "--root-owner-group", "--build", "files", fulldebname}
result := repo.RunVerbose(cmd)
if shell.Exists(fulldebname) {
} else {
log.Warn("CMD FAILED", cmd, result)
log.Warn("build failed: full name was not created:", fulldebname)
return false, errors.New("dpkg-deb --build failed")
}
repo.RunVerbose([]string{"dpkg-deb", "-I", fulldebname})
repo.RunVerbose([]string{"dpkg-deb", "-c", fulldebname})
// cleanup files
if shell.Exists("files") {
if argv.KeepFiles {
log.Info("keeping the build files/")
} else {
repo.RunVerbose([]string{"rm", "-rf", "files"})
// log.Info("running sync")
repo.RunVerbose([]string{"sync"})
if shell.Exists("files") {
log.Warn("rm -rf files/ failed. Run() returned false")
return false, errors.New("rm files/")
}
}
}
return true, nil
}

View File

@ -1,314 +0,0 @@
package main
import (
"errors"
"fmt"
"os"
"path/filepath"
"strconv"
"strings"
"time"
"go.wit.com/lib/gui/shell"
"go.wit.com/log"
)
func (c *controlBox) buildPackage() (bool, error) {
// TODO: if dirty, set GO111MODULE
// also, if last tag != version
/*
go install -ldflags " \
-X main.GITCOMMIT=${GITCOMMIT} \
-X main.GOVERSION='${GOVERSION}' \
-X main.BUILDTIME='${BUILDTIME}' \
-X main.VERSION=${VERSION}"
*/
// ldflags := "main.GOTAG=" + repo.LastTag()
filename := c.Package.String()
if filename == "" {
return false, errors.New("filename is blank")
}
homeDir, err := os.UserHomeDir()
if err != nil {
return false, err
}
arch := c.Architecture.String()
version := c.Version.String()
log.Info("version is:", version)
debname := filename + "_" + version + "_" + arch + ".deb"
var fulldebname string
if argv.OutDir == "" {
fulldebname = debname
} else {
fulldebname = filepath.Join(argv.OutDir, debname)
}
if shell.Exists(fulldebname) {
log.Info("debian package already built: " + fulldebname)
if argv.Auto {
return true, errors.New("debian package already built: " + fulldebname)
} else {
return false, errors.New("debian package already built: " + fulldebname)
}
}
var fullfilename string
if argv.Release {
fullfilename = filepath.Join(homeDir, "go/bin", filename)
} else {
fullfilename = filename
}
shell.Run([]string{"rm", "-f", fullfilename})
if shell.Exists(fullfilename) {
// something wrong
return false, errors.New("binary existed before build")
}
if argv.Release {
os.Unsetenv("GO111MODULE")
path := c.pathL.String() + "@latest"
cmd := []string{"go", "install", "-v", "-x", path}
if r := shell.Run(cmd); r.Error == nil {
log.Warn("go install worked")
} else {
return false, errors.New("go install")
}
} else {
// set the GO111 build var to true. pass the versions to the compiler manually
os.Setenv("GO111MODULE", "off")
cmd := []string{"go", "build"}
// 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 argv.Ldflags {
cmd = append(cmd, "-ldflags", "-X "+flag)
}
r := shell.Run(cmd)
if r.Exit != 0 {
return false, errors.New("go build")
}
if r.Error != nil {
return false, errors.New("go build")
}
log.Warn("go build worked")
}
filebase := filepath.Base(c.pathL.String())
if fullfilename != filebase {
// this exception is for when you want to override a package name
// sometimes that's the best option. This way you can keep your
// name, but the .deb package name can be different so you can
// still apt-get it. For an example, look at the gozookeeper package
fullfilename = filebase
}
if !shell.Exists(fullfilename) {
log.Warn("build failed. filename does not exist", fullfilename)
return false, errors.New("missing " + fullfilename)
}
if shell.Exists("files") {
shell.Run([]string{"rm", "-rf", "files"})
log.Info("running sync")
shell.Run([]string{"sync"})
if shell.Exists("files") {
log.Warn("rm failed for some reason")
return false, errors.New("rm files/")
}
}
shell.Run([]string{"sync"}) // for some reason the next check fails sometimes?
if shell.Exists("files") {
// probably the 'shell' package id being stupid and not waiting for the process to actually exit
log.Warn("rm failed. files/ still exists. is golang doing these in parallel?")
return false, errors.New("rm files/")
}
if err := os.MkdirAll("files/DEBIAN", os.ModePerm); err != nil {
return false, errors.New("mkdir files/DEBIAN")
}
if err := os.MkdirAll("files/usr/bin", os.ModePerm); err != nil {
log.Warn("mkdir failed")
return false, errors.New("mkdir files/usr/bin")
}
if os.Getenv("GO_DEB_CUSTOM") == "true" {
// skip cp & strip on custom 'control' files
} else {
if r := shell.Run([]string{"cp", fullfilename, "files/usr/bin"}); r.Error != nil {
log.Warn("cp failed")
return false, r.Error
}
if r := shell.Run([]string{"strip", "files/usr/bin/" + filename}); r.Error != nil {
log.Warn("strip failed")
return false, r.Error
}
}
// put the README in there (if missing, generate it?)
var readme string = ""
if shell.Exists("README.md") {
readme = "README.md"
}
if shell.Exists("README") {
readme = "README"
}
if readme != "" {
path := filepath.Join("files/usr/lib/" + filename)
if err := os.MkdirAll(path, os.ModePerm); err != nil {
return false, errors.New("no files/usr/lib")
}
if r := shell.Run([]string{"cp", readme, path}); r.Error != nil {
return false, r.Error
}
}
if !c.writeDebianControlFile() {
return false, errors.New("write control file")
}
if shell.Exists("postinst") {
shell.Run([]string{"cp", "postinst", "files/DEBIAN/"})
}
// experiment for the toolkit package
// if the git repo has a "./build" script run it before packaging
// this way the user can put custom files in the .deb package
if shell.Exists("build") {
shell.Run([]string{"./build"})
}
shell.Run([]string{"dpkg-deb", "--build", "files", fulldebname})
if shell.Exists(fulldebname) {
} else {
log.Warn("build failed")
return false, errors.New("dpkg-deb --build failed")
}
shell.Run([]string{"dpkg-deb", "-I", fulldebname})
shell.Run([]string{"dpkg-deb", "-c", fulldebname})
// cleanup files
if shell.Exists("files") {
if argv.KeepFiles {
log.Info("keeping the build files/")
} else {
shell.Run([]string{"rm", "-rf", "files"})
log.Info("running sync")
shell.Run([]string{"sync"})
if shell.Exists("files") {
log.Warn("rm -rf files/ failed. Run() returned false")
return false, errors.New("rm files/")
}
}
}
return true, nil
}
func (c *controlBox) writeDebianControlFile() bool {
cf, err := os.OpenFile("files/DEBIAN/control", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
log.Info("open control file failed", err)
return false
}
fmt.Fprintln(cf, "Package:", c.Package.String())
fmt.Fprintln(cf, "Source:", c.Source.String())
fmt.Fprintln(cf, "Version:", c.Version.String())
fmt.Fprintln(cf, "Architecture:", c.Architecture.String())
if c.Depends.String() != "" {
fmt.Fprintln(cf, "Depends:", c.Depends.String())
}
if c.BuildDepends.String() != "" {
fmt.Fprintln(cf, "Build-Depends:", c.BuildDepends.String())
}
stamp := time.Now().UTC().Format("2006/01/02 15:04:05 UTC")
// update to now now despite what the GUI is showing
fmt.Fprintln(cf, "Package-Build-Date:", stamp)
if c.tagDate.String() == "" {
// todo: allow this to be set somehow
} else {
fmt.Fprintln(cf, "Git-Tag-Date:", c.tagDate.String())
}
fmt.Fprintln(cf, "Maintainer:", c.Maintainer.String())
fmt.Fprintln(cf, "Packager:", c.Packager.String())
if c.GoPath.String() != "" {
fmt.Fprintln(cf, "GoPath:", c.URL.String())
}
if c.URL.String() != "" {
fmt.Fprintln(cf, "URL:", c.URL.String())
}
if c.Conflicts.String() != "" {
fmt.Fprintln(cf, "Conflicts:", c.Conflicts.String())
}
desc := c.Description.String()
parts := strings.Split(desc, "\n")
fmt.Fprintln(cf, "Description:", strings.Join(parts, "\n "))
return true
}
// try to guess or figure out the config file values
// if there is not a control file
func (c *controlBox) computeControlValues() bool {
if c.Package.String() == "" {
// get the package name from the repo name
path := c.pathL.String()
parts := strings.Split(path, "/")
name := parts[len(parts)-1]
c.Package.SetText(name)
}
if c.Source.String() == "" {
c.Source.SetText(c.Package.String())
}
if c.BuildDepends.String() == "" {
c.BuildDepends.SetText("golang")
}
if c.Recommends.String() == "" {
c.Recommends.SetText("go-gui-toolkits")
}
// TODO: get this from the git log
if c.Maintainer.String() == "" {
c.Maintainer.SetText("made by go-deb")
}
// TODO: get this from gitea (or gitlab or github, etc)
// or from the README.md ?
if c.Description.String() == "" {
path := c.pathL.String()
c.Description.SetText("GO binary of " + path)
}
return true
}
// stamp := time.Now().UTC().Format("2006/01/02 15:04:05 UTC")
func (c *controlBox) getDateStamp(tag string) string {
r := repo.Run([]string{"git", "log", "-1", "--format=%at", tag})
out := strings.Join(r.Stdout, "\n")
out = strings.TrimSpace(out)
// Convert the string to an integer
gitTagTimestampInt, err := strconv.ParseInt(out, 10, 64)
if err != nil {
fmt.Println("Error converting timestamp:", err)
return "git tag " + tag + " unknown"
}
// Parse the Unix timestamp into a time.Time object
gitTagDate := time.Unix(gitTagTimestampInt, 0)
return gitTagDate.UTC().Format("2006/01/02 15:04:05 UTC")
}

145
control.read.go Normal file
View File

@ -0,0 +1,145 @@
package main
import (
"bufio"
"os"
"path/filepath"
"strings"
"unicode"
"go.wit.com/lib/protobuf/gitpb"
"go.wit.com/log"
)
func trimNonNumericPrefix(s string) string {
// Find the index of the first character that IS a digit.
firstDigitIndex := strings.IndexFunc(s, unicode.IsDigit)
// If no digit is found, IndexFunc returns -1.
// In this case, the result should be an empty string.
if firstDigitIndex == -1 {
return ""
}
// Return the substring starting from the first digit.
return s[firstDigitIndex:]
}
// readGitConfig reads and parses the control file
func readControlFile(repo *gitpb.Repo) error {
pairs := make(map[string]string)
var key string
file, err := os.Open("control")
if err != nil {
log.Warn("readControlFile() could not find the file")
// return errors.New("'control': file not found")
// if this happens, make up a fake control file
pairs["Architecture"] = "amd64" // TODO: figure this out
pairs["Recommends"] = ""
pairs["Source"] = "notsure"
if me.repo == nil {
pairs["Description"] = "put something here"
} else {
pairs["Description"] = me.repo.GetGoPath()
}
if repo.Control == nil {
repo.Control = make(map[string]string)
}
for key, value := range pairs {
repo.Control[key] = value
}
if os.Getenv("GIT_AUTHOR_NAME") != "" {
author := log.Sprintf("%s <%s>", os.Getenv("GIT_AUTHOR_NAME"), os.Getenv("GIT_AUTHOR_EMAIL"))
repo.Control["Packager"] = author
}
_, fname := filepath.Split(repo.GetFullPath())
repo.Control["Package"] = fname
repo.Control["Version"] = trimNonNumericPrefix(repo.GetCurrentVersion())
repo.Control["URL"] = repo.URL
return nil
}
defer file.Close()
pairs["Version"] = trimNonNumericPrefix(repo.GetCurrentVersion())
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
// Skip empty lines and comments
if line == "" || strings.HasPrefix(line, "#") || strings.HasPrefix(line, ";") {
continue
}
// if line starts with a space, it's part of the last key
if strings.HasPrefix(line, " ") {
pairs[key] = pairs[key] + "\n" + strings.TrimSpace(line)
continue
}
partsNew := strings.SplitN(line, ":", 2)
if len(partsNew) < 2 {
log.Warn("error on line:", line)
continue
}
key = strings.TrimSpace(partsNew[0])
value := strings.TrimSpace(partsNew[1])
pairs[key] = value
}
if repo.Control == nil {
repo.Control = make(map[string]string)
}
for key, value := range pairs {
repo.Control[key] = value
/*
switch key {
case "Source":
c.Source.SetText(value)
case "Build-Depends":
c.BuildDepends.SetText(value)
case "Description":
c.Description.SetText(value)
case "Maintainer":
c.Maintainer.SetText(value)
case "Packager":
c.Packager.SetText(value)
case "GoPath":
c.GoPath.SetText(value)
case "URL":
c.URL.SetText(value)
case "Depends":
c.Depends.SetText(value)
case "Recommends":
c.Recommends.SetText(value)
case "Conflicts":
c.Conflicts.SetText(value)
case "Version":
c.Version.SetText(value)
case "Package":
c.Package.SetText(value)
// if c.Package.String() != value {
// log.Warn("not sure what to do with Package", c.Package.String(), value)
// }
case "Architecture":
// todo: add logic to find OS arch
if c.Architecture.String() != value {
log.Warn("attempting to set arch to", value)
c.Architecture.SetText(value)
}
default:
log.Warn("the 'control' file has a value I don't know about")
log.Warn("error unknown key", key, "value:", value)
}
*/
}
pairs["Architecture"] = "amd64" // TODO: figure this out
if err := scanner.Err(); err != nil {
return err
}
return nil
}

106
control.write.go Normal file
View File

@ -0,0 +1,106 @@
package main
import (
"fmt"
"os"
"strconv"
"strings"
"time"
"github.com/go-cmd/cmd"
"go.wit.com/lib/protobuf/gitpb"
"go.wit.com/log"
)
func writeDebianControlFile(repo *gitpb.Repo) bool {
filename := "files/DEBIAN/control"
cf, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
log.Info("open control file failed", err)
return false
}
fmt.Fprintln(cf, "Package:", repo.Control["Package"]) // c.Package.String())
fmt.Fprintln(cf, "Source:", repo.Control["Source"]) // c.Source.String())
fmt.Fprintln(cf, "Version:", repo.Control["Version"])
if repo.Control["Architecture"] == "" {
repo.Control["Architecture"] = "amd64"
}
fmt.Fprintln(cf, "Architecture:", repo.Control["Architecture"]) // c.Architecture.String())
writeControlVar(cf, repo, "Depends")
writeControlVar(cf, repo, "Build-Depends")
writeControlVar(cf, repo, "Maintainer")
writeControlVar(cf, repo, "Packager")
writeControlVar(cf, repo, "GoPath")
writeControlVar(cf, repo, "URL")
writeControlVar(cf, repo, "Conflicts")
stamp := time.Now().UTC().Format("2006/01/02 15:04:05 UTC")
// update to now now despite what the GUI is showing
fmt.Fprintln(cf, "Package-Build-Date:", stamp)
fmt.Fprintln(cf, "Git-Tag-Date:", "todo: get from repo")
desc, _ := repo.Control["Description"] // c.Description.String()
parts := strings.Split(desc, "\n")
fmt.Fprintln(cf, "Description:", strings.Join(parts, "\n "))
log.Info("file written as:", filename)
return true
}
func writeControlVar(f *os.File, repo *gitpb.Repo, varname string) {
val, _ := repo.Control[varname]
if val == "" {
return
}
fmt.Fprintln(f, varname+":", val)
}
// try to guess or figure out the config file values
// if there is not a control file
func computeControlValues(repo *gitpb.Repo) bool {
if repo.Control["Package"] == "" {
// get the package name from the repo name
path := repo.Control["pathL"] // c.pathL.String()
parts := strings.Split(path, "/")
name := parts[len(parts)-1]
repo.Control["Package"] = name
}
if repo.Control["Source"] == "" {
repo.Control["Source"] = repo.Control["Package"]
}
if repo.Control["Build-Depends"] == "" {
repo.Control["Build-Depends"] = repo.Control["golang"]
}
if repo.Control["Recommends"] == "" {
repo.Control["Recommends"] = repo.Control["go-gui-toolkits"]
}
if repo.Control["Maintainer"] == "" {
repo.Control["Maintainer"] = "todo: get from ENV"
}
if repo.Control["Description"] == "" {
repo.Control["Description"] = "todo: put URL here"
}
return true
}
// stamp := time.Now().UTC().Format("2006/01/02 15:04:05 UTC")
func getDateStamp(tag string) string {
var r cmd.Status
r = me.repo.Run([]string{"git", "log", "-1", "--format=%at", tag})
out := strings.Join(r.Stdout, "\n")
out = strings.TrimSpace(out)
// Convert the string to an integer
gitTagTimestampInt, err := strconv.ParseInt(out, 10, 64)
if err != nil {
fmt.Println("Error converting timestamp:", err)
return "git tag " + tag + " unknown"
}
// Parse the Unix timestamp into a time.Time object
gitTagDate := time.Unix(gitTagTimestampInt, 0)
return gitTagDate.UTC().Format("2006-01-02_15:04:05_UTC") // close to RFC3339
}

View File

@ -1,46 +1,72 @@
// Copyright 2017-2025 WIT.COM Inc. All rights reserved.
// Use of this source code is governed by the GPL 3.0
package main
import (
"os"
"go.wit.com/gui"
"go.wit.com/lib/gadgets"
"go.wit.com/lib/gui/shell"
"go.wit.com/log"
)
type controlBox struct {
group *gui.Node // the group
grid *gui.Node // the grid
// An app to submit patches for the 30 GO GUI repos
Package *gadgets.OneLiner
Source *gadgets.OneLiner
Version *gadgets.OneLiner
Maintainer *gadgets.OneLiner
Packager *gadgets.BasicEntry
GoPath *gadgets.BasicEntry
URL *gadgets.BasicEntry
Architecture *gadgets.BasicDropdown
InstallPath *gadgets.BasicCombobox
Depends *gadgets.OneLiner
BuildDepends *gadgets.OneLiner
Recommends *gadgets.OneLiner
Conflicts *gadgets.BasicEntry
Test gui.Widget
Description *gadgets.OneLiner
func doGui() {
log.Warn("init basicWindow state")
win := gadgets.NewGenericWindow("Create .deb files for GO applications", "things")
win.Custom = func() {
log.Info("got to close")
os.Exit(0)
}
// repostatus things
pathL *gadgets.OneLiner
lastTag *gadgets.OneLiner
dirtyL *gadgets.OneLiner
currentL *gadgets.OneLiner
buildDate *gadgets.OneLiner
tagDate *gadgets.BasicEntry
// status *repostatus.RepoStatus
var cbox *controlBox
vbox := win.Middle.Box().Horizontal()
group1 := vbox.NewGroup("controls").Horizontal() // Vertical()
group1.NewButton("go build", func() {
shell.Run([]string{"go", "build", "-v", "-x"})
})
group1.NewButton("read control file", func() {
readControlFile(me.repo)
})
group1.NewButton("write control file", func() {
writeDebianControlFile(me.repo)
})
group1.NewButton("dump repo.Control", func() {
// log.Info("CONTROL:", me.repo.Control)
for v := range me.repo.Control {
log.Infof("CONTROL: %s: %s\n", v, me.repo.Control[v])
}
})
group1.NewButton("Make .deb", func() {
win.Disable()
if ok, err := buildPackage(me.repo); ok {
log.Info("build worked")
os.Exit(0)
} else {
log.Warn("build failed with err:", err)
}
win.Enable()
})
grid := win.Middle.RawGrid()
cbox = newControl(grid)
updateControl(cbox)
}
// This initializes the control box
func newControl(parent *gui.Node) *controlBox {
var c *controlBox
c = new(controlBox)
c.group = parent.NewGroup("choices")
c.grid = c.group.NewGrid("gridiron", 8, 1)
func newControl(grid *gui.Node) *controlBox {
c := new(controlBox)
c.grid = grid
c.Package = gadgets.NewOneLiner(c.grid, "Package")
c.grid.NextRow()
@ -80,6 +106,9 @@ func newControl(parent *gui.Node) *controlBox {
c.GoPath = gadgets.NewBasicEntry(c.grid, "GoPath")
c.grid.NextRow()
c.Namespace = gadgets.NewBasicEntry(c.grid, "Namespace")
c.grid.NextRow()
c.URL = gadgets.NewBasicEntry(c.grid, "URL")
c.grid.NextRow()
@ -96,6 +125,7 @@ func newControl(parent *gui.Node) *controlBox {
c.grid.NextRow()
c.Description = gadgets.NewOneLiner(c.grid, "Description")
c.Description.SetText("na")
c.grid.NextRow()
return c

20
exit.go Normal file
View File

@ -0,0 +1,20 @@
package main
import (
"os"
"go.wit.com/log"
)
func okExit(thing string) {
if thing != "" {
log.Info(thing, "ok")
}
// log.Info("Finished go-clean on", check.GetGoPath(), "ok")
os.Exit(0)
}
func badExit(err error) {
log.Info("go-deb failed: ", err)
os.Exit(-1)
}

135
main.go
View File

@ -4,13 +4,11 @@ import (
"embed"
"os"
"path/filepath"
"time"
"go.wit.com/gui"
"go.wit.com/lib/debugger"
"go.wit.com/lib/gadgets"
"go.wit.com/lib/gui/shell"
"go.wit.com/dev/alexflint/arg"
"go.wit.com/lib/gui/prep"
"go.wit.com/lib/protobuf/gitpb"
"go.wit.com/lib/protobuf/forgepb"
"go.wit.com/log"
)
@ -18,109 +16,84 @@ import (
var VERSION string
var DATE string
// This is the beginning of the binary tree of GUI widgets
var myGui *gui.Node
// this scans in the repos
var forge *forgepb.Forge
var repo *gitpb.Repo
var cBox *controlBox
// this is a basic window. the user can open and close it
var basicWindow *gadgets.BasicWindow
//go:embed resources/*
var resources embed.FS
var ARGNAME string = "go-deb"
var argv args
func main() {
if argv.Repo == "" {
log.Info("You need to tell me what repo you want to work on")
println("")
println("go-deb --repo go.wit.com/apps/helloworld")
os.Exit(0)
}
forge = forgepb.Init()
os.Setenv("REPO_WORK_PATH", forge.GetGoSrc())
me = new(mainType)
prep.Bash(ARGNAME, argv.DoAutoComplete) // this line should be: prep.Bash(argv)
me.myGui = prep.Gui() // prepares the GUI package for go-args
me.pp = arg.MustParse(&argv)
repo = forge.FindByGoPath(argv.Repo)
if repo == nil {
log.Info("repo not found. you need to clone", argv.Repo)
os.Exit(-1)
wd, err := os.Getwd()
if err != nil {
badExit(err)
}
log.Info("found repo", argv.Repo)
me.repo, err = gitpb.NewRepo(wd)
if err != nil {
badExit(err)
}
// build()
myGui = gui.New()
if !argv.Auto {
myGui.InitEmbed(resources)
if argv.Show != nil {
log.Info("todo: show", me.repo.GetGoPath())
okExit("")
}
myGui.Default()
log.Info("Namespace:", me.repo.GetNamespace(), "Fullpath:", me.repo.GetFullPath())
basicWindow = makebasicWindow()
// todo: add the go.work file logic here
homeDir, _ := os.UserHomeDir()
// figure out where we are working from
// os.Chdir to that directory
var debpath string
if argv.Repo == "." {
if me.repo == nil {
os.Setenv("GO_DEB_CUSTOM", "true")
debpath, _ = os.Getwd()
} else {
debpath = filepath.Join(homeDir, "go/src", argv.Repo)
debpath = me.repo.GetFullPath()
}
_, basename := filepath.Split(debpath)
me.goPath = basename
os.Chdir(debpath)
// scan the repo
cBox.addRepo(argv.Repo)
// look for a 'config' file in the repo
if cBox.readControlFile() == nil {
if readControlFile(me.repo) == nil {
log.Warn("scan worked")
} else {
log.Warn("scan failed")
}
cBox.computeControlValues()
// verify the values for the package
computeControlValues(me.repo)
if repo == nil {
if argv.Repo == "." {
// this means try the local directory for a custom 'control' file
} else {
log.Info("argv.Repo =", argv.Repo)
log.Info("repo not found. Try:")
log.Info("")
log.Info(" go-clone", argv.Repo)
log.Info("")
os.Exit(-1)
if argv.Dump != nil {
for v := range me.repo.Control {
log.Infof("CONTROL: %s: %s\n", v, me.repo.Control[v])
}
okExit("")
}
// set the working directory to argv.Repo
log.Info("cd", repo.FullPath)
os.Chdir(repo.FullPath)
if argv.Auto {
shell.TestTerminalColor()
// basicWindow.Show() // broken gui package. convert to protobuf
if ok, err := cBox.buildPackage(); ok {
log.Info("build worked")
} else {
log.Warn("build failed:", err)
os.Exit(-1)
}
os.Exit(0)
if argv.Gui != nil {
// only load teh toolkit if you get this far
me.myGui.Start() // loads the GUI toolkit
doGui()
debug()
}
// run the debugger if triggered from the commandline
if debugger.ArgDebug() {
go func() {
log.Sleep(2)
debugger.DebugWindow()
}()
log.Info("go-deb: attempting to build package")
if ok, err := buildPackage(me.repo); ok {
log.Info("build worked")
} else {
log.Warn("build failed:", err)
os.Exit(-1)
}
basicWindow.Show()
// go will sit here until the window exits
gui.Watchdog()
os.Exit(0)
}
func debug() {
time.Sleep(2 * time.Second)
for {
log.Info("idle loop() todo: could check for things here")
time.Sleep(90 * time.Second)
}
}

View File

@ -1,104 +0,0 @@
package main
import (
"bufio"
"os"
"strings"
"go.wit.com/log"
)
// readGitConfig reads and parses the control file
func (c *controlBox) readControlFile() error {
pairs := make(map[string]string)
var key string
file, err := os.Open("control")
if err != nil {
log.Warn("readControlFile() could not find the file")
// return errors.New("'control': file not found")
// if this happens, make up a fake control file
pairs["Maintainer"] = "go-deb build"
pairs["Architecture"] = "amd64" // TODO: figure this out
pairs["Recommends"] = ""
pairs["Source"] = "notsure"
if argv.Repo == "" {
pairs["Description"] = "put something here"
} else {
pairs["Description"] = argv.Repo
}
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
// Skip empty lines and comments
if line == "" || strings.HasPrefix(line, "#") || strings.HasPrefix(line, ";") {
continue
}
// if line starts with a space, it's part of the last key
if strings.HasPrefix(line, " ") {
pairs[key] = pairs[key] + "\n" + strings.TrimSpace(line)
continue
}
partsNew := strings.SplitN(line, ":", 2)
if len(partsNew) < 2 {
log.Warn("error on line:", line)
continue
}
key = strings.TrimSpace(partsNew[0])
value := strings.TrimSpace(partsNew[1])
pairs[key] = value
}
for key, value := range pairs {
switch key {
case "Source":
c.Source.SetText(value)
case "Build-Depends":
c.BuildDepends.SetText(value)
case "Description":
c.Description.SetText(value)
case "Maintainer":
c.Maintainer.SetText(value)
case "Packager":
c.Packager.SetText(value)
case "GoPath":
c.GoPath.SetText(value)
case "URL":
c.URL.SetText(value)
case "Depends":
c.Depends.SetText(value)
case "Recommends":
c.Recommends.SetText(value)
case "Conflicts":
c.Conflicts.SetText(value)
case "Version":
c.Version.SetText(value)
case "Package":
c.Package.SetText(value)
// if c.Package.String() != value {
// log.Warn("not sure what to do with Package", c.Package.String(), value)
// }
case "Architecture":
// todo: add logic to find OS arch
if c.Architecture.String() != value {
log.Warn("attempting to set arch to", value)
c.Architecture.SetText(value)
}
default:
log.Warn("error unknown key", key, "value:", value)
}
}
if err := scanner.Err(); err != nil {
return err
}
return nil
}

View File

@ -1,47 +0,0 @@
package main
import (
"os"
"go.wit.com/lib/gadgets"
"go.wit.com/lib/gui/shell"
"go.wit.com/log"
)
// This initializes the first window, a group and a button
func makebasicWindow() *gadgets.BasicWindow {
log.Warn("init basicWindow state")
basicWindow = gadgets.NewBasicWindow(myGui, "Create .deb files for GO applications")
basicWindow.Make()
basicWindow.Custom = func() {
log.Info("got to close")
os.Exit(0)
}
box1 := basicWindow.Box()
cBox = newControl(box1)
vbox := box1.Box().Horizontal()
group1 := vbox.NewGroup("controls").Horizontal() // Vertical()
group1.NewButton("go build", func() {
shell.Run([]string{"go", "build", "-v", "-x"})
})
group1.NewButton("read control file", func() {
cBox.readControlFile()
})
group1.NewButton("Make .deb", func() {
basicWindow.Disable()
if ok, err := cBox.buildPackage(); ok {
log.Info("build worked")
os.Exit(0)
} else {
log.Warn("build failed", err)
}
basicWindow.Enable()
})
return basicWindow
}

52
structs.go Normal file
View File

@ -0,0 +1,52 @@
package main
import (
"go.wit.com/dev/alexflint/arg"
"go.wit.com/gui"
"go.wit.com/lib/gadgets"
"go.wit.com/lib/gui/prep"
"go.wit.com/lib/protobuf/gitpb"
)
var me *mainType
// this app's variables
type mainType struct {
pp *arg.Parser // for parsing the command line args. Yay to alexf lint!
goSrc string // path to ~/go/src or go.work file
goPath string // the goPath to use for the package
hasWork bool // true if using go.work file
repo *gitpb.Repo // this is the repo we are in
myGui *prep.GuiPrep // the gui toolkit handle
}
type controlBox struct {
group *gui.Node // the group
grid *gui.Node // the grid
Package *gadgets.OneLiner
Source *gadgets.OneLiner
Version *gadgets.OneLiner
Maintainer *gadgets.OneLiner
Packager *gadgets.BasicEntry
GoPath *gadgets.BasicEntry
Namespace *gadgets.BasicEntry
URL *gadgets.BasicEntry
Architecture *gadgets.BasicDropdown
InstallPath *gadgets.BasicCombobox
Depends *gadgets.OneLiner
BuildDepends *gadgets.OneLiner
Recommends *gadgets.OneLiner
Conflicts *gadgets.BasicEntry
Test gui.Widget
Description *gadgets.OneLiner
// repostatus things
pathL *gadgets.OneLiner
lastTag *gadgets.OneLiner
dirtyL *gadgets.OneLiner
currentL *gadgets.OneLiner
buildDate *gadgets.OneLiner
tagDate *gadgets.BasicEntry
// status *repostatus.RepoStatus
}

16
update.go Normal file
View File

@ -0,0 +1,16 @@
package main
func updateControl(c *controlBox) {
c.Namespace.SetText(me.repo.Namespace)
c.URL.SetText(me.repo.URL)
c.Package.SetText(me.repo.Control["Package"])
c.Source.SetText(me.repo.Control["Source"])
c.Maintainer.SetText(me.repo.Control["Maintainer"])
c.Packager.SetText(me.repo.Control["Packager"])
c.Version.SetText(me.repo.Control["Version"])
c.Description.SetText(me.repo.Control["Description"])
c.Depends.SetText(me.repo.Control["Depends"])
c.Recommends.SetText(me.repo.Control["Recommends"])
c.Architecture.SetText("amd64")
}