some windows fixes

This commit is contained in:
AJ ONeal 2019-07-03 02:11:50 -06:00
parent 196fdee7ac
commit fa6d7afa05
7 changed files with 64 additions and 64 deletions

View File

@ -15,3 +15,21 @@ serviceman install --user ./foo-app -- -c ./
```bash ```bash
serviceman install --user /usr/local/bin/node ./whatever.js -- -c ./ serviceman install --user /usr/local/bin/node ./whatever.js -- -c ./
``` ```
```bash
serviceman run --config conf.json
```
```json
{
"interpreter": "/Program Files (x86)/node/node.exe",
"exec": "/Users/aj/demo/demo.js",
"argv": ["--foo", "bar", "--baz", "qux"]
}
```
```bash
go generate -mod=vendor ./...
go build -mod=vendor -ldflags "-H=windowsgui"
.\\go-serviceman node ./demo.js -- --foo bar --baz qux
```

View File

@ -5,8 +5,8 @@ package installer
import ( import (
"fmt" "fmt"
"os" "os"
"os/exec"
"path/filepath" "path/filepath"
"strings"
"git.rootprojects.org/root/go-serviceman/service" "git.rootprojects.org/root/go-serviceman/service"
) )
@ -42,26 +42,18 @@ func Install(c *service.Service) error {
return nil return nil
} }
// Returns true if we suspect that the current user (or process) will be able // IsPrivileged returns true if we suspect that the current user (or process) will be able
// to write to system folders, bind to privileged ports, and otherwise // to write to system folders, bind to privileged ports, and otherwise
// successfully run a system service. // successfully run a system service.
func IsPrivileged() bool { func IsPrivileged() bool {
return isPrivileged() return isPrivileged()
} }
func WhereIs(exec string) (string, error) { // WhereIs uses exec.LookPath to return an absolute filepath with forward slashes
// TODO use exec.LookPath instead func WhereIs(exe string) (string, error) {
exec = filepath.ToSlash(exec) exepath, err := exec.LookPath(exe)
if strings.Contains(exec, "/") { if nil != err {
// it's a path (so we don't allow filenames with slashes) return "", err
stat, err := os.Stat(exec)
if nil != err {
return "", err
}
if stat.IsDir() {
return "", fmt.Errorf("'%s' is not an executable file", exec)
}
return filepath.Abs(exec)
} }
return whereIs(exec) return filepath.Abs(filepath.ToSlash(exepath))
} }

View File

@ -1,18 +0,0 @@
// +build !windows
package installer
import (
"os/exec"
"strings"
)
func whereIs(exe string) (string, error) {
// TODO use exec.LookPath instead
cmd := exec.Command("command", "-v", exe)
out, err := cmd.Output()
if nil != err {
return "", err
}
return strings.TrimSpace(string(out)), nil
}

View File

@ -6,7 +6,6 @@ import (
"io/ioutil" "io/ioutil"
"log" "log"
"os" "os"
"os/exec"
"path/filepath" "path/filepath"
"strings" "strings"
@ -77,24 +76,21 @@ func install(c *service.Service) error {
// it can be "the main thing" // it can be "the main thing"
bin = exec bin = exec
} }
if 0 != len(args) {
// On Windows the /c acts kinda like -- does on *nix,
// at least for commands in the registry that have arguments
setArgs = ` /c `
}
// The final string ends up looking something like one of these: // The final string ends up looking something like one of these:
// "C:\Users\aj\.local\opt\appname\appname.js /c -p 8080" // `"C:\Users\aj\.local\opt\appname\appname.js" -p 8080`
// "C:\Program Files (x64)\nodejs\node.exe /c C:\Users\aj\.local\opt\appname\appname.js -p 8080" // `"C:\Program Files (x64)\nodejs\node.exe" C:\Users\aj\.local\opt\appname\appname.js -p 8080`
regSZ := bin + setArgs + strings.Join(c.Argv, " ") regSZ := bin + setArgs + strings.Join(c.Argv, " ")
*/ */
regSZ := fmt.Sprintf("%s /c %s", args[0], strings.Join(args[1:], " ")) regSZ := fmt.Sprintf(`"%s" %s`, args[0], strings.Join(args[1:], " "))
if len(regSZ) > 260 { if len(regSZ) > 260 {
return fmt.Errorf("data value is too long for registry entry") return fmt.Errorf("data value is too long for registry entry")
} }
fmt.Println("Set Registry Key:") // In order for a windows gui program to not show a console,
fmt.Println(autorunKey, c.Title, regSZ) // it has to not output any messages?
//fmt.Println("Set Registry Key:")
//fmt.Println(autorunKey, c.Title, regSZ)
k.SetStringValue(c.Title, regSZ) k.SetStringValue(c.Title, regSZ)
return nil return nil
@ -108,7 +104,7 @@ func installServiceman(c *service.Service) ([]string, error) {
// TODO support service level services (which probably wouldn't need serviceman) // TODO support service level services (which probably wouldn't need serviceman)
smdir = filepath.Join(c.Home, ".local", smdir) smdir = filepath.Join(c.Home, ".local", smdir)
// for now we'll scope the runner to the name of the application // for now we'll scope the runner to the name of the application
smbin := filepath.Join(smdir, `bin\serviceman.`+c.Name) smbin := filepath.Join(smdir, `bin\serviceman.`+c.Name+`.exe`)
if smbin != self { if smbin != self {
err := os.MkdirAll(filepath.Dir(smbin), 0755) err := os.MkdirAll(filepath.Dir(smbin), 0755)
@ -148,13 +144,3 @@ func installServiceman(c *service.Service) ([]string, error) {
conffile, conffile,
}, nil }, nil
} }
func whereIs(exe string) (string, error) {
// TODO use exec.LookPath instead
cmd := exec.Command("where.exe", exe)
out, err := cmd.Output()
if nil != err {
return "", err
}
return strings.TrimSpace(string(out)), nil
}

