Initial commit

This commit is contained in:
Edgaru089 2023-08-15 18:41:11 +08:00
commit 57fc43ff9c
7 changed files with 173 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
cmd/pbuild/pbuild

11
cmd/pbuild/config.go Normal file
View File

@ -0,0 +1,11 @@
package main
// Config file for the daemon.
type Config struct {
WorkDir string // Working directory.
ListenAddr string // Listen address for net.Dial.
}
// Post message in Gitea format, only taking what we're interested in.
type GiteaPost struct {
}

27
cmd/pbuild/main.go Normal file
View File

@ -0,0 +1,27 @@
package main
import (
"encoding/json"
"fmt"
"os"
"edgaru089.ink/go/pbuild/internal/runner"
)
func main() {
var profile runner.Profile
file, err := os.ReadFile("profile.json")
if err != nil {
panic(err)
}
err = json.Unmarshal(file, &profile)
if err != nil {
panic(err)
}
logs, _, _ := profile.Run(".")
fmt.Print(logs)
}

8
cmd/pbuild/profile.json Normal file
View File

@ -0,0 +1,8 @@
{
"Name": "pbuild",
"ID": "pbuild",
"Commands": [
"go clean",
"go build -v"
]
}

3
go.mod Normal file
View File

@ -0,0 +1,3 @@
module edgaru089.ink/go/pbuild
go 1.21.0

View File

@ -0,0 +1,41 @@
package runner
import (
"fmt"
"strings"
"time"
)
// A Profile defines what to run when invoked on the target directory.
type Profile struct {
Name string // Name of the profile.
ID string // ID of the profile.
Commands []string // Commands to run on the profile.
Environ map[string]string // Environment variables
Output []string // List of globs to match output files.
OutputDir string // The globs will be matched in this relative directory.
}
type LogEntry struct {
Time time.Time
Text string
OutFd int // 0(manual) 1(stdout) 2(stderr)
}
type Logs []LogEntry
func (logs Logs) String() string {
var buf strings.Builder
for _, log := range logs {
switch log.OutFd {
case 0:
fmt.Fprintf(&buf, "%s %s\n", log.Time.Format("15:04:05"), log.Text)
case 1, 2:
fmt.Fprintf(&buf, "%s %s\n", log.Time.Format("15:04:05"), log.Text)
}
}
return buf.String()
}

82
internal/runner/run.go Normal file
View File

@ -0,0 +1,82 @@
package runner
import (
"fmt"
"os"
"os/exec"
"sync"
"time"
)
type logsWriter struct {
lock *sync.Mutex
logs *Logs
outfd int // 0(manual message) 1(stdout) or 2(stderr)
}
func (l *logsWriter) Write(data []byte) (len int, err error) {
l.lock.Lock()
defer l.lock.Unlock()
*l.logs = append(*l.logs, LogEntry{
Time: time.Now(),
Text: string(data),
OutFd: l.outfd,
})
return
}
// Run runs the profile on the target directory, preserving output.
func (p *Profile) Run(dir string) (logs Logs, exitcode int, err error) {
// Try if the directory exists
_, err = os.ReadDir(dir)
if err != nil {
return
}
// Construct the env slice
env := make([]string, len(p.Environ))
{
i := 0
for key, val := range p.Environ {
env[i] = key + "=" + val
i++
}
}
loglock := &sync.Mutex{}
logman := &logsWriter{logs: &logs, lock: loglock, outfd: 0}
logout := &logsWriter{logs: &logs, lock: loglock, outfd: 1}
logerr := &logsWriter{logs: &logs, lock: loglock, outfd: 2}
var systime, usrtime time.Duration
// Run commands
runcmds:
for i, str := range p.Commands {
fmt.Fprintf(logman, "[%d/%d] running \"%s\"", i, len(p.Commands), str)
cmd := exec.Command("sh", "-c", str)
cmd.Env = append(cmd.Env, env...)
cmd.Stdout = logout
cmd.Stderr = logerr
cmd.Dir = dir
err := cmd.Run()
systime += cmd.ProcessState.SystemTime()
usrtime += cmd.ProcessState.UserTime()
switch err.(type) {
case *exec.ExitError:
fmt.Fprintf(logman, "!!!!! command exit with code %d !!!!!", err.(*exec.ExitError).ExitCode())
break runcmds
}
}
fmt.Fprintf(logman, "system %.4f, user %.4f", systime.Seconds(), usrtime.Seconds())
return
}