Compare commits

..

No commits in common. "6622ea0e1cb22687791c26b60381b138cbbb8098" and "d83517f67ba638abed1d76541068413e60142194" have entirely different histories.

2 changed files with 28 additions and 39 deletions

50
acid.go
View File

@ -30,6 +30,7 @@ import (
"syscall" "syscall"
ttemplate "text/template" ttemplate "text/template"
"time" "time"
"unicode"
_ "github.com/mattn/go-sqlite3" _ "github.com/mattn/go-sqlite3"
"github.com/pkg/sftp" "github.com/pkg/sftp"
@ -153,14 +154,6 @@ var shellFuncs = ttemplate.FuncMap{
// --- Utilities --------------------------------------------------------------- // --- Utilities ---------------------------------------------------------------
func localShell() string {
if shell := os.Getenv("SHELL"); shell != "" {
return shell
}
// The os/user package doesn't store the parsed out shell field.
return "/bin/sh"
}
func giteaSign(b []byte) string { func giteaSign(b []byte) string {
payloadHmac := hmac.New(sha256.New, []byte(getConfig().Secret)) payloadHmac := hmac.New(sha256.New, []byte(getConfig().Secret))
payloadHmac.Write(b) payloadHmac.Write(b)
@ -313,7 +306,9 @@ function get(id) {
return document.getElementById(id) return document.getElementById(id)
} }
function getLog(id) { function getLog(id) {
const header = get(id), log = get(id + 'log'), text = log.textContent const header = document.getElementById(id)
const log = document.getElementById(id + 'log')
const text = log.textContent
// lines[-1] is an implementation detail of terminalWriter.Serialize, // lines[-1] is an implementation detail of terminalWriter.Serialize,
// lines[-2] is the actual last line. // lines[-2] is the actual last line.
const last = Math.max(0, text.split('\n').length - 2) const last = Math.max(0, text.split('\n').length - 2)
@ -331,7 +326,8 @@ function refreshLog(log, top, changed) {
log.log.hidden = empty log.log.hidden = empty
} }
let refresher = setInterval(() => { let refresher = setInterval(() => {
const run = getLog('run'), task = getLog('task'), deploy = getLog('deploy') let run = getLog('run'), task = getLog('task'), deploy = getLog('deploy')
const url = new URL(window.location.href) const url = new URL(window.location.href)
url.search = '' url.search = ''
url.searchParams.set('json', '') url.searchParams.set('json', '')
@ -370,8 +366,8 @@ let refresher = setInterval(() => {
if (!data.IsRunning) if (!data.IsRunning)
clearInterval(refresher) clearInterval(refresher)
}).catch(error => { }).catch(error => {
clearInterval(refresher)
alert(error) alert(error)
clearInterval(refresher)
}) })
}, 1000 /* For faster updates than this, we should use WebSockets. */) }, 1000 /* For faster updates than this, we should use WebSockets. */)
</script> </script>
@ -846,7 +842,7 @@ func notifierRunCommand(ctx context.Context, task Task) {
return return
} }
cmd := exec.CommandContext(ctx, localShell()) cmd := exec.CommandContext(ctx, "sh")
cmd.Stdin = script cmd.Stdin = script
cmd.Stdout = os.Stdout cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr cmd.Stderr = os.Stderr
@ -1170,6 +1166,14 @@ func executorDownload(client *ssh.Client, remoteRoot, localRoot string) error {
return nil return nil
} }
func executorLocalShell() string {
if shell := os.Getenv("SHELL"); shell != "" {
return shell
}
// The os/user package doesn't store the parsed out shell field.
return "/bin/sh"
}
func executorTmpDir(fallback string) string { func executorTmpDir(fallback string) string {
// See also: https://systemd.io/TEMPORARY_DIRECTORIES/ // See also: https://systemd.io/TEMPORARY_DIRECTORIES/
if tmp := os.Getenv("TMPDIR"); tmp != "" { if tmp := os.Getenv("TMPDIR"); tmp != "" {
@ -1205,10 +1209,9 @@ func executorDeploy(
return err return err
} }
cmd := exec.CommandContext(ctx, localShell()) cmd := exec.CommandContext(ctx, executorLocalShell(), "-c", script.String())
cmd.Env = rt.localEnv() cmd.Env = rt.localEnv()
cmd.Dir = dir cmd.Dir = dir
cmd.Stdin = script
cmd.Stdout = &rt.DeployLog cmd.Stdout = &rt.DeployLog
cmd.Stderr = &rt.DeployLog cmd.Stderr = &rt.DeployLog
return cmd.Run() return cmd.Run()
@ -1602,15 +1605,18 @@ func (t *Task) CloneURL() string {
} }
func shortDurationString(d time.Duration) string { func shortDurationString(d time.Duration) string {
if d.Abs() >= 24*time.Hour { rs := []rune(d.Truncate(time.Second).String())
return strconv.FormatInt(int64(d/time.Hour/24), 10) + "d" for i, r := range rs {
} else if d.Abs() >= time.Hour { if !unicode.IsLetter(r) {
return strconv.FormatInt(int64(d/time.Hour), 10) + "h" continue
} else if d.Abs() >= time.Minute { }
return strconv.FormatInt(int64(d/time.Minute), 10) + "m" i++
} else { for i < len(rs) && unicode.IsLetter(rs[i]) {
return strconv.FormatInt(int64(d/time.Second), 10) + "s" i++
}
return string(rs[:i])
} }
return string(rs)
} }
func (t *Task) Created() *time.Time { func (t *Task) Created() *time.Time {

View File

@ -4,7 +4,6 @@ import (
"bytes" "bytes"
"testing" "testing"
ttemplate "text/template" ttemplate "text/template"
"time"
) )
func TestTemplateQuote(t *testing.T) { func TestTemplateQuote(t *testing.T) {
@ -31,19 +30,3 @@ func TestTemplateQuote(t *testing.T) {
} }
} }
} }
func TestShortDurationString(t *testing.T) {
for _, test := range []struct {
d time.Duration
expect string
}{
{72 * time.Hour, "3d"},
{-3 * time.Hour, "-3h"},
{12 * time.Minute, "12m"},
{time.Millisecond, "0s"},
} {
if sd := shortDurationString(test.d); sd != test.expect {
t.Errorf("%s = %s; want %s\n", test.d, sd, test.expect)
}
}
}