View File

@ -5,11 +5,15 @@ import (
"os" "os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
"strings"
"time" "time"
"git.rootprojects.org/root/go-serviceman/service" "git.rootprojects.org/root/go-serviceman/service"
) )
// Filled in on init by runner_windows.go
var shellArgs = []string{}
// Notes on spawning a child process // Notes on spawning a child process
// https://groups.google.com/forum/#!topic/golang-nuts/shST-SDqIp4 // https://groups.google.com/forum/#!topic/golang-nuts/shST-SDqIp4
@ -30,11 +34,17 @@ func Run(conf *service.Service) {
} }
args = append(args, conf.Argv...) args = append(args, conf.Argv...)
if !conf.System && 0 != len(shellArgs) {
nargs := append(shellArgs[1:], binpath)
args = append(nargs, args...)
binpath = shellArgs[0]
}
for { for {
// setup the log // setup the log
lf, err := os.OpenFile(logfile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644) lf, err := os.OpenFile(logfile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
if nil != err { if nil != err {
fmt.Fprintf(os.Stderr, "Could not open log file %q\n", logfile) fmt.Fprintf(os.Stderr, "[%s] Could not open log file %q\n", time.Now(), logfile)
lf = os.Stderr lf = os.Stderr
} else { } else {
defer lf.Close() defer lf.Close()
@ -42,6 +52,8 @@ func Run(conf *service.Service) {
start := time.Now() start := time.Now()
cmd := exec.Command(binpath, args...) cmd := exec.Command(binpath, args...)
fmt.Fprintf(lf, "[%s] Starting %q %s \n", time.Now(), binpath, strings.Join(args, " "))
cmd.Stdin = nil cmd.Stdin = nil
cmd.Stdout = lf cmd.Stdout = lf
cmd.Stderr = lf cmd.Stderr = lf
@ -50,20 +62,18 @@ func Run(conf *service.Service) {
} }
err = cmd.Start() err = cmd.Start()
if nil != err { if nil != err {
fmt.Fprintf(lf, "Could not start %q process: %s\n", conf.Name, err) fmt.Fprintf(lf, "[%s] Could not start %q process: %s\n", time.Now(), conf.Name, err)
} else { } else {
err = cmd.Wait() err = cmd.Wait()
if nil != err { if nil != err {
fmt.Fprintf(lf, "Process %q failed with error: %s\n", conf.Name, err) fmt.Fprintf(lf, "[%s] Process %q failed with error: %s\n", time.Now(), conf.Name, err)
} else { } else {
fmt.Fprintf(lf, "Process %q exited cleanly\n", conf.Name) fmt.Fprintf(lf, "[%s] Process %q exited cleanly\n", time.Now(), conf.Name)
fmt.Printf("Process %q exited cleanly\n", conf.Name)
} }
} }
// if this is a oneshot... so it is // if this is a oneshot... so it is
if !conf.Restart { if !conf.Restart {
fmt.Printf("Not restarting %q because `restart` set to `false`\n", conf.Name)
fmt.Fprintf(lf, "Not restarting %q because `restart` set to `false`\n", conf.Name) fmt.Fprintf(lf, "Not restarting %q because `restart` set to `false`\n", conf.Name)
break break
} }

12
runner/runner_windows.go Normal file
View File

@ -0,0 +1,12 @@
package runner
import (
"os/exec"
)
func init() {
cmd, _ := exec.LookPath("cmd.exe")
if "" != cmd {
shellArgs = []string{cmd, "/c"}
}
}

View File

@ -178,7 +178,7 @@ func run() {
} }
s.Normalize(false) s.Normalize(false)
fmt.Fprintf(os.Stdout, "Logdir: %s\n", s.Logdir) //fmt.Fprintf(os.Stdout, "Logdir: %s\n", s.Logdir)
err = os.MkdirAll(s.Logdir, 0755) err = os.MkdirAll(s.Logdir, 0755)
if nil != err { if nil != err {
fmt.Fprintf(os.Stderr, "%s\n", err) fmt.Fprintf(os.Stderr, "%s\n", err)
@ -186,7 +186,7 @@ func run() {
} }
if !daemonize { if !daemonize {
fmt.Fprintf(os.Stdout, "Running %s %s %s\n", s.Interpreter, s.Exec, strings.Join(s.Argv, " ")) //fmt.Fprintf(os.Stdout, "Running %s %s %s\n", s.Interpreter, s.Exec, strings.Join(s.Argv, " "))
runner.Run(s) runner.Run(s)
return return
} }