Compare commits
93 Commits
Author | SHA1 | Date |
---|---|---|
|
7e1804f6e3 | |
|
8ceec9210d | |
|
cf6db578a4 | |
|
da485dcc3f | |
|
5377a89d2c | |
|
f7d6dfa6a7 | |
|
281ffbc75b | |
|
4193f41847 | |
|
9d5bae8a14 | |
|
f540aab434 | |
|
a170250cb4 | |
|
2fc67512c8 | |
|
eaadfa21d3 | |
|
22ebf174c8 | |
|
9a87c93bad | |
|
b7b18626d8 | |
|
7900b1416e | |
|
5c84b9ab66 | |
|
c09e292a66 | |
|
3278f6400e | |
|
83ad663fc0 | |
|
f70f54615f | |
|
018772dbfb | |
|
9baa477990 | |
|
ab01c2cd60 | |
|
c89f101fb2 | |
|
23d7ad1581 | |
|
ec4acd425c | |
|
0614066fdb | |
|
b60279b19a | |
|
95fcacfde0 | |
|
b6a71a515f | |
|
47ee3f1493 | |
|
329710f9e7 | |
|
f7b5e1a83e | |
|
7c37e3841a | |
|
f146bf4ef0 | |
|
d9d90e9e12 | |
|
393b91c415 | |
|
b412e50df0 | |
|
aa06450042 | |
|
121e9f08da | |
|
df19b5b8f8 | |
|
0efc3c67ca | |
|
667257595d | |
|
76a0347fdf | |
|
66738e4300 | |
|
3e4b1ddc83 | |
|
9ec7b4394f | |
|
1191b9b65d | |
|
52b8a4e312 | |
|
b770759167 | |
|
0898c24f45 | |
|
58c64cd53b | |
|
f29f25b9b7 | |
|
4328692039 | |
|
244bf612f9 | |
|
f4ac491490 | |
|
bdf9d97cf9 | |
|
a822e1e4f0 | |
|
cee7e25f3d | |
|
9b8cb52b7b | |
|
538531f503 | |
|
e8f29e593d | |
|
b8d0864c37 | |
|
156af56859 | |
|
8d275ff054 | |
|
0f232fe342 | |
|
9e81be86da | |
|
2398e30048 | |
|
49a06843e9 | |
|
9b9c51d964 | |
|
23887a155e | |
|
0600f54488 | |
|
0ea93faef2 | |
|
48b19f1e70 | |
|
1e38cacfa7 | |
|
40c340c626 | |
|
f9dd82cdcc | |
|
4f84a4e584 | |
|
8aff3f13b2 | |
|
26cf5055a2 | |
|
14e5bf5fbd | |
|
e0c0d3d9e6 | |
|
bd3e924e2b | |
|
e6e70ccaa5 | |
|
67ae8d8773 | |
|
e333ca726b | |
|
6cbd7e67af | |
|
7e5db53e9d | |
|
b0662fb61a | |
|
ac57825c10 | |
|
338018376b |
|
@ -1,5 +1,5 @@
|
|||
go.*
|
||||
|
||||
*.swp
|
||||
*.patch
|
||||
*.mbox
|
||||
*.pb.go
|
||||
|
||||
forgeConfig/forgeConfig
|
||||
|
|
16
Makefile
16
Makefile
|
@ -5,7 +5,11 @@
|
|||
# go install
|
||||
|
||||
|
||||
all: goimports forgeConfig.pb.go uuid.pb.go patch.pb.go vet
|
||||
all: forgeConfig.pb.go patchset.pb.go goimports vet
|
||||
|
||||
generate: clean
|
||||
autogenpb --proto patchset.proto
|
||||
autogenpb --proto forgeConfig.proto
|
||||
|
||||
vet:
|
||||
@GO111MODULE=off go vet
|
||||
|
@ -16,14 +20,12 @@ goimports:
|
|||
goimports -w *.go
|
||||
|
||||
clean:
|
||||
rm -f *.pb.go
|
||||
rm -f *.pb.go *.patch
|
||||
-rm -f go.*
|
||||
go-mod-clean --purge
|
||||
|
||||
forgeConfig.pb.go: forgeConfig.proto
|
||||
autogenpb --proto forgeConfig.proto
|
||||
|
||||
uuid.pb.go: uuid.proto
|
||||
autogenpb --proto uuid.proto
|
||||
|
||||
patch.pb.go: patch.proto
|
||||
autogenpb --proto patch.proto
|
||||
patchset.pb.go: patchset.proto
|
||||
autogenpb --proto patchset.proto
|
||||
|
|
36
build.go
36
build.go
|
@ -30,6 +30,7 @@ func (f *Forge) Install(repo *gitpb.Repo, userFlags []string) error {
|
|||
return f.doBuild(repo, userFlags, "install")
|
||||
}
|
||||
|
||||
// userflags are intended for "-v" and "-x" right now
|
||||
func (f *Forge) doBuild(repo *gitpb.Repo, userFlags []string, goWhat string) error {
|
||||
if repo == nil {
|
||||
log.Warn("forge.doBuild repo == nil")
|
||||
|
@ -57,6 +58,9 @@ func (f *Forge) doBuild(repo *gitpb.Repo, userFlags []string, goWhat string) err
|
|||
data, _ := repo.ReadFile(".forge")
|
||||
log.Info(".forge =", string(data))
|
||||
log.Info("todo: do the custom build instructions")
|
||||
basedir, filename := filepath.Split(repo.GetGoPath())
|
||||
log.Info("touching filename", basedir, filename)
|
||||
repo.RunVerbose([]string{"touch", filename})
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -108,11 +112,14 @@ func (f *Forge) doBuild(repo *gitpb.Repo, userFlags []string, goWhat string) err
|
|||
cmd = append(cmd, "-buildmode=plugin", "-o", soname)
|
||||
}
|
||||
}
|
||||
cmd = append(cmd, "-v")
|
||||
for _, flag := range userFlags {
|
||||
cmd = append(cmd, flag)
|
||||
}
|
||||
|
||||
// set standard ldflag options
|
||||
now := time.Now()
|
||||
datestamp := now.UTC().Format("2006/01/02_1504_UTC")
|
||||
// datestamp := now.UTC().Format("2006/01/02_1504_UTC")
|
||||
datestamp := now.UTC().Format("2006-01-02_15:04:05_UTC") // 2006-01-02 15:04:05 UTC
|
||||
// log.Info("datestamp =", datestamp)
|
||||
// add some standard golang flags
|
||||
ldflags := "-X main.VERSION=" + version + " "
|
||||
|
@ -120,13 +127,6 @@ func (f *Forge) doBuild(repo *gitpb.Repo, userFlags []string, goWhat string) err
|
|||
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())
|
||||
|
@ -209,3 +209,21 @@ func (f *Forge) FindWorkingDirRepo() *gitpb.Repo {
|
|||
basedir = strings.Trim(basedir, "/")
|
||||
return f.FindByGoPath(basedir)
|
||||
}
|
||||
|
||||
// Never do this. this is stupid. fix your repo
|
||||
// Never try to version & release broken repos
|
||||
// leave this code here as a reminder to never attempt this
|
||||
func (f *Forge) forgeIgnoreGoMod(repo *gitpb.Repo) bool {
|
||||
if !repo.Exists(".forge") {
|
||||
return false
|
||||
}
|
||||
log.Info("custom build instructions")
|
||||
data, _ := repo.ReadFile(".forge")
|
||||
log.Info(".forge =", string(data))
|
||||
for _, line := range strings.Split(string(data), "\n") {
|
||||
if strings.Contains(line, "forge:ignore:gomod") { // this is stupid
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -0,0 +1,161 @@
|
|||
package forgepb
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"go.wit.com/lib/protobuf/gitpb"
|
||||
"go.wit.com/log"
|
||||
)
|
||||
|
||||
// This will recreate your go.sum and go.mod files
|
||||
var cleanVerbose bool = false
|
||||
|
||||
// checks to see if every 'master' git branch version
|
||||
// matches the go.sum file
|
||||
func (f *Forge) CleanGoDepsCheckOk(check *gitpb.Repo) error {
|
||||
var err error = nil
|
||||
var fixes [][]string
|
||||
log.Printf("current repo %s go dependancy count: %d", check.GetGoPath(), check.GoDepsLen())
|
||||
if check.GoDeps == nil {
|
||||
return errors.New("check.GoDeps == nil")
|
||||
}
|
||||
all := check.GoDeps.SortByGoPath()
|
||||
for all.Scan() {
|
||||
depRepo := all.Next()
|
||||
found := f.FindByGoPath(depRepo.GetGoPath())
|
||||
if found == nil {
|
||||
if f.CheckOverride(depRepo.GetGoPath()) {
|
||||
// skip this gopath because it's probably broken forever
|
||||
continue
|
||||
}
|
||||
log.Info("not found:", depRepo.GetGoPath())
|
||||
err = errors.New("not found: " + depRepo.GetGoPath())
|
||||
continue
|
||||
}
|
||||
// log.Info("found dep", depRepo.GetGoPath())
|
||||
if depRepo.GetVersion() != found.GetMasterVersion() {
|
||||
check := f.FindByGoPath(depRepo.GetGoPath())
|
||||
var ends string
|
||||
if check.CheckDirty() {
|
||||
ends = "(dirty) "
|
||||
}
|
||||
|
||||
if f.Config.IsReadOnly(check.GetGoPath()) {
|
||||
ends += "(ignoring read-only) "
|
||||
if cleanVerbose {
|
||||
log.Printf("%-48s ok error .%s. vs .%s. %s", depRepo.GetGoPath(),
|
||||
depRepo.GetVersion(), found.GetMasterVersion(), ends)
|
||||
}
|
||||
} else {
|
||||
if f.CheckOverride(depRepo.GetGoPath()) {
|
||||
ends += "(override) "
|
||||
if cleanVerbose {
|
||||
log.Printf("%-48s ok error .%s. vs .%s. %s", depRepo.GetGoPath(),
|
||||
depRepo.GetVersion(), found.GetMasterVersion(), ends)
|
||||
// skip this gopath because it's probably broken forever
|
||||
}
|
||||
continue
|
||||
} else {
|
||||
log.Printf("%-48s error %10s vs %10s %s", depRepo.GetGoPath(),
|
||||
depRepo.GetVersion(), found.GetMasterVersion(), ends)
|
||||
errs := fmt.Sprintf("%s error %s vs %s %s", depRepo.GetGoPath(),
|
||||
depRepo.GetVersion(), found.GetMasterVersion(), ends)
|
||||
if ok, _ := ValidGoVersion(found.GetMasterVersion()); ok {
|
||||
// can't go get invalid version numbers
|
||||
cmd := []string{"go", "get", depRepo.GetGoPath() + "@" + found.GetMasterVersion()}
|
||||
fixes = append(fixes, cmd)
|
||||
}
|
||||
err = errors.New(errs)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for i, cmd := range fixes {
|
||||
log.Info("try cmd", i, cmd)
|
||||
check.RunRealtime(cmd)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (f *Forge) TrimGoSum(check *gitpb.Repo) error {
|
||||
var stuff map[string]string
|
||||
stuff = make(map[string]string)
|
||||
|
||||
var modver map[string]string
|
||||
modver = make(map[string]string)
|
||||
|
||||
var good map[string]bool
|
||||
good = make(map[string]bool)
|
||||
|
||||
if check == nil {
|
||||
log.Info("boo, check == nil")
|
||||
return errors.New("*repo == nil")
|
||||
}
|
||||
filename := filepath.Join(filepath.Join(check.FullPath, "go.sum"))
|
||||
data, err := os.ReadFile(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, line := range strings.Split(string(data), "\n") {
|
||||
parts := strings.Fields(line)
|
||||
if len(parts) < 3 {
|
||||
log.Info("WIERD OR BAD:", line)
|
||||
continue
|
||||
}
|
||||
|
||||
gopath := parts[0]
|
||||
version := parts[1]
|
||||
hash := parts[2]
|
||||
|
||||
if strings.HasSuffix(version, "/go.mod") {
|
||||
if _, ok := stuff[gopath]; ok {
|
||||
if cleanVerbose {
|
||||
log.Info("MATCHED: gopath:", gopath, "version:", version)
|
||||
}
|
||||
modver[gopath] = version + " " + hash
|
||||
good[gopath] = true
|
||||
} else {
|
||||
if cleanVerbose {
|
||||
log.Info("GARBAGE: gopath:", gopath, "version:", version)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if cleanVerbose {
|
||||
log.Info("GOOD : gopath:", gopath, "version:", version)
|
||||
}
|
||||
stuff[gopath] = version + " " + hash
|
||||
}
|
||||
}
|
||||
|
||||
keys := make([]string, 0, len(stuff))
|
||||
for k := range stuff {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
|
||||
// rewrite the go.sum file
|
||||
newfilename := filepath.Join(filepath.Join(check.FullPath, "go.sum"))
|
||||
newf, err := os.OpenFile(newfilename, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer newf.Close()
|
||||
sort.Strings(keys)
|
||||
for _, gopath := range keys {
|
||||
if good[gopath] {
|
||||
fmt.Fprintf(newf, "%s %s\n", gopath, stuff[gopath])
|
||||
fmt.Fprintf(newf, "%s %s\n", gopath, modver[gopath])
|
||||
check := f.FindByGoPath(gopath)
|
||||
if check == nil {
|
||||
log.Info("gopath does not really exist:", gopath)
|
||||
}
|
||||
}
|
||||
}
|
||||
// fmt.Fprintln(newf, "test")
|
||||
return nil
|
||||
}
|
2
clone.go
2
clone.go
|
@ -1,3 +1,5 @@
|
|||
// Copyright 2025 WIT.COM Inc Licensed GPL 3.0
|
||||
|
||||
package forgepb
|
||||
|
||||
import (
|
||||
|
|
51
config.go
51
config.go
|
@ -1,3 +1,5 @@
|
|||
// Copyright 2025 WIT.COM Inc Licensed GPL 3.0
|
||||
|
||||
package forgepb
|
||||
|
||||
// functions to import and export the protobuf
|
||||
|
@ -5,10 +7,13 @@ package forgepb
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"go.wit.com/log"
|
||||
timestamppb "google.golang.org/protobuf/types/known/timestamppb"
|
||||
)
|
||||
|
||||
func (f *Forge) ConfigSave() error {
|
||||
|
@ -27,6 +32,11 @@ func (f *Forge) ConfigSave() error {
|
|||
}
|
||||
}
|
||||
if f.Repos != nil {
|
||||
if f.HasFullScan() {
|
||||
f.Repos.HasFullScan = true
|
||||
t := time.Now()
|
||||
f.Repos.FullScan = timestamppb.New(t)
|
||||
}
|
||||
if e := f.Repos.ConfigSave(); e != nil {
|
||||
log.Info("forge.Repos.ConfigSave() error", e)
|
||||
err = e
|
||||
|
@ -42,7 +52,7 @@ func (f *ForgeConfigs) ConfigSave() error {
|
|||
log.Info("proto.Marshal() failed len", len(data), err)
|
||||
return err
|
||||
}
|
||||
log.Info("forgepb.ConfigSave() proto.Marshal() worked len", len(data))
|
||||
// log.Info("forgepb.ConfigSave() proto.Marshal() worked len", len(data))
|
||||
|
||||
s := f.FormatTEXT()
|
||||
configWrite("forge.text", []byte(s))
|
||||
|
@ -64,25 +74,13 @@ func (c *ForgeConfigs) ConfigLoad() error {
|
|||
// var err error
|
||||
if c == nil {
|
||||
// can't safely do c = new(ForgeConfig) if c is in a struct from the caller. notsure why
|
||||
// TODO: recheck this. it might work now? It's probably still a bad idea(?)
|
||||
return errors.New("It's not safe to run ConfigLoad() on a nil")
|
||||
}
|
||||
|
||||
// this lets the user hand edit the config
|
||||
if data, err := loadFile("forge.text"); err == nil {
|
||||
if data != nil {
|
||||
// this means the forge.text file exists and was read
|
||||
if len(data) != 0 {
|
||||
if err = c.UnmarshalTEXT(data); err != nil {
|
||||
log.Info("forge.ConfigLoad()", len(c.ForgeConfigs), "entries in ~/.config/forge")
|
||||
// forge.pb file was broken. save on load right away
|
||||
log.Info("attempting forge.ConfigSave()")
|
||||
c.ConfigSave()
|
||||
if err := c.loadText(); err == nil {
|
||||
return nil
|
||||
}
|
||||
// todo: error out if the file is empty?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// forge.text doesn't exist. try forge.json
|
||||
// this lets the user hand edit the JSON config
|
||||
|
@ -93,7 +91,7 @@ func (c *ForgeConfigs) ConfigLoad() error {
|
|||
if len(data) != 0 {
|
||||
if err = c.UnmarshalJSON(data); err == nil {
|
||||
log.Info("forge.ConfigLoad()", len(c.ForgeConfigs), "entries in ~/.config/forge")
|
||||
// forge.pb file was broken. save on load right away
|
||||
// forge.text file was broken. save on load right away
|
||||
log.Info("attempting forge.ConfigSave()")
|
||||
c.ConfigSave()
|
||||
return nil
|
||||
|
@ -114,6 +112,27 @@ func (c *ForgeConfigs) ConfigLoad() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (c *ForgeConfigs) loadText() error {
|
||||
// this lets the user hand edit the config
|
||||
data, err := loadFile("forge.text")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if data == nil {
|
||||
return fmt.Errorf("forge.text data was nil")
|
||||
}
|
||||
if len(data) == 0 {
|
||||
return fmt.Errorf("forge.text was empty")
|
||||
}
|
||||
|
||||
// attempt to marshal forge.text
|
||||
if err := c.UnmarshalTEXT(data); err != nil {
|
||||
return err
|
||||
}
|
||||
log.Log(INFO, "forge.ConfigLoad()", len(c.ForgeConfigs), "entries in ~/.config/forge")
|
||||
return nil
|
||||
}
|
||||
|
||||
func loadFile(filename string) ([]byte, error) {
|
||||
fullname := filepath.Join(os.Getenv("FORGE_CONFIG"), filename)
|
||||
data, err := os.ReadFile(fullname)
|
||||
|
|
|
@ -7,7 +7,6 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
@ -15,12 +14,8 @@ import (
|
|||
|
||||
func backupConfig() error {
|
||||
// make a new dir to backup the files
|
||||
now := time.Now()
|
||||
// timestamp := now.Format("2022.07.18.190545") // 50yr shout out to K&R
|
||||
timestamp := now.Format("2006.01.02.150405") // bummer. other date doesn't work?
|
||||
srcDir := filepath.Join(os.Getenv("FORGE_CONFIG"))
|
||||
destDir := filepath.Join(os.Getenv("FORGE_CONFIG"), timestamp)
|
||||
|
||||
destDir := filepath.Join(os.Getenv("FORGE_CONFIG"), "backup")
|
||||
return backupFiles(srcDir, destDir)
|
||||
}
|
||||
|
||||
|
@ -44,7 +39,7 @@ func backupFiles(srcDir string, destDir string) error {
|
|||
continue
|
||||
}
|
||||
|
||||
log.Println("backing up file", entry.Name())
|
||||
// log.Println("backing up file", entry.Name())
|
||||
srcPath := filepath.Join(srcDir, entry.Name())
|
||||
destPath := filepath.Join(destDir, entry.Name())
|
||||
|
||||
|
@ -64,6 +59,9 @@ func copyFile(src, dest string) error {
|
|||
}
|
||||
defer srcFile.Close()
|
||||
|
||||
now := time.Now()
|
||||
timestamp := now.Format("2006.01.02.150405") // bummer. other date doesn't work?
|
||||
dest = dest + timestamp
|
||||
destFile, err := os.Create(dest)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -2,8 +2,6 @@ package forgepb
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"go.wit.com/log"
|
||||
)
|
||||
|
||||
func (all *ForgeConfigs) sampleConfig() {
|
||||
|
@ -11,53 +9,7 @@ func (all *ForgeConfigs) sampleConfig() {
|
|||
new1.GoPath = "go.wit.com"
|
||||
new1.Writable = true
|
||||
new1.Directory = true
|
||||
if all.Append(new1) {
|
||||
log.Info("added", new1.GoPath, "ok")
|
||||
} else {
|
||||
log.Info("added", new1.GoPath, "failed")
|
||||
}
|
||||
|
||||
new1 = new(ForgeConfig)
|
||||
new1.GoPath = "go.wit.com/apps/zookeeper"
|
||||
new1.DebName = "zookeeper-go"
|
||||
if all.Append(new1) {
|
||||
log.Info("added", new1.GoPath, "ok")
|
||||
} else {
|
||||
log.Info("added", new1.GoPath, "failed")
|
||||
}
|
||||
|
||||
new1 = new(ForgeConfig)
|
||||
new1.GoPath = "go.wit.com/apps/wit-package"
|
||||
new1.Private = true
|
||||
if all.Append(new1) {
|
||||
log.Info("added", new1.GoPath, "ok")
|
||||
} else {
|
||||
log.Info("added", new1.GoPath, "failed")
|
||||
}
|
||||
|
||||
new1 = new(ForgeConfig)
|
||||
new1.GoPath = "go.wit.com/apps/networkQuality"
|
||||
new1.DebName = "networkquality"
|
||||
new1.ReadOnly = true
|
||||
if all.Append(new1) {
|
||||
log.Info("added", new1.GoPath, "ok")
|
||||
} else {
|
||||
log.Info("added", new1.GoPath, "failed")
|
||||
}
|
||||
|
||||
new2 := new(ForgeConfig)
|
||||
new2.GoPath = "go.wit.com/apps/go-clone"
|
||||
if all.Append(new2) {
|
||||
log.Info("added", new2.GoPath, "ok")
|
||||
} else {
|
||||
log.Info("added", new2.GoPath, "failed")
|
||||
}
|
||||
|
||||
if all.Append(new2) {
|
||||
log.Info("added", new2.GoPath, "ok (this is bad)")
|
||||
} else {
|
||||
log.Info("added", new2.GoPath, "failed (but ok)")
|
||||
}
|
||||
all.Append(new1)
|
||||
|
||||
fmt.Println("first time user. adding an example config file with", len(all.ForgeConfigs), "repos")
|
||||
}
|
||||
|
|
|
@ -260,3 +260,65 @@ func (fc *ForgeConfigs) FindUserBranch(thing string) string {
|
|||
|
||||
return match.UserBranchName
|
||||
}
|
||||
|
||||
// allows custom devel branch names in the forge config
|
||||
func (fc *ForgeConfigs) FindDevelBranch(thing string) string {
|
||||
var match *ForgeConfig
|
||||
|
||||
all := fc.SortByGoPath() // get the list of repos
|
||||
for all.Scan() {
|
||||
r := all.Next()
|
||||
if r.GoPath == thing {
|
||||
if r.DevelBranchName != "" {
|
||||
return r.DevelBranchName
|
||||
}
|
||||
}
|
||||
base := filepath.Base(r.GoPath)
|
||||
if base == thing {
|
||||
if r.DevelBranchName != "" {
|
||||
return r.DevelBranchName
|
||||
}
|
||||
}
|
||||
if r.Directory {
|
||||
if strings.HasPrefix(thing, r.GoPath) {
|
||||
match = r
|
||||
}
|
||||
}
|
||||
}
|
||||
if match == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return match.DevelBranchName
|
||||
}
|
||||
|
||||
// allows custom devel branch names in the forge config
|
||||
func (fc *ForgeConfigs) FindMasterBranch(thing string) string {
|
||||
var match *ForgeConfig
|
||||
|
||||
all := fc.SortByGoPath() // get the list of repos
|
||||
for all.Scan() {
|
||||
r := all.Next()
|
||||
if r.GoPath == thing {
|
||||
if r.MasterBranchName != "" {
|
||||
return r.MasterBranchName
|
||||
}
|
||||
}
|
||||
base := filepath.Base(r.GoPath)
|
||||
if base == thing {
|
||||
if r.MasterBranchName != "" {
|
||||
return r.MasterBranchName
|
||||
}
|
||||
}
|
||||
if r.Directory {
|
||||
if strings.HasPrefix(thing, r.GoPath) {
|
||||
match = r
|
||||
}
|
||||
}
|
||||
}
|
||||
if match == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return match.MasterBranchName
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package forgepb
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"go.wit.com/lib/protobuf/gitpb"
|
||||
|
@ -16,24 +18,20 @@ import (
|
|||
// it re-scans the go.sum file. DOES NOT MODIFY ANYTHING
|
||||
// this is the last thing to run to double check everything
|
||||
// before 'git tag' or git push --tags
|
||||
func (f *Forge) FinalGoDepsCheckOk(check *gitpb.Repo) bool {
|
||||
var good bool = true
|
||||
func (f *Forge) FinalGoDepsCheckOk(check *gitpb.Repo, verbose bool) error {
|
||||
if check == nil {
|
||||
log.Info("boo, check == nil")
|
||||
return false
|
||||
return errors.New("FinalGoDepsCheckOk() boo, check == nil")
|
||||
}
|
||||
|
||||
// parse the go.mod and go.sum files
|
||||
if !check.ParseGoSum() {
|
||||
log.Info("forge.FinalGoDepsCheckOk() failed")
|
||||
return false
|
||||
return fmt.Errorf("forge.ParseGoSum() failed. go.mod & go.sum are broken")
|
||||
}
|
||||
|
||||
if check.GetGoPrimitive() {
|
||||
return true
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Printf("current repo %s go dependancy count: %d", check.GetGoPath(), check.GoDepsLen())
|
||||
deps := check.GoDeps.SortByGoPath()
|
||||
for deps.Scan() {
|
||||
depRepo := deps.Next()
|
||||
|
@ -43,63 +41,114 @@ func (f *Forge) FinalGoDepsCheckOk(check *gitpb.Repo) bool {
|
|||
// skip this gopath because it's probably broken forever
|
||||
continue
|
||||
}
|
||||
log.Info("not found:", depRepo.GetGoPath())
|
||||
good = false
|
||||
return fmt.Errorf("dep not found: %s", depRepo.GetGoPath())
|
||||
}
|
||||
if depRepo.GetVersion() == found.GetMasterVersion() {
|
||||
// log.Printf("%-48s error ?? %-10s vs %-10s\n", depRepo.GetGoPath(), depRepo.GetVersion(), found.GetMasterVersion())
|
||||
continue
|
||||
}
|
||||
// log.Info("found dep", depRepo.GetGoPath())
|
||||
if depRepo.GetVersion() != found.GetTargetVersion() {
|
||||
check := f.FindByGoPath(depRepo.GetGoPath())
|
||||
if f.Config.IsReadOnly(check.GetGoPath()) {
|
||||
log.Printf("%-48s ok error .%s. vs .%s. (ignoring read-only repo)", depRepo.GetGoPath(), depRepo.GetVersion(), found.GetTargetVersion())
|
||||
if verbose {
|
||||
log.Printf("%-48s ok error .%s. vs .%s. (ignoring read-only repo)\n", depRepo.GetGoPath(), depRepo.GetVersion(), found.GetTargetVersion())
|
||||
}
|
||||
} else {
|
||||
if f.CheckOverride(depRepo.GetGoPath()) {
|
||||
log.Printf("%-48s ok error .%s. vs .%s. (forge.CheckOverride())", depRepo.GetGoPath(), depRepo.GetVersion(), found.GetTargetVersion())
|
||||
if verbose {
|
||||
log.Printf("%-48s ok error .%s. vs .%s. (forge.CheckOverride())\n", depRepo.GetGoPath(), depRepo.GetVersion(), found.GetTargetVersion())
|
||||
}
|
||||
// skip this gopath because it's probably broken forever
|
||||
continue
|
||||
} else {
|
||||
log.Printf("%-48s error %10s vs %10s", depRepo.GetGoPath(), depRepo.GetVersion(), found.GetTargetVersion())
|
||||
good = false
|
||||
// log.Printf("%-48s error ?? %-10s vs %-10s\n", depRepo.GetGoPath(), depRepo.GetVersion(), found.GetMasterVersion())
|
||||
// log.Printf("%-48s error %10s vs %10s\n", depRepo.GetGoPath(), depRepo.GetVersion(), found.GetTargetVersion())
|
||||
return fmt.Errorf("%-48s error %10s vs %10s", depRepo.GetGoPath(), depRepo.GetVersion(), found.GetMasterVersion())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return good
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *Forge) CheckOverride(gopath string) bool {
|
||||
if gopath == "cloud.google.com/go" {
|
||||
log.Info("CheckOverride() is ignoring", gopath)
|
||||
// log.Info("CheckOverride() is ignoring", gopath)
|
||||
return true
|
||||
}
|
||||
if gopath == "bou.ke/monkey" {
|
||||
log.Info("CheckOverride() is ignoring", gopath)
|
||||
// log.Info("CheckOverride() is ignoring", gopath)
|
||||
return true
|
||||
}
|
||||
if gopath == "github.com/posener/complete/v2" {
|
||||
log.Info("CheckOverride() is ignoring", gopath)
|
||||
// log.Info("CheckOverride() is ignoring", gopath)
|
||||
return true
|
||||
}
|
||||
if strings.HasPrefix(gopath, "github.com/go-gl") {
|
||||
log.Info("CheckOverride() is ignoring", gopath)
|
||||
// log.Info("CheckOverride() is ignoring", gopath)
|
||||
return true
|
||||
}
|
||||
if strings.HasPrefix(gopath, "google.golang.org") {
|
||||
log.Info("CheckOverride() is ignoring", gopath)
|
||||
// log.Info("CheckOverride() is ignoring", gopath)
|
||||
return true
|
||||
}
|
||||
if strings.HasPrefix(gopath, "go.opencensus.io") {
|
||||
log.Info("CheckOverride() is ignoring", gopath)
|
||||
// log.Info("CheckOverride() is ignoring", gopath)
|
||||
return true
|
||||
}
|
||||
if strings.HasPrefix(gopath, "github.com/nicksnyder/go-i18n") {
|
||||
log.Info("CheckOverride() is ignoring", gopath)
|
||||
// log.Info("CheckOverride() is ignoring", gopath)
|
||||
return true
|
||||
}
|
||||
// fuckit for now. just blacklist github.com
|
||||
if strings.HasPrefix(gopath, "github.com/") {
|
||||
log.Info("CheckOverride() is ignoring", gopath)
|
||||
// log.Info("CheckOverride() is ignoring", gopath)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (f *Forge) TestGoDepsCheckOk(godeps *gitpb.GoDeps, verbose bool) error {
|
||||
if godeps == nil {
|
||||
return errors.New("forge.TestGoDepsCheckOk() godeps == nil")
|
||||
}
|
||||
all := godeps.SortByGoPath()
|
||||
for all.Scan() {
|
||||
depRepo := all.Next()
|
||||
found := f.FindByGoPath(depRepo.GetGoPath())
|
||||
if found == nil {
|
||||
if f.CheckOverride(depRepo.GetGoPath()) {
|
||||
// skip this gopath because it's probably broken forever
|
||||
continue
|
||||
}
|
||||
return fmt.Errorf("dep not found: %s", depRepo.GetGoPath())
|
||||
}
|
||||
if depRepo.GetVersion() == found.GetMasterVersion() {
|
||||
// log.Printf("%-48s error ?? %-10s vs %-10s\n", depRepo.GetGoPath(), depRepo.GetVersion(), found.GetMasterVersion())
|
||||
continue
|
||||
}
|
||||
// log.Info("found dep", depRepo.GetGoPath())
|
||||
if depRepo.GetVersion() != found.GetTargetVersion() {
|
||||
check := f.FindByGoPath(depRepo.GetGoPath())
|
||||
if f.Config.IsReadOnly(check.GetGoPath()) {
|
||||
if verbose {
|
||||
log.Printf("%-48s ok error .%s. vs .%s. (ignoring read-only repo)\n", depRepo.GetGoPath(), depRepo.GetVersion(), found.GetTargetVersion())
|
||||
}
|
||||
} else {
|
||||
if f.CheckOverride(depRepo.GetGoPath()) {
|
||||
if verbose {
|
||||
log.Printf("%-48s ok error .%s. vs .%s. (forge.CheckOverride())\n", depRepo.GetGoPath(), depRepo.GetVersion(), found.GetTargetVersion())
|
||||
}
|
||||
// skip this gopath because it's probably broken forever
|
||||
continue
|
||||
} else {
|
||||
// log.Printf("%-48s error ?? %-10s vs %-10s\n", depRepo.GetGoPath(), depRepo.GetVersion(), found.GetMasterVersion())
|
||||
// log.Printf("%-48s error %10s vs %10s\n", depRepo.GetGoPath(), depRepo.GetVersion(), found.GetTargetVersion())
|
||||
return fmt.Errorf("%-48s error %10s vs %10s", depRepo.GetGoPath(), depRepo.GetVersion(), found.GetMasterVersion())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// Copyright 2025 WIT.COM Inc Licensed GPL 3.0
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package forgepb;
|
||||
|
@ -12,8 +14,8 @@ import "google/protobuf/timestamp.proto"; // Import the well-known type for Time
|
|||
// package names sometimes must be different than the binary name
|
||||
// for example 'zookeeper' is packaged as 'zookeeper-go'
|
||||
// due to the prior apache foundation project. This happens and is ok!
|
||||
message ForgeConfig {
|
||||
string goPath = 1; // `autogenpb:unique` // Examples: 'go.wit.com/apps/go-clone' or "~/mythings" or "/home/src/foo"
|
||||
message ForgeConfig { // `autogenpb:nomutex`
|
||||
string goPath = 1; // `autogenpb:unique` `autogenpb:sort` // Examples: 'go.wit.com/apps/go-clone' or "~/mythings" or "/home/src/foo"
|
||||
|
||||
bool writable = 2; // if you have write access to the repo
|
||||
bool readOnly = 3; // the opposite, but needed for now because I don't know what I'm doing
|
||||
|
@ -34,9 +36,27 @@ message ForgeConfig {
|
|||
string goSrc = 13; // is ~/go/src unless a go.work file is found
|
||||
}
|
||||
|
||||
message ForgeConfigs { // `autogenpb:marshal`
|
||||
string uuid = 1; // could be useful for /usr/share/file/magic someday?
|
||||
string version = 2; // could be used for protobuf schema change violations?
|
||||
// todo: fix autogenpb to look for enum
|
||||
enum ForgeMode {
|
||||
MASTER = 0; // "release mode"
|
||||
DEVEL = 1; // "patch mode"
|
||||
USER = 2; // "work mode"
|
||||
}
|
||||
|
||||
message ForgeConfigs { // `autogenpb:marshal` `autogenpb:nomutex`
|
||||
string uuid = 1; // `autogenpb:uuid:1941cd4f-1cfd-4bf6-aa75-c2c391907e81`
|
||||
string version = 2; // `autogenpb:version:v0.0.47`
|
||||
repeated ForgeConfig ForgeConfigs = 3;
|
||||
string username = 4; // what to use for the user branch (default ENV{USER})
|
||||
string xterm = 5; // what xterm the user wants as the default
|
||||
repeated string xtermArgv = 6; // the argv line for xterm
|
||||
string defaultGui = 7; // default GUI plugin to use
|
||||
ForgeMode mode = 8; // what "mode" forge is in
|
||||
}
|
||||
|
||||
// this generic message is used by autogen to identify and
|
||||
// then dump the uuid and version from any arbitrary .pb file
|
||||
message Identify { // `autogenpb:marshal`
|
||||
string uuid = 1; //
|
||||
string version = 2; //
|
||||
}
|
||||
|
|
151
gitCheckout.go
151
gitCheckout.go
|
@ -1,151 +0,0 @@
|
|||
package forgepb
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"go.wit.com/lib/protobuf/gitpb"
|
||||
"go.wit.com/log"
|
||||
)
|
||||
|
||||
func (f *Forge) GitPull() bool {
|
||||
f.Repos.RillGitPull(5, 5)
|
||||
/*
|
||||
|
||||
var localonly int
|
||||
var badmap int
|
||||
|
||||
log.Log(FORGEPBWARN, "running git pull everywhere")
|
||||
var failed int = 0
|
||||
for all.Scan() {
|
||||
repo := all.Next()
|
||||
if out, err := repo.GitPull(); err == nil {
|
||||
log.Log(FORGEPBWARN, "Ran git pull ok", repo.GetGoPath(), out)
|
||||
} else {
|
||||
failed += 1
|
||||
// repo.DumpTags()
|
||||
if errors.Is(repostatus.ErrorGitPullOnLocal, err) {
|
||||
localonly += 1
|
||||
continue
|
||||
}
|
||||
badmap += 1
|
||||
log.Log(FORGEPBWARN, "bad unknown git error", repo.GetGoPath(), out, err)
|
||||
}
|
||||
}
|
||||
log.Log(FORGEPBWARN, "Ran git pull in all repos. failure count =", failed)
|
||||
log.Log(FORGEPBWARN, "Ran git pull in all repos. bad errors =", badmap)
|
||||
if localonly != 0 {
|
||||
log.Log(FORGEPBWARN, "Ran git pull in all repos. ignored local only branches =", localonly)
|
||||
}
|
||||
*/
|
||||
return true
|
||||
}
|
||||
|
||||
func (f *Forge) CheckoutDevel() bool {
|
||||
log.Log(FORGEPBWARN, "running git checkout devel everwhere")
|
||||
var failed int = 0
|
||||
var count int = 0
|
||||
all := f.Repos.SortByFullPath()
|
||||
for all.Scan() {
|
||||
repo := all.Next()
|
||||
count += 1
|
||||
if repo.CheckoutDevel() {
|
||||
// checkout ok
|
||||
} else {
|
||||
dname := repo.GetDevelBranchName()
|
||||
if err := f.makeBranch(repo, dname); err != nil {
|
||||
log.Info(repo.GetGoPath(), "can not make devel branch", dname)
|
||||
failed += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
log.Log(FORGEPBWARN, "Ran git checkout in", count, "repos. failure count =", failed)
|
||||
return true
|
||||
}
|
||||
|
||||
func (f *Forge) MakeDevelBranch(repo *gitpb.Repo) error {
|
||||
dname := repo.GetDevelBranchName()
|
||||
if dname == "" {
|
||||
dname = f.configDevelBranchName(repo)
|
||||
}
|
||||
if err := f.makeBranch(repo, dname); err != nil {
|
||||
return err
|
||||
}
|
||||
repo.DevelBranchName = dname
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *Forge) MakeUserBranch(repo *gitpb.Repo) error {
|
||||
uname := repo.GetUserBranchName()
|
||||
if uname == "" {
|
||||
uname = f.configUserBranchName(repo)
|
||||
}
|
||||
if err := f.makeBranch(repo, uname); err != nil {
|
||||
return err
|
||||
}
|
||||
repo.UserBranchName = uname
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *Forge) makeBranch(repo *gitpb.Repo, bname string) error {
|
||||
if repo.IsLocalBranch(bname) {
|
||||
// branch already exists in refs/heads/
|
||||
return nil
|
||||
}
|
||||
if repo.IsBranch(bname) {
|
||||
// branch already exists refs/remotes/
|
||||
return nil
|
||||
} else {
|
||||
log.Info("makeBranch() says", bname, "does not exist")
|
||||
loop := repo.Tags.All()
|
||||
for loop.Scan() {
|
||||
t := loop.Next()
|
||||
log.Info("LocalTagExists() tag:", t.Refname)
|
||||
}
|
||||
}
|
||||
mname := repo.GetMasterBranchName()
|
||||
cname := repo.GetCurrentBranchName()
|
||||
if mname != cname {
|
||||
return errors.New("can only make branches from master branch")
|
||||
}
|
||||
cmd := []string{"git", "branch", bname}
|
||||
if err := repo.StrictRun(cmd); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *Forge) CheckoutMaster() bool {
|
||||
log.Log(FORGEPBWARN, "running git checkout master everwhere")
|
||||
var failed int = 0
|
||||
var count int = 0
|
||||
all := f.Repos.SortByFullPath()
|
||||
for all.Scan() {
|
||||
repo := all.Next()
|
||||
count += 1
|
||||
if repo.CheckoutMaster() {
|
||||
// checkout ok
|
||||
} else {
|
||||
failed += 1
|
||||
}
|
||||
}
|
||||
log.Log(FORGEPBWARN, "Ran git checkout in", count, "repos. failure count =", failed)
|
||||
return true
|
||||
}
|
||||
|
||||
func (f *Forge) CheckoutUser() bool {
|
||||
log.Log(FORGEPBWARN, "running git checkout user everwhere")
|
||||
var failed int = 0
|
||||
var count int = 0
|
||||
all := f.Repos.SortByFullPath()
|
||||
for all.Scan() {
|
||||
repo := all.Next()
|
||||
count += 1
|
||||
if repo.CheckoutUser() {
|
||||
// checkout ok
|
||||
} else {
|
||||
failed += 1
|
||||
}
|
||||
}
|
||||
log.Log(FORGEPBWARN, "Ran git checkout in", count, "repos. failure count =", failed)
|
||||
return true
|
||||
}
|
|
@ -12,6 +12,10 @@ import (
|
|||
"go.wit.com/log"
|
||||
)
|
||||
|
||||
func (f *Forge) GetHome() string {
|
||||
return f.goSrc
|
||||
}
|
||||
|
||||
// look for a go.work file
|
||||
// otherwise use ~/go/src
|
||||
func (f *Forge) findGoSrc() (string, error) {
|
||||
|
|
53
goSrcScan.go
53
goSrcScan.go
|
@ -30,7 +30,7 @@ func (f *Forge) ScanGoSrc() (bool, error) {
|
|||
}
|
||||
gopaths = append(gopaths, gopath)
|
||||
} else {
|
||||
log.Log(FORGEPBWARN, "ScanGoSrc() bad:", dir)
|
||||
log.Log(WARN, "ScanGoSrc() bad:", dir)
|
||||
return false, errors.New("forgepb.ScanGoSrc() bad dir: " + dir)
|
||||
}
|
||||
}
|
||||
|
@ -41,11 +41,18 @@ func (f *Forge) ScanGoSrc() (bool, error) {
|
|||
}
|
||||
if newcount != 0 {
|
||||
log.Info("forge go src scan found", newcount, "repos")
|
||||
f.Repos.ConfigSave()
|
||||
f.SetConfigSave(true)
|
||||
}
|
||||
return true, err
|
||||
}
|
||||
|
||||
func (f *Forge) ScanDir(dir string) *gitpb.Repo {
|
||||
// repo, err := f.NewGoRepo(gopath, "")
|
||||
repo, err := f.Repos.NewGoRepo(dir, "")
|
||||
log.Info("need to implement ScanDir()", dir, err)
|
||||
return repo
|
||||
}
|
||||
|
||||
// doesn't enter the directory any further when it finds a .git/
|
||||
// not stupid like my old version
|
||||
func gitDirectoriesNew(srcDir string) ([]string, error) {
|
||||
|
@ -106,7 +113,7 @@ func gitDirectoriesOld(srcDir string) ([]string, error) {
|
|||
var all []string
|
||||
err := filepath.Walk(srcDir, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
log.Log(FORGEPBWARN, "Error accessing path:", path, err)
|
||||
log.Log(WARN, "Error accessing path:", path, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -119,7 +126,7 @@ func gitDirectoriesOld(srcDir string) ([]string, error) {
|
|||
})
|
||||
|
||||
if err != nil {
|
||||
log.Log(FORGEPBWARN, "Error walking the path:", srcDir, err)
|
||||
log.Log(WARN, "Error walking the path:", srcDir, err)
|
||||
}
|
||||
|
||||
return all, err
|
||||
|
@ -160,44 +167,10 @@ func (f *Forge) rillScanDirs(gopaths []string) (int, error) {
|
|||
|
||||
func (f *Forge) checkpath(gopath string, url string) (*gitpb.Repo, error) {
|
||||
fullpath := filepath.Join(f.GetGoSrc(), gopath)
|
||||
log.Info("checkpath()", gopath, fullpath)
|
||||
log.Info("forge creating protobuf for", fullpath)
|
||||
repo, err := f.NewGoRepo(gopath, "")
|
||||
if err != nil {
|
||||
log.Info("checkpath()", gopath, err)
|
||||
log.Info("\tprotobuf error", gopath, err)
|
||||
}
|
||||
return repo, err
|
||||
}
|
||||
|
||||
func (f *Forge) RillRedoGoMod() int {
|
||||
var all []*gitpb.Repo
|
||||
tmp := f.Repos.SortByFullPath()
|
||||
for tmp.Scan() {
|
||||
repo := tmp.Next()
|
||||
if !repo.IsValidDir() {
|
||||
log.Printf("%10s %-50s", "why am I in RillRedoGoMod? old?", repo.GetGoPath())
|
||||
continue
|
||||
}
|
||||
all = append(all, repo)
|
||||
}
|
||||
// Convert a slice of user IDs into a channel
|
||||
ids := rill.FromSlice(all, nil)
|
||||
|
||||
var counter int
|
||||
// Read users from the API.
|
||||
// Concurrency = 20
|
||||
dirs := rill.Map(ids, 50, func(id *gitpb.Repo) (*gitpb.Repo, error) {
|
||||
return id, nil
|
||||
})
|
||||
|
||||
err := rill.ForEach(dirs, 20, func(repo *gitpb.Repo) error {
|
||||
counter += 1
|
||||
// repo.RedoGoMod()
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
log.Info("rill.ForEach() error:", err)
|
||||
}
|
||||
|
||||
return counter
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// Copyright 2025 WIT.COM Inc Licensed GPL 3.0
|
||||
|
||||
package forgepb
|
||||
|
||||
import (
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
// Copyright 1994-2025 WIT.COM Inc Licensed GPL 3.0
|
||||
|
||||
package forgepb
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os/user"
|
||||
|
||||
"go.wit.com/log"
|
||||
)
|
||||
|
||||
/*
|
||||
func (f *Forge) HttpPostMachine(url string) ([]byte, error) {
|
||||
if f.Machine == nil {
|
||||
// run f.InitMachine() here?
|
||||
log.Info("you must run f.InitMachine()")
|
||||
return nil, fmt.Errorf("you must run f.InitMachine()")
|
||||
}
|
||||
if f.Machine.Hostname == "" {
|
||||
log.Info("WTF. hostname is blank")
|
||||
} else {
|
||||
log.Info("GOOD. hostname is set to", f.Machine.Hostname)
|
||||
}
|
||||
log.Info("GOOD2. hostname is set to", f.Machine.Hostname)
|
||||
msg, err := f.Machine.Marshal()
|
||||
if err != nil {
|
||||
log.Info("proto.Marshal() failed:", err)
|
||||
return nil, err
|
||||
}
|
||||
log.Info("GOOD3. hostname is set to", f.Machine.Hostname)
|
||||
|
||||
check := new(zoopb.Machine)
|
||||
check.Unmarshal(msg)
|
||||
if check == nil {
|
||||
log.Info("WTF. check == nil")
|
||||
}
|
||||
log.Info("good? check.hostname =", check.Hostname)
|
||||
return f.HttpPost(url, msg)
|
||||
}
|
||||
*/
|
||||
|
||||
func (f *Forge) HttpPost(url string, data []byte) ([]byte, error) {
|
||||
var err error
|
||||
var req *http.Request
|
||||
|
||||
req, err = http.NewRequest(http.MethodPost, url, bytes.NewBuffer(data))
|
||||
// log.Info("httpPost() with len", len(data), "url", url)
|
||||
|
||||
usr, _ := user.Current()
|
||||
req.Header.Set("author", usr.Username)
|
||||
/*
|
||||
if f.Machine == nil {
|
||||
// run f.InitMachine() here?
|
||||
log.Info("you must run f.InitMachine()")
|
||||
return nil, fmt.Errorf("you must run f.InitMachine()")
|
||||
}
|
||||
*/
|
||||
req.Header.Set("hostname", "fixme:hostname")
|
||||
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return []byte("client.Do(req) error"), err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
// log.Info("httpPost() with len", len(data))
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return body, err
|
||||
}
|
||||
|
||||
return body, nil
|
||||
}
|
14
human.go
14
human.go
|
@ -1,3 +1,5 @@
|
|||
// Copyright 2025 WIT.COM Inc Licensed GPL 3.0
|
||||
|
||||
package forgepb
|
||||
|
||||
import (
|
||||
|
@ -33,6 +35,18 @@ func (f *Forge) standardHeader(r *ForgeConfig) string {
|
|||
} else {
|
||||
readonly = "r/w"
|
||||
}
|
||||
if r.MasterBranchName != "" {
|
||||
flags += "(master=" + r.MasterBranchName + ") "
|
||||
}
|
||||
if r.DevelBranchName != "" {
|
||||
flags += "(devel=" + r.DevelBranchName + ") "
|
||||
}
|
||||
if r.UserBranchName != "" {
|
||||
flags += "(user=" + r.UserBranchName + ") "
|
||||
}
|
||||
if r.DebName != "" {
|
||||
flags += "(deb=" + r.DebName + ") "
|
||||
}
|
||||
return fmt.Sprintf("%-4s %-40s %s", readonly, r.GoPath, flags)
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
// Copyright 2025 WIT.COM Inc Licensed GPL 3.0
|
||||
|
||||
package forgepb
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"go.wit.com/lib/gui/shell"
|
||||
"go.wit.com/lib/protobuf/gitpb"
|
||||
"go.wit.com/log"
|
||||
)
|
||||
|
||||
func (f *Forge) HumanPrintRepo(check *gitpb.Repo) {
|
||||
if check == nil {
|
||||
log.Info("forge: you sent me nil")
|
||||
return
|
||||
}
|
||||
|
||||
if check.GetTargetVersion() == "" {
|
||||
log.Info("TargetVersion == blank")
|
||||
}
|
||||
if check.GetTargetVersion() == check.GetCurrentVersion() {
|
||||
log.Info("IsReleased() == true. do not release this a second time")
|
||||
} else {
|
||||
log.Info("IsReleased() == false")
|
||||
}
|
||||
if check.CheckDirty() {
|
||||
log.Info("CheckDirty() == true. do not release dirty repos")
|
||||
} else {
|
||||
log.Info("CheckDirty() == false")
|
||||
}
|
||||
if check.GetGoPrimitive() {
|
||||
log.Info("IsPrimitive() == true")
|
||||
} else {
|
||||
log.Info("IsPrimitive() == false")
|
||||
}
|
||||
if f.Config.IsPrivate(check.GetGoPath()) {
|
||||
log.Info("IsPrivate() == true")
|
||||
} else {
|
||||
log.Info("IsPrivate() == false")
|
||||
}
|
||||
if ok, compiled, err := check.IsProtobuf(); ok {
|
||||
log.Info(log.Sprint("IsProtobuf() == true compiled protobuf files = ", compiled))
|
||||
if err != nil {
|
||||
log.Info("IsProtobuf() ERROR = ", err)
|
||||
}
|
||||
for _, s := range compiled {
|
||||
log.Info("\tcompiled file found:", s)
|
||||
}
|
||||
} else {
|
||||
log.Info("IsProtobuf() == false")
|
||||
if err != nil {
|
||||
log.Info("IsProtobuf() ERROR = ", err)
|
||||
}
|
||||
}
|
||||
log.Info("git master name ==", check.GetMasterBranchName())
|
||||
log.Info("git devel name ==", check.GetDevelBranchName())
|
||||
log.Info("git user name ==", check.GetUserBranchName())
|
||||
log.Info("git current name ==", check.GetCurrentBranchName())
|
||||
|
||||
// testNext(check)
|
||||
|
||||
found := new(gitpb.Repos)
|
||||
if !found.AppendByGoPath(check) {
|
||||
log.Info("forgepb check. repo already existed", check.FullPath, check.GetGoPath())
|
||||
} else {
|
||||
log.Info("forgepb check. repo was new", check.FullPath, check.GetGoPath())
|
||||
}
|
||||
f.PrintHumanTable(found)
|
||||
|
||||
printTime("Last Pull", check.Times.LastPull.AsTime())
|
||||
printTime("Last Dirty", check.Times.LastDirty.AsTime())
|
||||
printTime("dir mtime", check.Times.MtimeDir.AsTime())
|
||||
printTime("HEAD mtime", check.Times.MtimeHead.AsTime())
|
||||
printTime("Index mtime", check.Times.MtimeIndex.AsTime())
|
||||
printTime("fetch", check.Times.MtimeFetch.AsTime())
|
||||
printTime("last go.sum", check.Times.LastGoDep.AsTime())
|
||||
printTime("last commit", check.Times.NewestCommit.AsTime())
|
||||
|
||||
now := time.Now()
|
||||
dur := now.Sub(check.Times.LastUpdate.AsTime())
|
||||
log.Printf("Repo Last Reload: %s\n", shell.FormatDuration(dur))
|
||||
}
|
||||
|
||||
func (f *Forge) testGoRepo(check *gitpb.Repo) {
|
||||
data, _ := os.ReadFile(filepath.Join(check.FullPath, "go.mod"))
|
||||
log.Info(string(data))
|
||||
|
||||
if err := f.FinalGoDepsCheckOk(check, true); err == nil {
|
||||
log.Info("forge.FinalGoDepsCheck(check) worked!")
|
||||
} else {
|
||||
log.Info("forge.FinalGoDepsCheck(check) failed. boo.")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func printTime(s string, t time.Time) {
|
||||
now := time.Now()
|
||||
dur := now.Sub(t)
|
||||
if dur < (time.Hour * 24) {
|
||||
log.Printf("%s mtime last changed %s\n", s, shell.FormatDuration(dur))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,245 @@
|
|||
// Copyright 2025 WIT.COM Inc Licensed GPL 3.0
|
||||
|
||||
package forgepb
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
"go.wit.com/lib/gui/shell"
|
||||
"go.wit.com/lib/protobuf/gitpb"
|
||||
"go.wit.com/log"
|
||||
)
|
||||
|
||||
// you can replace all of COBOL with this amount of GO
|
||||
|
||||
// ah yes, COBOL. what an ancient throwback. for those that know
|
||||
// then you know exactly what is in this file. For those that don't, here it is:
|
||||
|
||||
// All this does is output human readable text formatted to be viewable on
|
||||
// a console with a fixed with font. AKA: a typerwriter. Which is exactly
|
||||
// what COBOL did in the 1970's (60s? notsure) And the 80s.
|
||||
|
||||
// So, you want to dump out stuff on the console. Let's see. Something like
|
||||
|
||||
/*
|
||||
forge --favorites
|
||||
|
||||
go.wit.com/apps/myapp v0.2.0 (installed)
|
||||
go.wit.com/lib/somethingfun v0.0.7 (not downloaded)
|
||||
*/
|
||||
|
||||
// anyway, you get the idea. This is also called COBOL because it does on
|
||||
// thing and truncates every line output to the columns you see with stty -a
|
||||
// my monitor is huge, so it's not going to work at 80x24. 160x48 is better
|
||||
// actually, I'd predict some of these will probably end up 240 wide
|
||||
// long live good eyesight and 4K monitors!
|
||||
|
||||
func (f *Forge) PrintHumanTable(allr *gitpb.Repos) {
|
||||
log.DaemonMode(true)
|
||||
|
||||
var count int
|
||||
// log.Info(standardStart5("gopath", "cur name", "master", "user", "repo type"))
|
||||
log.Info(standardTable10("repopath", "cur br", "age", "master", "devel", "user", "curver", "lasttag", "next", "repo type"))
|
||||
all := allr.SortByFullPath()
|
||||
for all.Scan() {
|
||||
repo := all.Next()
|
||||
f.printRepoToTable(repo)
|
||||
count += 1
|
||||
}
|
||||
log.Info("Total git repositories:", count)
|
||||
}
|
||||
|
||||
// also shows which files are dirty
|
||||
func (f *Forge) PrintHumanTableDirty(allr *gitpb.Repos) {
|
||||
log.DaemonMode(true)
|
||||
|
||||
var count int
|
||||
// log.Info(standardStart5("gopath", "cur name", "master", "user", "repo type"))
|
||||
log.Info(standardTable10("repopath", "cur br", "age", "master", "devel", "user", "curver", "lasttag", "next", "repo type"))
|
||||
// all := allr.SortByFullPath()
|
||||
all := allr.All()
|
||||
for all.Scan() {
|
||||
repo := all.Next()
|
||||
f.printRepoToTable(repo)
|
||||
if len(repo.DirtyList) != 0 {
|
||||
for _, line := range repo.DirtyList {
|
||||
log.Info("\t", line)
|
||||
}
|
||||
}
|
||||
var mver string = repo.GetMasterVersion()
|
||||
repo.Tags.GetAge(mver)
|
||||
|
||||
count += 1
|
||||
}
|
||||
log.Info("Total git repositories:", count)
|
||||
}
|
||||
|
||||
func standardTable5(arg1, arg2, arg3, arg4, arg5 string) string {
|
||||
len1 := 40
|
||||
len2 := 12
|
||||
len3 := 12
|
||||
len4 := 16
|
||||
len5 := 8
|
||||
var s string
|
||||
if len(arg1) > len1 {
|
||||
arg1 = arg1[:len1]
|
||||
}
|
||||
s = "%-" + fmt.Sprintf("%d", len1) + "s "
|
||||
if len(arg2) > len2 {
|
||||
arg2 = arg2[:len2]
|
||||
}
|
||||
s += "%-" + fmt.Sprintf("%d", len2) + "s "
|
||||
if len(arg3) > len3 {
|
||||
arg3 = arg3[:len3]
|
||||
}
|
||||
s += "%-" + fmt.Sprintf("%d", len3) + "s "
|
||||
if len(arg4) > len4 {
|
||||
arg4 = arg4[:len4]
|
||||
}
|
||||
s += "%-" + fmt.Sprintf("%d", len4) + "s "
|
||||
if len(arg5) > len5 {
|
||||
arg5 = arg5[:len5]
|
||||
}
|
||||
s += "%-" + fmt.Sprintf("%d", len5) + "s"
|
||||
return fmt.Sprintf(s, arg1, arg2, arg3, arg4, arg5)
|
||||
}
|
||||
|
||||
func standardTable10(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10 string) string {
|
||||
len1 := 40
|
||||
len2 := 12
|
||||
len3 := 6
|
||||
len4 := 12
|
||||
len5 := 16
|
||||
len6 := 16
|
||||
len7 := 16
|
||||
len8 := 12
|
||||
len9 := 12
|
||||
len10 := 8
|
||||
var s string
|
||||
if len(arg1) > len1 {
|
||||
arg1 = arg1[:len1]
|
||||
}
|
||||
s = "%-" + fmt.Sprintf("%d", len1) + "s "
|
||||
if len(arg2) > len2 {
|
||||
arg2 = arg2[:len2]
|
||||
}
|
||||
s += "%-" + fmt.Sprintf("%d", len2) + "s "
|
||||
if len(arg3) > len3 {
|
||||
arg3 = arg3[:len3]
|
||||
}
|
||||
s += "%-" + fmt.Sprintf("%d", len3) + "s "
|
||||
if len(arg4) > len4 {
|
||||
arg4 = arg4[:len4]
|
||||
}
|
||||
s += "%-" + fmt.Sprintf("%d", len4) + "s "
|
||||
|
||||
if len(arg5) > len5 {
|
||||
arg5 = arg5[:len5]
|
||||
}
|
||||
s += "%-" + fmt.Sprintf("%d", len5) + "s "
|
||||
|
||||
if len(arg6) > len6 {
|
||||
arg6 = arg6[:len6]
|
||||
}
|
||||
s += "%-" + fmt.Sprintf("%d", len6) + "s "
|
||||
|
||||
if len(arg7) > len7 {
|
||||
arg7 = arg7[:len7]
|
||||
}
|
||||
s += "%-" + fmt.Sprintf("%d", len7) + "s "
|
||||
|
||||
if len(arg8) > len8 {
|
||||
arg8 = arg8[:len8]
|
||||
}
|
||||
s += "%-" + fmt.Sprintf("%d", len8) + "s "
|
||||
|
||||
if len(arg9) > len9 {
|
||||
arg9 = arg9[:len9]
|
||||
}
|
||||
s += "%-" + fmt.Sprintf("%d", len9) + "s "
|
||||
|
||||
if len(arg10) > len10 {
|
||||
arg10 = arg10[:len10]
|
||||
}
|
||||
s += "%-" + fmt.Sprintf("%d", len10) + "s "
|
||||
|
||||
return fmt.Sprintf(s, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10)
|
||||
}
|
||||
|
||||
func (f *Forge) printRepoToTable(repo *gitpb.Repo) {
|
||||
var end string
|
||||
|
||||
// shortened version numbers
|
||||
var mhort string = repo.GetMasterVersion()
|
||||
var dhort string = repo.GetDevelVersion()
|
||||
var uhort string = repo.GetUserVersion()
|
||||
if uhort == "uerr" {
|
||||
// blank these out
|
||||
uhort = ""
|
||||
}
|
||||
var lasttag string = repo.GetLastTag()
|
||||
var thort string = repo.GetTargetVersion()
|
||||
var chort string = repo.GetCurrentBranchVersion()
|
||||
var cname string = repo.GetCurrentBranchName()
|
||||
|
||||
var gopath string = repo.GetGoPath()
|
||||
var rtype string = repo.GetRepoType()
|
||||
|
||||
// ctime := repo.Tags.GetAge(mhort)
|
||||
// age := shell.FormatDuration(time.Since(ctime))
|
||||
age := shell.FormatDuration(repo.BranchAge(cname))
|
||||
|
||||
if f.Config.IsReadOnly(repo.GetGoPath()) {
|
||||
// end += "(readonly) "
|
||||
} else {
|
||||
end += "(rw) "
|
||||
}
|
||||
|
||||
if repo.IsDirty() {
|
||||
age = ""
|
||||
end += "(dirty) "
|
||||
}
|
||||
|
||||
start := standardTable10(gopath, cname, age, mhort, dhort, uhort, chort, lasttag, thort, rtype)
|
||||
|
||||
if rtype == "protobuf" {
|
||||
if repo.GoInfo.GoBinary {
|
||||
end += "(binary) "
|
||||
}
|
||||
}
|
||||
|
||||
if repo.GetMasterBranchName() != "master" && repo.GetMasterBranchName() != "main" {
|
||||
end += "(m:" + repo.GetMasterBranchName() + ") "
|
||||
}
|
||||
|
||||
if repo.GetDevelBranchName() != "devel" {
|
||||
end += "(d:" + repo.GetDevelBranchName() + ") "
|
||||
}
|
||||
|
||||
if repo.GetUserBranchName() != f.Config.Username {
|
||||
end += "(u:" + repo.GetUserBranchName() + ") "
|
||||
}
|
||||
|
||||
debname := f.Config.DebName(repo.GetGoPath())
|
||||
if debname != filepath.Base(gopath) {
|
||||
end += "(deb:" + debname + ") "
|
||||
}
|
||||
|
||||
switch repo.GetState() {
|
||||
case "PERFECT":
|
||||
case "unchanged":
|
||||
case "dirty":
|
||||
case "unknown branches":
|
||||
if repo.CurrentTag == nil {
|
||||
end += "(" + repo.GetState() + ") "
|
||||
} else {
|
||||
end += "(unknown branch " + repo.CurrentTag.Refname + ") "
|
||||
}
|
||||
// end += "(invalid tag) "
|
||||
default:
|
||||
end += "(" + repo.GetState() + ") "
|
||||
}
|
||||
|
||||
log.Info(start, end)
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package forgepb
|
||||
|
||||
import (
|
||||
"go.wit.com/log"
|
||||
)
|
||||
|
||||
// print the protobuf in human form
|
||||
func IdentifyProtobuf(data []byte) error {
|
||||
var pb *Identify
|
||||
pb = new(Identify)
|
||||
if err := pb.Unmarshal(data); err != nil {
|
||||
log.Info("data can't be identified as a standard protobuf. len =", len(data))
|
||||
return err
|
||||
}
|
||||
log.Info("Identify protobuf file uuid =", pb.Uuid, "version =", pb.Version)
|
||||
return nil
|
||||
}
|
108
init.go
108
init.go
|
@ -1,3 +1,5 @@
|
|||
// Copyright 2025 WIT.COM Inc Licensed GPL 3.0
|
||||
|
||||
package forgepb
|
||||
|
||||
import (
|
||||
|
@ -8,7 +10,6 @@ import (
|
|||
|
||||
"go.wit.com/lib/gui/shell"
|
||||
"go.wit.com/lib/protobuf/gitpb"
|
||||
"go.wit.com/lib/protobuf/zoopb"
|
||||
"go.wit.com/log"
|
||||
)
|
||||
|
||||
|
@ -18,40 +19,63 @@ import (
|
|||
func Init() *Forge {
|
||||
f := InitPB()
|
||||
|
||||
/*
|
||||
f.Machine = new(zoopb.Machine)
|
||||
|
||||
if err := f.Machine.ConfigLoad(); err != nil {
|
||||
log.Warn("zoopb.ConfigLoad() failed", err)
|
||||
log.Log(WARN, "zoopb.ConfigLoad() failed", err)
|
||||
}
|
||||
*/
|
||||
if f.Config.Username == "" {
|
||||
usr, _ := user.Current()
|
||||
f.Config.Username = usr.Username
|
||||
f.SetConfigSave(true)
|
||||
}
|
||||
f.Machine.InitWit()
|
||||
|
||||
if f.Config.Xterm == "" {
|
||||
f.Config.Xterm = "xterm"
|
||||
f.Config.XtermArgv = append(f.Config.XtermArgv, "-bg")
|
||||
f.Config.XtermArgv = append(f.Config.XtermArgv, "black")
|
||||
f.Config.XtermArgv = append(f.Config.XtermArgv, "-fg")
|
||||
f.Config.XtermArgv = append(f.Config.XtermArgv, "white")
|
||||
f.SetConfigSave(true)
|
||||
}
|
||||
|
||||
// f.Machine.InitWit()
|
||||
|
||||
if f.hasFullScan {
|
||||
// duplicate time checking below. which one to keep?
|
||||
if f.FullScanAge() > time.Minute {
|
||||
log.Log(INFO, "forgepb.Scan() skipping scan. been run a minute ago", f.FullScanAge())
|
||||
return f
|
||||
}
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
start := f.Repos.Len()
|
||||
f.ScanGoSrc()
|
||||
f.FullScanRan()
|
||||
end := f.Repos.Len()
|
||||
if (end - start) == 0 {
|
||||
log.Info("forgepb.Scan() Scan did not find new git repositories. Total =", end)
|
||||
log.Log(INFO, "forgepb.Scan() Scan did not find new git repositories. Total =", end)
|
||||
if f.FullScanAge() > time.Minute {
|
||||
f.rillUpdate(20, 10)
|
||||
}
|
||||
} else {
|
||||
log.Info("forgepb.Scan() Scan found", end-start, "new git repositories. Total =", end)
|
||||
log.Log(INFO, "forgepb.Scan() Scan found", end-start, "new git repositories. Total =", end)
|
||||
f.rillUpdate(20, 10)
|
||||
}
|
||||
|
||||
f.rillUpdate(20, 10)
|
||||
|
||||
if f.configSave {
|
||||
// taking this out to debug Marshal() panic
|
||||
// os.Exit(-1)
|
||||
f.ConfigSave()
|
||||
f.configSave = false
|
||||
}
|
||||
log.Info("update() check took", shell.FormatDuration(time.Since(now)))
|
||||
log.Log(INFO, "update() check took", shell.FormatDuration(time.Since(now)))
|
||||
return f
|
||||
}
|
||||
|
||||
// only init's the protobuf. intended to not scan or change anything
|
||||
func InitPB() *Forge {
|
||||
func DetermineGoPath() *Forge {
|
||||
f := new(Forge)
|
||||
|
||||
// TODO: rethink this but it works for now
|
||||
|
@ -59,7 +83,7 @@ func InitPB() *Forge {
|
|||
if gosrc == "" {
|
||||
goSrcDir, err := f.findGoSrc()
|
||||
if err != nil {
|
||||
log.Warn("forge init() findGoSrc()", err)
|
||||
log.Log(WARN, "forge init() findGoSrc()", err)
|
||||
}
|
||||
os.Setenv("FORGE_GOSRC", goSrcDir)
|
||||
}
|
||||
|
@ -72,27 +96,73 @@ func InitPB() *Forge {
|
|||
os.Setenv("FORGE_CONFIG", fullpath)
|
||||
}
|
||||
|
||||
f.configDir = os.Getenv("FORGE_CONFIG")
|
||||
|
||||
// check again for go.work // user could have a go.work file in ~/go/src
|
||||
if f.goWorkExists() {
|
||||
f.goWork = true
|
||||
}
|
||||
|
||||
// print out the settings that will be used
|
||||
log.Info("forgepb.Init() FORGE_CONFIG", os.Getenv("FORGE_CONFIG"))
|
||||
log.Log(INFO, "forgepb.Init() FORGE_CONFIG", os.Getenv("FORGE_CONFIG"))
|
||||
|
||||
return f
|
||||
}
|
||||
|
||||
func (f *Forge) InitPB() {
|
||||
// load the ~/.config/forge/ config
|
||||
f.Config = new(ForgeConfigs)
|
||||
if err := f.Config.ConfigLoad(); err != nil {
|
||||
log.Warn("forgepb.ConfigLoad() failed", err)
|
||||
log.Log(WARN, "forgepb.ConfigLoad() failed", err)
|
||||
}
|
||||
|
||||
if f.IsGoWork() {
|
||||
log.Info("forgepb.Init() FORGE_GOSRC ", os.Getenv("FORGE_GOSRC"), "(go.work = true)")
|
||||
log.Log(INFO, "forgepb.Init() FORGE_GOSRC ", os.Getenv("FORGE_GOSRC"), "(go.work = true)")
|
||||
} else {
|
||||
log.Info("forgepb.Init() FORGE_GOSRC ", os.Getenv("FORGE_GOSRC"), "(go.work = false)")
|
||||
log.Log(INFO, "forgepb.Init() FORGE_GOSRC ", os.Getenv("FORGE_GOSRC"), "(go.work = false)")
|
||||
}
|
||||
f.Repos = new(gitpb.Repos)
|
||||
|
||||
f.Repos = gitpb.NewRepos()
|
||||
f.Repos.ConfigLoad()
|
||||
if f.Repos.HasFullScan {
|
||||
f.hasFullScan = true
|
||||
}
|
||||
|
||||
if os.Getenv("FORGE_URL") != "" {
|
||||
forgeURL = os.Getenv("FORGE_URL")
|
||||
log.Info("got forge url", forgeURL)
|
||||
}
|
||||
}
|
||||
|
||||
func (f *Forge) InitMachine() {
|
||||
/*
|
||||
f.Machine = new(zoopb.Machine)
|
||||
if err := f.Machine.ConfigLoad(); err != nil {
|
||||
log.Log(WARN, "zoopb.ConfigLoad() failed", err)
|
||||
f.Machine.InitWit()
|
||||
}
|
||||
*/
|
||||
|
||||
if f.Config.Username == "" {
|
||||
usr, _ := user.Current()
|
||||
f.Config.Username = usr.Username
|
||||
}
|
||||
|
||||
/*
|
||||
if f.Machine.Hostname == "" {
|
||||
r, err := shell.RunVerbose([]string{"hostname", "-f"})
|
||||
if err == nil {
|
||||
tmp := strings.Join(r.Stdout, "\n")
|
||||
f.Machine.Hostname = strings.TrimSpace(tmp)
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
// only init's the protobuf. intended to not scan or change anything
|
||||
func InitPB() *Forge {
|
||||
f := DetermineGoPath()
|
||||
f.InitPB()
|
||||
return f
|
||||
}
|
||||
|
||||
|
@ -102,10 +172,10 @@ func (f *Forge) SetConfigSave(b bool) {
|
|||
|
||||
// saves the config if there have been changes
|
||||
func (f *Forge) Exit() {
|
||||
log.Info("forge.configSave =", f.configSave)
|
||||
// log.Info("forge.configSave =", f.configSave)
|
||||
if f.configSave {
|
||||
f.ConfigSave()
|
||||
}
|
||||
log.Info("forge.Exit() ok")
|
||||
// log.Info("forge.Exit() ok")
|
||||
os.Exit(0)
|
||||
}
|
||||
|
|
8
log.go
8
log.go
|
@ -4,13 +4,13 @@ import (
|
|||
"go.wit.com/log"
|
||||
)
|
||||
|
||||
var FORGEPB *log.LogFlag
|
||||
var FORGEPBWARN *log.LogFlag
|
||||
var INFO *log.LogFlag
|
||||
var WARN *log.LogFlag
|
||||
|
||||
func init() {
|
||||
full := "go.wit.com/lib/protobuf/forgepb"
|
||||
short := "forgepb"
|
||||
|
||||
FORGEPB = log.NewFlag("FORGEPB", false, full, short, "general forgepb things")
|
||||
FORGEPBWARN = log.NewFlag("FORGEPBWARN", true, full, short, "forgepb warnings")
|
||||
INFO = log.NewFlag("INFO", false, full, short, "general forgepb things")
|
||||
WARN = log.NewFlag("WARN", true, full, short, "forgepb warnings")
|
||||
}
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
// Copyright 1994-2025 WIT.COM Inc Licensed GPL 3.0
|
||||
|
||||
package forgepb
|
||||
|
||||
// TODO: implement i18n with the protobuf's
|
||||
func (f *Forge) GetMode() string {
|
||||
switch f.Config.Mode {
|
||||
case ForgeMode_MASTER:
|
||||
return "Release Mode (master branch)"
|
||||
case ForgeMode_DEVEL:
|
||||
return "Patch Mode (devel branch)"
|
||||
case ForgeMode_USER:
|
||||
return "Hack Mode (user branch)"
|
||||
default:
|
||||
return f.Config.Mode.String()
|
||||
}
|
||||
}
|
166
patch.Make.go
166
patch.Make.go
|
@ -1,166 +0,0 @@
|
|||
package forgepb
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"go.wit.com/lib/protobuf/gitpb"
|
||||
"go.wit.com/log"
|
||||
)
|
||||
|
||||
func (f *Forge) MakeDevelPatchSet() (*Patchs, error) {
|
||||
pset := new(Patchs)
|
||||
dir, err := os.MkdirTemp("", "forge")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer os.RemoveAll(dir) // clean up
|
||||
pset.TmpDir = dir
|
||||
|
||||
all := f.Repos.SortByFullPath()
|
||||
for all.Scan() {
|
||||
repo := all.Next()
|
||||
userb := repo.GetUserBranchName()
|
||||
develb := repo.GetDevelBranchName()
|
||||
|
||||
if develb == "" {
|
||||
continue
|
||||
}
|
||||
if userb == "" {
|
||||
continue
|
||||
}
|
||||
pset.StartBranchName = develb
|
||||
pset.EndBranchName = userb
|
||||
err := pset.makePatchSetNew(repo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return pset, nil
|
||||
}
|
||||
|
||||
func (f *Forge) MakeMasterPatchSet() (*Patchs, error) {
|
||||
pset := new(Patchs)
|
||||
dir, err := os.MkdirTemp("", "forge")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer os.RemoveAll(dir) // clean up
|
||||
pset.TmpDir = dir
|
||||
|
||||
all := f.Repos.SortByFullPath()
|
||||
for all.Scan() {
|
||||
repo := all.Next()
|
||||
startb := repo.GetMasterBranchName()
|
||||
endb := repo.GetUserBranchName()
|
||||
|
||||
if startb == "" {
|
||||
continue
|
||||
}
|
||||
if endb == "" {
|
||||
continue
|
||||
}
|
||||
// log.Info("repo", repo.GetGoPath(), startb, "..", endb)
|
||||
pset.StartBranchName = startb
|
||||
pset.EndBranchName = endb
|
||||
err := pset.makePatchSetNew(repo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return pset, nil
|
||||
}
|
||||
|
||||
func (pset *Patchs) makePatchSetNew(repo *gitpb.Repo) error {
|
||||
startBranch := pset.StartBranchName
|
||||
endBranch := pset.EndBranchName
|
||||
repoDir := filepath.Join(pset.TmpDir, repo.GetGoPath())
|
||||
err := os.MkdirAll(repoDir, 0755)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// git format-patch branch1..branch2
|
||||
cmd := []string{"git", "format-patch", "-o", repoDir, startBranch + ".." + endBranch}
|
||||
r := repo.Run(cmd)
|
||||
if r.Error != nil {
|
||||
log.Info("git format-patch", repo.FullPath)
|
||||
log.Info("git format-patch", cmd)
|
||||
log.Info("git format-patch error", r.Error)
|
||||
return r.Error
|
||||
}
|
||||
if r.Exit != 0 {
|
||||
log.Info("git format-patch", repo.FullPath)
|
||||
log.Info("git format-patch", cmd)
|
||||
log.Info("git format-patch exit", r.Exit)
|
||||
return errors.New(fmt.Sprintf("git returned %d", r.Exit))
|
||||
}
|
||||
if len(r.Stdout) == 0 {
|
||||
// git created no files to add
|
||||
return nil
|
||||
}
|
||||
|
||||
return pset.addPatchFiles(repo.GetGoPath())
|
||||
}
|
||||
|
||||
// process each file in pDir/
|
||||
func (p *Patchs) addPatchFiles(psetDir string) error {
|
||||
tmpDir := p.TmpDir
|
||||
log.Info("ADD PATCH FILES ADDED DIR", tmpDir)
|
||||
fullDir := filepath.Join(tmpDir, psetDir)
|
||||
var baderr error
|
||||
filepath.Walk(fullDir, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
// Handle possible errors, like permission issues
|
||||
fmt.Fprintf(os.Stderr, "error accessing path %q: %v\n", path, err)
|
||||
baderr = err
|
||||
return err
|
||||
}
|
||||
|
||||
if info.IsDir() {
|
||||
return nil
|
||||
}
|
||||
log.Info("IS THIS A FULL PATH ?", path)
|
||||
log.Info("trim this from path ?", fullDir)
|
||||
log.Info("trim this from path ?", psetDir)
|
||||
log.Info("trim this from path ?", tmpDir)
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
log.Info("addPatchFile() failed", path)
|
||||
baderr = err
|
||||
return err
|
||||
}
|
||||
patch := new(Patch)
|
||||
patch.Filename, _ = filepath.Rel(p.TmpDir, path)
|
||||
patch.Data = data
|
||||
p.Patchs = append(p.Patchs, patch)
|
||||
log.Info("ADDED PATCH FILE", path)
|
||||
return nil
|
||||
})
|
||||
return baderr
|
||||
}
|
||||
|
||||
// just an example of how to walk only directories
|
||||
func onlyWalkDirs(pDir string) error {
|
||||
log.Info("DIR", pDir)
|
||||
// var all []string
|
||||
var baderr error
|
||||
filepath.WalkDir(pDir, func(path string, d os.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
// Handle possible errors, like permission issues
|
||||
fmt.Fprintf(os.Stderr, "error accessing path %q: %v\n", path, err)
|
||||
baderr = err
|
||||
return err
|
||||
}
|
||||
|
||||
log.Info("TESTING DIR", path)
|
||||
if d.IsDir() {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
log.Info("NEVER GETS HERE? WHAT IS THIS?", path)
|
||||
return nil
|
||||
})
|
||||
return baderr
|
||||
}
|
30
patch.proto
30
patch.proto
|
@ -1,30 +0,0 @@
|
|||
syntax = "proto3";
|
||||
|
||||
package forgepb;
|
||||
|
||||
import "google/protobuf/timestamp.proto"; // Import the well-known type for Timestamp
|
||||
|
||||
message Patch {
|
||||
string filename = 1; // `autogenpb:unique`
|
||||
bytes data = 2; //
|
||||
string repoPath = 3; // path to the git repo
|
||||
string branchName = 4; //
|
||||
string branchHash = 5; //
|
||||
google.protobuf.Timestamp ctime = 7; // the git commit timestamp of the version
|
||||
}
|
||||
|
||||
message Patchs { // `autogenpb:marshal`
|
||||
string uuid = 1; // `autogenpb:uuid:0703df95-6a38-4422-994b-c55d3d6001f9` // todo: add file support
|
||||
string version = 2; // could be used for protobuf schema change violations?
|
||||
repeated Patch Patchs = 3;
|
||||
string name = 4; //
|
||||
string comment = 5; //
|
||||
string gitAuthorName = 6; //
|
||||
string gitAuthorEmail = 7; //
|
||||
google.protobuf.Timestamp ctime = 8; // create time of this patchset
|
||||
string tmpDir = 9; // temp dir
|
||||
string startBranchName = 10; //
|
||||
string endBranchName = 11; //
|
||||
string startBranchHash = 12; //
|
||||
string endBranchHash = 13; //
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
// Copyright 1994-2025 WIT.COM Inc Licensed GPL 3.0
|
||||
|
||||
package forgepb
|
||||
|
||||
import (
|
||||
"go.wit.com/log"
|
||||
)
|
||||
|
||||
var forgeURL string = "https://go.wit.com/"
|
||||
|
||||
func (f *Forge) GetPatchesets() (*Patchsets, error) {
|
||||
url := forgeURL + "GetPatchsets"
|
||||
log.Info("GetPatchsets() url", url)
|
||||
body, err := f.HttpPost(url, nil)
|
||||
if err != nil {
|
||||
log.Info("httpPost() failed:", err)
|
||||
return nil, err
|
||||
}
|
||||
log.Info("GetPatchets() len(body)", len(body))
|
||||
var psets *Patchsets
|
||||
psets = new(Patchsets)
|
||||
err = psets.Unmarshal(body)
|
||||
if err != nil {
|
||||
log.Info("Unmarshal failed", err)
|
||||
return nil, err
|
||||
}
|
||||
/*
|
||||
filename := filepath.Join("/tmp", pbfile)
|
||||
f, _ := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
|
||||
f.Write(body)
|
||||
f.Close()
|
||||
*/
|
||||
return psets, nil
|
||||
}
|
|
@ -0,0 +1,272 @@
|
|||
package forgepb
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"go.wit.com/lib/protobuf/gitpb"
|
||||
"go.wit.com/log"
|
||||
timestamppb "google.golang.org/protobuf/types/known/timestamppb"
|
||||
)
|
||||
|
||||
// creates a patchset
|
||||
// works from the user branches against the devel branches
|
||||
func (f *Forge) MakeDevelPatchSet(name string) (*Patchset, error) {
|
||||
pset := new(Patchset)
|
||||
pset.Name = name
|
||||
pset.Ctime = timestamppb.New(time.Now())
|
||||
pset.Uuid = uuid.New().String()
|
||||
if os.Getenv("GIT_AUTHOR_NAME") == "" {
|
||||
return nil, fmt.Errorf("GIT_AUTHOR_NAME not set")
|
||||
} else {
|
||||
pset.GitAuthorName = os.Getenv("GIT_AUTHOR_NAME")
|
||||
}
|
||||
if os.Getenv("GIT_AUTHOR_EMAIL") == "" {
|
||||
return nil, fmt.Errorf("GIT_AUTHOR_EMAIL not set")
|
||||
} else {
|
||||
pset.GitAuthorEmail = os.Getenv("GIT_AUTHOR_EMAIL")
|
||||
}
|
||||
|
||||
dir, err := os.MkdirTemp("", "forge")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer os.RemoveAll(dir) // clean up
|
||||
pset.TmpDir = dir
|
||||
|
||||
all := f.Repos.SortByFullPath()
|
||||
for all.Scan() {
|
||||
repo := all.Next()
|
||||
|
||||
if !repo.IsLocalBranch(repo.GetUserBranchName()) {
|
||||
// log.Info("repo doesn't have user branch", repo.GetGoPath())
|
||||
continue
|
||||
}
|
||||
if !repo.IsLocalBranch(repo.GetDevelBranchName()) {
|
||||
// log.Info("repo doesn't have devel branch", repo.GetGoPath())
|
||||
continue
|
||||
}
|
||||
|
||||
// make a patchset from user to devel
|
||||
// TODO: verify branches are otherwise exact
|
||||
pset.StartBranchName = repo.GetDevelBranchName()
|
||||
pset.EndBranchName = repo.GetUserBranchName()
|
||||
|
||||
err := pset.makePatchSetNew(repo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return pset, nil
|
||||
}
|
||||
|
||||
func (f *Forge) SubmitDevelPatchSet(name string) (*Patchset, error) {
|
||||
pset, err := f.MakeDevelPatchSet(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := f.submitPatchset(pset); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return pset, nil
|
||||
}
|
||||
|
||||
func (f *Forge) MakeMasterPatchSet() (*Patchset, error) {
|
||||
pset := new(Patchset)
|
||||
dir, err := os.MkdirTemp("", "forge")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer os.RemoveAll(dir) // clean up
|
||||
pset.TmpDir = dir
|
||||
|
||||
all := f.Repos.SortByFullPath()
|
||||
for all.Scan() {
|
||||
repo := all.Next()
|
||||
startb := repo.GetMasterBranchName()
|
||||
endb := repo.GetUserBranchName()
|
||||
|
||||
if startb == "" {
|
||||
continue
|
||||
}
|
||||
if endb == "" {
|
||||
continue
|
||||
}
|
||||
// log.Info("repo", repo.GetGoPath(), startb, "..", endb)
|
||||
pset.StartBranchName = startb
|
||||
pset.EndBranchName = endb
|
||||
err := pset.makePatchSetNew(repo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return pset, nil
|
||||
}
|
||||
|
||||
func (pset *Patchset) makePatchSetNew(repo *gitpb.Repo) error {
|
||||
startBranch := pset.StartBranchName
|
||||
endBranch := pset.EndBranchName
|
||||
repoDir := filepath.Join(pset.TmpDir, repo.GetGoPath())
|
||||
err := os.MkdirAll(repoDir, 0755)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// maybe better? maybe worse?
|
||||
// git format-patch -o patches --stdout <commit-range> > my-patch.mbox
|
||||
// git format-patch --stdout -5 > my-patch.mbox # last 5 patches
|
||||
// git am < my-patch.mbox
|
||||
// git format-patch branch1..branch2
|
||||
// export GIT_COMMITTER_DATE="2024-01-01T12:00:00"
|
||||
// export GIT_AUTHOR_DATE="2024-01-01T12:00:00"
|
||||
// export GIT_COMMITTER_NAME="Your Name"
|
||||
// export GIT_COMMITTER_EMAIL="your.email@example.com"
|
||||
// export GIT_AUTHOR_NAME="Your Name"
|
||||
// export GIT_AUTHOR_EMAIL="your.email@example.com"
|
||||
// git am < patch.mbox
|
||||
|
||||
cmd := []string{"git", "format-patch", "-o", repoDir, startBranch + ".." + endBranch}
|
||||
r := repo.Run(cmd)
|
||||
if r.Error != nil {
|
||||
log.Info("git format-patch", repo.FullPath)
|
||||
log.Info("git format-patch", cmd)
|
||||
log.Info("git format-patch error", r.Error)
|
||||
return r.Error
|
||||
}
|
||||
if r.Exit != 0 {
|
||||
log.Info("git format-patch", repo.FullPath)
|
||||
log.Info("git format-patch", cmd)
|
||||
log.Info("git format-patch exit", r.Exit)
|
||||
return errors.New(fmt.Sprintf("git returned %d", r.Exit))
|
||||
}
|
||||
if len(r.Stdout) == 0 {
|
||||
// git created no files to add
|
||||
return nil
|
||||
}
|
||||
|
||||
err = pset.addPatchFiles(repo)
|
||||
pset.Ctime = timestamppb.New(time.Now())
|
||||
return err
|
||||
}
|
||||
|
||||
// process each file in pDir/
|
||||
func (p *Patchset) addPatchFiles(repo *gitpb.Repo) error {
|
||||
psetDir := repo.GetGoPath()
|
||||
tmpDir := p.TmpDir
|
||||
// log.Info("ADD PATCH FILES ADDED DIR", tmpDir)
|
||||
fullDir := filepath.Join(tmpDir, psetDir)
|
||||
var baderr error
|
||||
filepath.Walk(fullDir, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
// Handle possible errors, like permission issues
|
||||
fmt.Fprintf(os.Stderr, "error accessing path %q: %v\n", path, err)
|
||||
baderr = err
|
||||
return err
|
||||
}
|
||||
|
||||
if info.IsDir() {
|
||||
return nil
|
||||
}
|
||||
// log.Info("IS THIS A FULL PATH ?", path)
|
||||
// log.Info("trim this from path ?", fullDir)
|
||||
// log.Info("trim this from path ?", psetDir)
|
||||
// log.Info("trim this from path ?", tmpDir)
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
log.Info("addPatchFile() failed", path)
|
||||
baderr = err
|
||||
return err
|
||||
}
|
||||
patch := new(Patch)
|
||||
patch.Filename, _ = filepath.Rel(p.TmpDir, path)
|
||||
patch.Data = data
|
||||
patch.parseData()
|
||||
patch.StartHash = repo.DevelHash()
|
||||
patch.NewHash = "na"
|
||||
patch.RepoNamespace = repo.GetGoPath()
|
||||
if p.Patches == nil {
|
||||
p.Patches = new(Patches)
|
||||
}
|
||||
p.Patches.Append(patch)
|
||||
p.Patches.Uuid = uuid.New().String()
|
||||
// log.Info("ADDED PATCH FILE", path)
|
||||
return nil
|
||||
})
|
||||
return baderr
|
||||
}
|
||||
|
||||
// looks at the git format-patch output
|
||||
// saves the commit Hash
|
||||
// saves the diff lines
|
||||
func (p *Patch) parseData() string {
|
||||
lines := strings.Split(string(p.Data), "\n")
|
||||
for _, line := range lines {
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) < 2 {
|
||||
continue
|
||||
}
|
||||
switch fields[0] {
|
||||
case "From":
|
||||
p.CommitHash = fields[1]
|
||||
case "Subject:":
|
||||
p.Comment = line
|
||||
case "diff":
|
||||
p.Files = append(p.Files, line)
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// just an example of how to walk only directories
|
||||
func onlyWalkDirs(pDir string) error {
|
||||
log.Info("DIR", pDir)
|
||||
// var all []string
|
||||
var baderr error
|
||||
filepath.WalkDir(pDir, func(path string, d os.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
// Handle possible errors, like permission issues
|
||||
fmt.Fprintf(os.Stderr, "error accessing path %q: %v\n", path, err)
|
||||
baderr = err
|
||||
return err
|
||||
}
|
||||
|
||||
log.Info("TESTING DIR", path)
|
||||
if d.IsDir() {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
log.Info("NEVER GETS HERE? WHAT IS THIS?", path)
|
||||
return nil
|
||||
})
|
||||
return baderr
|
||||
}
|
||||
|
||||
func (f *Forge) submitPatchset(pset *Patchset) error {
|
||||
var url string
|
||||
url = forgeURL + "patchset"
|
||||
msg, err := pset.Marshal()
|
||||
if err != nil {
|
||||
log.Info("proto.Marshal() failed:", err)
|
||||
return err
|
||||
}
|
||||
log.Info("proto.Marshal() msg len", len(msg))
|
||||
body, err := f.HttpPost(url, msg)
|
||||
if err != nil {
|
||||
log.Info("httpPost() failed:", err)
|
||||
return err
|
||||
}
|
||||
|
||||
test := strings.TrimSpace(string(body))
|
||||
lines := strings.Split(test, "\n")
|
||||
count := 0
|
||||
for _, line := range lines {
|
||||
log.Info("got back:", line)
|
||||
count += 1
|
||||
}
|
||||
log.Info("Total patches:", count)
|
||||
return nil
|
||||
}
|
|
@ -10,7 +10,7 @@ import (
|
|||
"go.wit.com/log"
|
||||
)
|
||||
|
||||
func (f *Forge) SendPatchSet(pset *Patchs) error {
|
||||
func (f *Forge) SendPatchSet(pset *Patchset) error {
|
||||
var err error
|
||||
data, err := pset.Marshal()
|
||||
if err != nil {
|
|
@ -0,0 +1,86 @@
|
|||
// Copyright 2025 WIT.COM Inc Licensed GPL 3.0
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package forgepb;
|
||||
|
||||
import "google/protobuf/timestamp.proto"; // Import the well-known type for Timestamp
|
||||
|
||||
// Forge doesn't need this kind of specificity
|
||||
// but this is what the patch files contain and how git sees them
|
||||
// message Blob {
|
||||
// string hunkLine = 1;
|
||||
// bytes data = 2;
|
||||
// }
|
||||
//
|
||||
// message File {
|
||||
// string filename = 1;
|
||||
// string hashLine = 2;
|
||||
// repeated Blob Blobs = 3;
|
||||
// }
|
||||
//
|
||||
// message Patch {
|
||||
// repeated File Files = 1;
|
||||
// string repoNamespace = 2;
|
||||
// string gH = 3;
|
||||
// string gaI = 4;
|
||||
// string gcI = 5;
|
||||
// }
|
||||
|
||||
// git log -1 --format="%H %aI %cI %an %ae %cn %ce"
|
||||
message Patch {
|
||||
string repoNamespace = 1; // the base repo git URL
|
||||
bytes data = 2; // the raw data of the whole patch
|
||||
string gH = 3; // after some deliberation, I think I'll just try variable names
|
||||
string gT = 4;
|
||||
string gP = 5;
|
||||
string gs = 6;
|
||||
string gaI = 7; // that exactly match what git uses.
|
||||
string gan = 8;
|
||||
string gae = 9;
|
||||
string gcI = 10;
|
||||
string gcn = 11;
|
||||
string gce = 12;
|
||||
string gN = 13;
|
||||
string gGG = 14;
|
||||
string gGS = 15;
|
||||
string gGK = 16;
|
||||
string newHash = 17; // new hash
|
||||
string state = 18; // the 'state' of the patch
|
||||
string filename = 19; // `autogenpb:unique` `autogenpb:sort`
|
||||
string startHash = 20; // the start commit hash
|
||||
string commitHash = 21; // the git commit hash of this patch
|
||||
string comment = 22; // the git commit message (in patch form)
|
||||
repeated string Files = 23; // the filenames this patch changes
|
||||
google.protobuf.Timestamp ctime = 24; // create time of the patch
|
||||
bool applied = 25; // have you applied this patch?
|
||||
bool upstream = 26; // has this patch been applied upstream?
|
||||
}
|
||||
|
||||
message Patches { // this is a "PATCH: [1/x]" series `autogenpb:gui:Patch`
|
||||
string uuid = 1; // `autogenpb:uuid:be926ad9-1111-484c-adf2-d96eeabf3079`
|
||||
string version = 2; // `autogenpb:version:v0.0.45`
|
||||
repeated Patch Patches = 3;
|
||||
}
|
||||
|
||||
message Patchset { // `autogenpb:marshal`
|
||||
Patches patches = 1; //
|
||||
string name = 2; // `autogenpb:sort`
|
||||
string comment = 3; //
|
||||
string gitAuthorName = 4; // `autogenpb:sort`
|
||||
string gitAuthorEmail = 5; //
|
||||
google.protobuf.Timestamp ctime = 6; // create time of the patchset
|
||||
string tmpDir = 7; // temp dir
|
||||
string startBranchName = 8; //
|
||||
string endBranchName = 9; //
|
||||
string startBranchHash = 10; //
|
||||
string endBranchHash = 11; //
|
||||
string state = 12; // the state of the patch
|
||||
string uuid = 13; // `autogenpb:sort` `autogenpb:unique`
|
||||
}
|
||||
|
||||
message Patchsets { // `autogenpb:marshal` `autogenpb:gui`
|
||||
string uuid = 1; // `autogenpb:uuid:be926ad9-f07f-484c-adf2-d96eeabf3079`
|
||||
string version = 2; // `autogenpb:version:v0.0.45`
|
||||
repeated Patchset Patchsets = 3;
|
||||
}
|
136
repoNew.go
136
repoNew.go
|
@ -1,8 +1,12 @@
|
|||
// Copyright 2025 WIT.COM Inc Licensed GPL 3.0
|
||||
|
||||
package forgepb
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"go.wit.com/lib/protobuf/gitpb"
|
||||
|
@ -11,11 +15,17 @@ import (
|
|||
|
||||
func (f *Forge) NewGoRepo(gopath string, url string) (*gitpb.Repo, error) {
|
||||
fullpath := filepath.Join(f.GetGoSrc(), gopath)
|
||||
test := f.Repos.FindByFullPath(fullpath)
|
||||
if test != nil {
|
||||
return test, nil
|
||||
}
|
||||
repo, err := f.Repos.NewGoRepo(fullpath, gopath)
|
||||
if err != nil {
|
||||
log.Info("WARNING. NEW FAILED", fullpath)
|
||||
return nil, err
|
||||
}
|
||||
// slices.Reverse(f.Repos.Repos)
|
||||
|
||||
repo.URL = url
|
||||
f.VerifyBranchNames(repo)
|
||||
if f.Config.IsReadOnly(repo.GetGoPath()) {
|
||||
|
@ -25,10 +35,22 @@ func (f *Forge) NewGoRepo(gopath string, url string) (*gitpb.Repo, error) {
|
|||
return repo, nil
|
||||
}
|
||||
|
||||
func isValidSemVer(version string) bool {
|
||||
// Regular expression for semantic versioning
|
||||
regex := `^v(\d+)\.(\d+)\.(\d+)$`
|
||||
matched, _ := regexp.MatchString(regex, version)
|
||||
return matched
|
||||
}
|
||||
|
||||
// golang versions MUST be vX.X.X
|
||||
// it can not be vX.X and it also can not be v0.0.0
|
||||
// verifies the version is format v3.2.1
|
||||
// this is retardedly wrong. it needs to be done right
|
||||
func (f *Forge) ValidGoVersion(ver string) (bool, error) {
|
||||
return ValidGoVersion(ver)
|
||||
}
|
||||
|
||||
func ValidGoVersion(ver string) (bool, error) {
|
||||
if ver == "v0.0.0" {
|
||||
return false, fmt.Errorf("golang does not allow version v0.0.0")
|
||||
}
|
||||
|
@ -40,46 +62,97 @@ func (f *Forge) ValidGoVersion(ver string) (bool, error) {
|
|||
if len(parts) != 3 {
|
||||
return false, fmt.Errorf("(%s) invalid. golang versions must have exactly 3 numbers (v1.2.3)", ver)
|
||||
}
|
||||
if isValidSemVer(ver) {
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// figure out what the name of the git master branch is
|
||||
// also check the forge config
|
||||
func (f *Forge) findMasterBranch(repo *gitpb.Repo) {
|
||||
// check the forge config first
|
||||
if bname := f.Config.FindMasterBranch(repo.GetGoPath()); bname != "" {
|
||||
log.Info("Using master branch name from forge config:", bname)
|
||||
repo.SetMasterBranchName(bname)
|
||||
return
|
||||
}
|
||||
// todo: fix this after .git parsing is better or libgit2 is being used
|
||||
headfile := filepath.Join(repo.GetFullPath(), ".git/refs/remotes/origin/HEAD")
|
||||
if data, err := os.ReadFile(headfile); err == nil {
|
||||
s := string(data)
|
||||
if strings.HasPrefix(s, "ref: ") {
|
||||
fields := strings.Fields(s)
|
||||
_, bname := filepath.Split(fields[1])
|
||||
// log.Info("Using master branch name from .git/ HEAD:", bname)
|
||||
repo.SetMasterBranchName(bname)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// try to guess what the 'master' branch is
|
||||
if repo.IsBranch("master") {
|
||||
repo.SetMasterBranchName("master")
|
||||
return
|
||||
}
|
||||
|
||||
if repo.IsBranch("main") {
|
||||
repo.SetMasterBranchName("main")
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: figure out the name from git
|
||||
repo.SetMasterBranchName("master")
|
||||
/* no longer checkout on Init()
|
||||
if repo.CheckoutMaster() {
|
||||
} else {
|
||||
cmd := []string{"git", "branch", "master"}
|
||||
repo.Run(cmd)
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
// figure out what the name of the git devel branch is
|
||||
// also check the forge config
|
||||
func (f *Forge) findDevelBranch(repo *gitpb.Repo) {
|
||||
// check the forge config first
|
||||
if bname := f.Config.FindDevelBranch(repo.GetGoPath()); bname != "" {
|
||||
repo.SetDevelBranchName(bname)
|
||||
/* no longer checkout on Init()
|
||||
if repo.CheckoutDevel() {
|
||||
} else {
|
||||
cmd := []string{"git", "branch", bname}
|
||||
repo.Run(cmd)
|
||||
}
|
||||
*/
|
||||
return
|
||||
}
|
||||
|
||||
if repo.IsBranch("devel") {
|
||||
repo.SetDevelBranchName("devel")
|
||||
return
|
||||
}
|
||||
|
||||
repo.SetDevelBranchName("devel")
|
||||
/* no longer checkout on Init()
|
||||
if repo.CheckoutDevel() {
|
||||
} else {
|
||||
cmd := []string{"git", "branch", "devel"}
|
||||
repo.Run(cmd)
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
// this is still in flux
|
||||
func (f *Forge) VerifyBranchNames(repo *gitpb.Repo) {
|
||||
// log.Info("init worked for", repo.GoPath)
|
||||
|
||||
if repo.GetMasterBranchName() == "" {
|
||||
// try to guess what the 'master' branch is
|
||||
if repo.IsBranch("guimaster") {
|
||||
repo.SetMasterBranchName("guimaster")
|
||||
} else if repo.IsBranch("master") {
|
||||
repo.SetMasterBranchName("master")
|
||||
} else if repo.IsBranch("main") {
|
||||
repo.SetMasterBranchName("main")
|
||||
} else {
|
||||
// todo, figure out the name from git
|
||||
repo.SetMasterBranchName("master")
|
||||
if repo.CheckoutMaster() {
|
||||
} else {
|
||||
cmd := []string{"git", "branch", "master"}
|
||||
repo.Run(cmd)
|
||||
}
|
||||
}
|
||||
f.findMasterBranch(repo)
|
||||
}
|
||||
|
||||
if repo.GetDevelBranchName() == "" {
|
||||
if repo.IsBranch("guidevel") {
|
||||
repo.SetDevelBranchName("guidevel")
|
||||
} else if repo.IsBranch("devel") {
|
||||
repo.SetDevelBranchName("devel")
|
||||
} else {
|
||||
// forcing for now. todo: warn users
|
||||
repo.SetDevelBranchName("devel")
|
||||
if repo.CheckoutDevel() {
|
||||
} else {
|
||||
cmd := []string{"git", "branch", "devel"}
|
||||
repo.Run(cmd)
|
||||
}
|
||||
}
|
||||
f.findDevelBranch(repo)
|
||||
}
|
||||
|
||||
if repo.GetUserBranchName() == "" {
|
||||
|
@ -89,11 +162,6 @@ func (f *Forge) VerifyBranchNames(repo *gitpb.Repo) {
|
|||
} else {
|
||||
// forcing for now. todo: warn users
|
||||
repo.SetUserBranchName(uname)
|
||||
if repo.CheckoutUser() {
|
||||
} else {
|
||||
cmd := []string{"git", "branch", uname}
|
||||
repo.Run(cmd)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
92
rill.go
92
rill.go
|
@ -1,6 +1,8 @@
|
|||
package forgepb
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/destel/rill"
|
||||
"go.wit.com/lib/protobuf/gitpb"
|
||||
"go.wit.com/log"
|
||||
|
@ -30,6 +32,7 @@ func (f *Forge) rillUpdate(pool1 int, pool2 int) (int, error) {
|
|||
// Concurrency = 10
|
||||
err := rill.ForEach(rills, pool2, func(repo *gitpb.Repo) error {
|
||||
counter += 1
|
||||
// log.Info("rill.ForEach() gopath=", repo.GetGoPath())
|
||||
return f.updateRepo(repo)
|
||||
})
|
||||
|
||||
|
@ -38,7 +41,7 @@ func (f *Forge) rillUpdate(pool1 int, pool2 int) (int, error) {
|
|||
|
||||
func (f *Forge) updateRepo(repo *gitpb.Repo) error {
|
||||
if !repo.IsValidDir() {
|
||||
log.Printf("%10s %-50s", "bad git dir\n", repo.FullPath)
|
||||
log.Printf("%10s %-50s gopath=%s\n", "git dir is missing:", repo.FullPath, repo.GetGoPath())
|
||||
f.Repos.DeleteByFullPath(repo.FullPath)
|
||||
f.configSave = true
|
||||
return nil
|
||||
|
@ -63,3 +66,90 @@ func (f *Forge) updateRepo(repo *gitpb.Repo) error {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var RillX int = 10
|
||||
var RillY int = 10
|
||||
|
||||
// x is the size of the queued up pool (shouldn't matter here for this I think)
|
||||
// y is how many simultanous functions will run
|
||||
// todo: tune and compute x,y by # of CPUs and disk io
|
||||
// todo: store x,y in forge config ? (or compute them. notsure)
|
||||
func (f *Forge) RillReload() int {
|
||||
var all []*gitpb.Repo
|
||||
tmp := f.Repos.All()
|
||||
for tmp.Scan() {
|
||||
repo := tmp.Next()
|
||||
if !repo.IsValidDir() {
|
||||
log.Printf("%s %-50s", "got an invalid repo in forgepb.RillFuncError()", repo.GetGoPath())
|
||||
continue
|
||||
}
|
||||
all = append(all, repo)
|
||||
}
|
||||
// Convert a slice of user IDs into a channel
|
||||
ids := rill.FromSlice(all, nil)
|
||||
|
||||
var counter int
|
||||
// Read users from the API.
|
||||
// Concurrency = 20
|
||||
dirs := rill.Map(ids, RillX, func(repo *gitpb.Repo) (*gitpb.Repo, error) {
|
||||
return repo, nil
|
||||
})
|
||||
|
||||
rill.ForEach(dirs, RillY, func(repo *gitpb.Repo) error {
|
||||
if !repo.DidRepoChange() {
|
||||
return nil
|
||||
}
|
||||
f.configSave = true
|
||||
repo.Reload()
|
||||
counter += 1
|
||||
return nil
|
||||
})
|
||||
|
||||
return counter
|
||||
}
|
||||
|
||||
// x is the size of the queued up pool (shouldn't matter here for this I think)
|
||||
// y is how many simultanous functions will run
|
||||
// todo: tune and compute x,y by # of CPUs and disk io
|
||||
// todo: store x,y in forge config ? (or compute them. notsure)
|
||||
func (f *Forge) RillFuncError(rillf func(*gitpb.Repo) error) int {
|
||||
var all []*gitpb.Repo
|
||||
tmp := f.Repos.All()
|
||||
for tmp.Scan() {
|
||||
repo := tmp.Next()
|
||||
if !repo.IsValidDir() {
|
||||
log.Printf("%s %-50s", "got an invalid repo in forgepb.RillFuncError()", repo.GetGoPath())
|
||||
continue
|
||||
}
|
||||
all = append(all, repo)
|
||||
}
|
||||
// Convert a slice of user IDs into a channel
|
||||
ids := rill.FromSlice(all, nil)
|
||||
|
||||
var counter int
|
||||
var watch int = 10
|
||||
var meMu sync.Mutex
|
||||
|
||||
// Read users from the API.
|
||||
// Concurrency = 20
|
||||
dirs := rill.Map(ids, RillX, func(id *gitpb.Repo) (*gitpb.Repo, error) {
|
||||
return id, nil
|
||||
})
|
||||
|
||||
err := rill.ForEach(dirs, RillY, func(repo *gitpb.Repo) error {
|
||||
meMu.Lock()
|
||||
counter += 1
|
||||
if counter > watch {
|
||||
// log.Info("Processed", watch, "repos") // this doesn't work
|
||||
watch += 50
|
||||
}
|
||||
meMu.Unlock()
|
||||
return rillf(repo)
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
log.Info("rill.ForEach() error:", err)
|
||||
}
|
||||
|
||||
return counter
|
||||
}
|
||||
|
|
29
structs.go
29
structs.go
|
@ -2,9 +2,9 @@ package forgepb
|
|||
|
||||
import (
|
||||
sync "sync"
|
||||
"time"
|
||||
|
||||
"go.wit.com/lib/protobuf/gitpb"
|
||||
"go.wit.com/lib/protobuf/zoopb"
|
||||
)
|
||||
|
||||
// maybe an interface someday?
|
||||
|
@ -12,19 +12,38 @@ type Forge struct {
|
|||
// one-time initialized data
|
||||
initOnce sync.Once
|
||||
initErr error // init error, if any
|
||||
|
||||
goSrc string // the path to go/src
|
||||
configDir string // normally ~/.config/forge
|
||||
goWork bool // means the user is currently using a go.work file
|
||||
Config *ForgeConfigs // config repos for readonly, private, etc
|
||||
Repos *gitpb.Repos
|
||||
Machine *zoopb.Machine
|
||||
configSave bool
|
||||
Repos *gitpb.Repos // the repo protobufs
|
||||
// Machine *zoopb.Machine // things for virtigo to track vm's
|
||||
configSave bool // if you need to save the config because things changed
|
||||
hasFullScan bool // track last scan so it can be throttled
|
||||
fullscan time.Time // time of the last scan so it can be throttled
|
||||
}
|
||||
|
||||
func (f *Forge) GetGoSrc() string {
|
||||
return f.goSrc
|
||||
}
|
||||
|
||||
func (f *Forge) GetConfigDir() string {
|
||||
return f.configDir
|
||||
}
|
||||
|
||||
func (f *Forge) IsGoWork() bool {
|
||||
return f.goWork
|
||||
}
|
||||
|
||||
func (f *Forge) HasFullScan() bool {
|
||||
return f.Repos.HasFullScan
|
||||
}
|
||||
|
||||
func (f *Forge) FullScanRan() {
|
||||
f.fullscan = time.Now()
|
||||
}
|
||||
|
||||
func (f *Forge) FullScanAge() time.Duration {
|
||||
fs := f.Repos.FullScan.AsTime()
|
||||
return time.Since(fs)
|
||||
}
|
||||
|
|
10
uuid.proto
10
uuid.proto
|
@ -1,10 +0,0 @@
|
|||
syntax = "proto3";
|
||||
|
||||
// experiment to identify .pb files incase things go sideways
|
||||
package forgepb;
|
||||
|
||||
// autogenpb:no-sort
|
||||
message UuidConfigs { // `autogenpb:marshal`
|
||||
string uuid = 1; // could be useful for /usr/share/file/magic someday?
|
||||
string version = 2; // could be used for protobuf schema change violations?
|
||||
}
|
Loading…
Reference in New Issue