Initial commit
This commit is contained in:
		
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
cmd/pbuild/pbuild
 | 
			
		||||
							
								
								
									
										11
									
								
								cmd/pbuild/config.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								cmd/pbuild/config.go
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										27
									
								
								cmd/pbuild/main.go
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										8
									
								
								cmd/pbuild/profile.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
{
 | 
			
		||||
	"Name": "pbuild",
 | 
			
		||||
	"ID": "pbuild",
 | 
			
		||||
	"Commands": [
 | 
			
		||||
		"go clean",
 | 
			
		||||
		"go build -v"
 | 
			
		||||
	]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										41
									
								
								internal/runner/profile.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								internal/runner/profile.go
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										82
									
								
								internal/runner/run.go
									
									
									
									
									
										Normal 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
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user