v0.2.0
This commit is contained in:
		
							parent
							
								
									63328251fa
								
							
						
					
					
						commit
						555edebf20
					
				
							
								
								
									
										335
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										335
									
								
								README.md
									
									
									
									
									
								
							| @ -2,34 +2,347 @@ | ||||
| 
 | ||||
| A cross-platform service manager. | ||||
| 
 | ||||
| Goal: | ||||
| Because debugging launchctl, systemd, etc absolutely sucks! | ||||
| 
 | ||||
| ...and I wanted a reasonable way to install [Telebit](https://telebit.io) on Windows. | ||||
| (see more in the **Why** section below) | ||||
| 
 | ||||
| <details> | ||||
| <summary>User Mode Services</summary> | ||||
|   * `sytemctl --user` on Linux | ||||
|   * `launchctl` on MacOS | ||||
|   * `HKEY_CURRENT_USER/.../Run` on Windows | ||||
| </details> | ||||
| <details> | ||||
| <summary>System Services</summary> | ||||
|   * `sudo sytemctl` on Linux | ||||
|   * `sudo launchctl` on MacOS | ||||
|   * _not yet implemented_ on Windows | ||||
| </details> | ||||
| 
 | ||||
| - **Install** | ||||
| - **Usage** | ||||
| - **Build** | ||||
| - **Examples** | ||||
|   - compiled programs | ||||
|   - scripts | ||||
|   - bash | ||||
|   - node | ||||
|   - python | ||||
|   - ruby | ||||
| - **Logging** | ||||
| - **Windows** | ||||
| - **Debugging** | ||||
| - **Why** | ||||
| - **Legal** | ||||
| 
 | ||||
| # Install | ||||
| 
 | ||||
| Download `serviceman` for | ||||
| 
 | ||||
| - [MacOS (64-bit darwin)](https://rootprojects.org/serviceman/dist/darwin/amd64/serviceman) | ||||
| - [Windows 10 (64-bit)](https://rootprojects.org/serviceman/dist/windows/amd64/serviceman.exe) | ||||
| - [Windows 10 (32-bit)](https://rootprojects.org/serviceman/dist/windows/386/serviceman.exe) | ||||
| - [Linux (64-bit)](https://rootprojects.org/serviceman/dist/linux/amd64/serviceman) | ||||
| - [Linux (32-bit)](https://rootprojects.org/serviceman/dist/linux/386/serviceman) | ||||
| - [Raspberry Pi 4 (64-bit armv8)](https://rootprojects.org/serviceman/dist/linux/armv8/serviceman) | ||||
| - [Raspberry Pi 3 (armv7)](https://rootprojects.org/serviceman/dist/linux/armv7/serviceman) | ||||
| - [Raspberry Pi 2 (armv6)](https://rootprojects.org/serviceman/dist/linux/armv6/serviceman) | ||||
| - [Raspberry Pi Zero (armv5)](https://rootprojects.org/serviceman/dist/linux/armv5/serviceman) | ||||
| 
 | ||||
| # Usage | ||||
| 
 | ||||
| ```bash | ||||
| serviceman install [options] [interpreter] <service> [-- [options]] | ||||
| serviceman add [options] [interpreter] <service> -- [service options] | ||||
| ``` | ||||
| 
 | ||||
| ```bash | ||||
| serviceman install --user ./foo-app -- -c ./ | ||||
| serviceman add --help | ||||
| ``` | ||||
| 
 | ||||
| ```bash | ||||
| serviceman install --user /usr/local/bin/node ./whatever.js -- -c ./ | ||||
| serviceman version | ||||
| ``` | ||||
| 
 | ||||
| # Examples | ||||
| 
 | ||||
| **Compiled Apps** | ||||
| 
 | ||||
| Normally you might run your program something like this: | ||||
| 
 | ||||
| ```bash | ||||
| dinglehopper --port 8421 | ||||
| ``` | ||||
| 
 | ||||
| Adding a service for that program with `serviceman` would look like this: | ||||
| 
 | ||||
| > **serviceman add** dinglehopper **--** --port 8421 | ||||
| 
 | ||||
| `serviceman` will find `dinglehopper` in your PATH, but if you have | ||||
| any arguments with relative paths, you should switch to using absolute paths. | ||||
| 
 | ||||
| ```bash | ||||
| dinglehopper --config ./conf.json | ||||
| ``` | ||||
| 
 | ||||
| becomes | ||||
| 
 | ||||
| > **serviceman add** dinglehopper **--** --config **/Users/aj/dinglehopper/conf.json** | ||||
| 
 | ||||
| <details> | ||||
| <summary>Using with scripts</summary> | ||||
| 
 | ||||
| Although your text script may be executable, you'll need to specify the interpreter | ||||
| in order for `serviceman` to configure the service correctly. | ||||
| 
 | ||||
| For example, if you had a bash script that you normally ran like this: | ||||
| 
 | ||||
| ```bash | ||||
| ./snarfblat.sh --port 8421 | ||||
| ``` | ||||
| 
 | ||||
| You'd create a system service for it like this: | ||||
| 
 | ||||
| > serviceman add **bash** ./snarfblat.sh **--** --port 8421 | ||||
| 
 | ||||
| `serviceman` will resolve `./snarfblat.sh` correctly because it comes | ||||
| before the **--**. | ||||
| 
 | ||||
| **Background Information** | ||||
| 
 | ||||
| An operating system can't "run" text files (even if the executable bit is set). | ||||
| 
 | ||||
| Scripts require an _interpreter_. Often this is denoted at the top of | ||||
| "executable" scripts with something like one of these: | ||||
| 
 | ||||
| ```bash | ||||
| #!/usr/bin/env ruby | ||||
| ``` | ||||
| 
 | ||||
| ```bash | ||||
| serviceman run --config conf.json | ||||
| #!/usr/bin/python | ||||
| ``` | ||||
| 
 | ||||
| However, sometimes people get fancy and pass arguments to the interpreter, | ||||
| like this: | ||||
| 
 | ||||
| ```bash | ||||
| #!/usr/local/bin/node --harmony --inspect | ||||
| ``` | ||||
| 
 | ||||
| </details> | ||||
| 
 | ||||
| <details> | ||||
| <summary>Using with node.js</summary> | ||||
| 
 | ||||
| If normally you run your node script something like this: | ||||
| 
 | ||||
| ```bash | ||||
| node ./demo.js --foo bar --baz | ||||
| ``` | ||||
| 
 | ||||
| Then you would add it as a system service like this: | ||||
| 
 | ||||
| > **serviceman add** node ./demo.js **--** --foo bar --baz | ||||
| 
 | ||||
| It is important that you specify `node ./demo.js` and not just `./demo.js` | ||||
| 
 | ||||
| See **Using with scripts** for more detailed information. | ||||
| 
 | ||||
| </details> | ||||
| 
 | ||||
| <details> | ||||
| <summary>Using with python</summary> | ||||
| 
 | ||||
| If normally you run your python script something like this: | ||||
| 
 | ||||
| ```bash | ||||
| python ./demo.py --foo bar --baz | ||||
| ``` | ||||
| 
 | ||||
| Then you would add it as a system service like this: | ||||
| 
 | ||||
| > **serviceman add** python ./demo.py **--** --foo bar --baz | ||||
| 
 | ||||
| It is important that you specify `python ./demo.py` and not just `./demo.py` | ||||
| 
 | ||||
| See **Using with scripts** for more detailed information. | ||||
| 
 | ||||
| </details> | ||||
| 
 | ||||
| <details> | ||||
| <summary>Using with ruby</summary> | ||||
| 
 | ||||
| If normally you run your ruby script something like this: | ||||
| 
 | ||||
| ```bash | ||||
| ruby ./demo.rb --foo bar --baz | ||||
| ``` | ||||
| 
 | ||||
| Then you would add it as a system service like this: | ||||
| 
 | ||||
| > **serviceman add** ruby ./demo.rb **--** --foo bar --baz | ||||
| 
 | ||||
| It is important that you specify `ruby ./demo.rb` and not just `./demo.rb` | ||||
| 
 | ||||
| See **Using with scripts** for more detailed information. | ||||
| 
 | ||||
| </details> | ||||
| 
 | ||||
| # Logging | ||||
| 
 | ||||
| When you run `serviceman add` it will either give you an error or | ||||
| will print out the location where logs will be found. | ||||
| 
 | ||||
| By default it's one of these: | ||||
| 
 | ||||
| ```txt | ||||
| ~/.local/share/<NAME>/var/log/<NAME>.log | ||||
| ``` | ||||
| 
 | ||||
| ```txt | ||||
| /var/log/<NAME>/var/log/<NAME>.log | ||||
| ``` | ||||
| 
 | ||||
| You set it with one of these: | ||||
| 
 | ||||
| - `--logdir <path>` (cli) | ||||
| - `"logdir": "<path>"` (json) | ||||
| - `Logdir: "<path>"` (go) | ||||
| 
 | ||||
| If anything about the logging sucks, tell me... unless they're your logs | ||||
| (which they probably are), in which case _you_ should fix them. | ||||
| 
 | ||||
| That said, my goal is that it shouldn't take an IT genius to interpret | ||||
| why your app failed to start. | ||||
| 
 | ||||
| # Peculiarities of Windows | ||||
| 
 | ||||
| Windows doesn't have a userspace daemon launcher. | ||||
| This means that if your application crashes, it won't automatically restart. | ||||
| 
 | ||||
| However, `serviceman` handles this by not directly adding your application | ||||
| to `HKEY_CURRENT_USER/.../Run`, but rather installing a copy of _itself_ | ||||
| instead, which runs your application and automatically restarts it whenever it | ||||
| exits. | ||||
| 
 | ||||
| If the application fails to start `serviceman` will retry continually, | ||||
| but it does have an exponential backoff of up to 1 minute between failed | ||||
| restart attempts. | ||||
| 
 | ||||
| See the bit on `serviceman run` in the **Debugging** section down below for more information. | ||||
| 
 | ||||
| # Debugging | ||||
| 
 | ||||
| One of the most irritating problems with all of these launchers is that they're | ||||
| terrible to debug - it's often difficult to find the logs, and nearly impossible | ||||
| to interpret them, if they exist at all. | ||||
| 
 | ||||
| The config files generate by `serviceman` are simple, template-generated and | ||||
| tested, and therefore gauranteed to work - **_if_** your | ||||
| application runs with the parameters given, which is big 'if'. | ||||
| 
 | ||||
| `serviceman` tries to make sure that all necessary files and folders | ||||
| exist and give clear error messages if they don't (be sure to check the logs, | ||||
| mentioned above). | ||||
| 
 | ||||
| There's also a `run` utility that can be used to test that the parameters | ||||
| you've given are being interpreted correctly (absolute paths and such). | ||||
| 
 | ||||
| ```bash | ||||
| serviceman run --config ./conf.json | ||||
| ``` | ||||
| 
 | ||||
| Where `conf.json` looks something like | ||||
| 
 | ||||
| **For Binaries**: | ||||
| 
 | ||||
| ```json | ||||
| { | ||||
|     "interpreter": "/Program Files (x86)/node/node.exe", | ||||
|     "exec": "/Users/aj/demo/demo.js", | ||||
|     "argv": ["--foo", "bar", "--baz", "qux"] | ||||
| 	"title": "Demo", | ||||
| 	"exec": "/Users/aj/go-demo/demo", | ||||
| 	"argv": ["--foo", "bar", "--baz", "qux"] | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| **For Scripts**: | ||||
| 
 | ||||
| Scripts can't be run directly. They require a binary `interpreter` - bash, node, ruby, python, etc. | ||||
| 
 | ||||
| If you're running from the folder containing `./demo.js`, | ||||
| and `node.exe` is in your PATH, then you can use executable | ||||
| names and relative paths. | ||||
| 
 | ||||
| ```json | ||||
| { | ||||
| 	"title": "Demo", | ||||
| 	"interpreter": "node.exe", | ||||
| 	"exec": "./bin/demo.js", | ||||
| 	"argv": ["--foo", "bar", "--baz", "qux"] | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| That's equivalent to this: | ||||
| 
 | ||||
| ```json | ||||
| { | ||||
| 	"title": "Demo", | ||||
| 
 | ||||
| 	"name": "demo", | ||||
| 
 | ||||
| 	"exec": "node.exe", | ||||
| 	"argv": ["./bin/demo.js", "--foo", "bar", "--baz", "qux"] | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| Making `add` and `run` take the exact same arguments is on the TODO list. | ||||
| The fact that they don't is an artifact of `run` being created specifically | ||||
| for Windows. | ||||
| 
 | ||||
| If you have gripes about it, tell me. It shouldn't suck. That's the goal anyway. | ||||
| 
 | ||||
| # Building | ||||
| 
 | ||||
| ```bash | ||||
| git clone https://git.coolaj86.com/coolaj86/go-serviceman.git | ||||
| ``` | ||||
| 
 | ||||
| ```bash | ||||
| pushd ./go-serviceman | ||||
| ``` | ||||
| 
 | ||||
| ```bash | ||||
| go generate -mod=vendor ./... | ||||
| go build -mod=vendor -ldflags "-H=windowsgui" | ||||
| .\\go-serviceman node ./demo.js -- --foo bar --baz qux | ||||
| ``` | ||||
| ``` | ||||
| 
 | ||||
| **Windows**: | ||||
| 
 | ||||
| ```bash | ||||
| go build -mod=vendor -ldflags "-H=windowsgui" -o serviceman.exe | ||||
| ``` | ||||
| 
 | ||||
| **Linux, MacOS**: | ||||
| 
 | ||||
| ```bash | ||||
| go build -mod=vendor -o /usr/local/bin/serviceman | ||||
| ``` | ||||
| 
 | ||||
| # Why | ||||
| 
 | ||||
| I created this for two reasons: | ||||
| 
 | ||||
| 1. Too often I just run services in `screen -xRS foo` because systemd `.service` files are way too hard to get right and even harder to debug. I make stupid typos or config mistakes and get it wrong. Then I get a notice 18 months later from digital ocean that NYC region 3 is being rebooted and to expect 5 seconds of downtime... and I don't remember if I remembered to go back and set up that service with systemd or not. | ||||
| 2. To make it easier for people to install [Telebit](https://telebit.io) on Windows. | ||||
| 
 | ||||
| <!-- {{ if .Legal }} --> | ||||
| 
 | ||||
| # Legal | ||||
| 
 | ||||
| [serviceman](https://git.coolaj86.com/coolaj86/go-serviceman) | | ||||
| MPL-2.0 | | ||||
| [Terms of Use](https://therootcompany.com/legal/#terms) | | ||||
| [Privacy Policy](https://therootcompany.com/legal/#privacy) | ||||
| 
 | ||||
| Copyright 2019 AJ ONeal. | ||||
| 
 | ||||
| <!-- {{ end }} --> | ||||
|  | ||||
							
								
								
									
										41
									
								
								build-all.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								build-all.sh
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,41 @@ | ||||
| #GOOS=windows GOARCH=amd64 go install | ||||
| #go tool dist list | ||||
| 
 | ||||
| # TODO move this into tools/build.go | ||||
| 
 | ||||
| export CGO_ENABLED=0 | ||||
| exe=serviceman | ||||
| gocmd=. | ||||
| 
 | ||||
| echo "" | ||||
| go generate -mod=vendor ./... | ||||
| 
 | ||||
| echo "" | ||||
| echo "Windows amd64" | ||||
| GOOS=windows GOARCH=amd64 go build -mod=vendor -o dist/windows/amd64/${exe}.exe -ldflags "-H=windowsgui" $gocmd | ||||
| echo "Windows 386" | ||||
| GOOS=windows GOARCH=386 go build -mod=vendor -o dist/windows/386/${exe}.exe -ldflags "-H=windowsgui" $gocmd | ||||
| 
 | ||||
| echo "" | ||||
| echo "Darwin (macOS) amd64" | ||||
| GOOS=darwin GOARCH=amd64 go build -mod=vendor -o dist/darwin/amd64/${exe} $gocmd | ||||
| 
 | ||||
| echo "" | ||||
| echo "Linux amd64" | ||||
| GOOS=linux GOARCH=amd64 go build -mod=vendor -o dist/linux/amd64/${exe} $gocmd | ||||
| echo "Linux 386" | ||||
| GOOS=linux GOARCH=386 go build -mod=vendor -o dist/linux/386/${exe} $gocmd | ||||
| 
 | ||||
| echo "" | ||||
| echo "RPi 4 (64-bit) ARMv8" | ||||
| GOOS=linux GOARCH=arm64 go build -mod=vendor -o dist/linux/armv8/${exe} $gocmd | ||||
| echo "RPi 3 B+ ARMv7" | ||||
| GOOS=linux GOARCH=arm GOARM=7 go build -mod=vendor -o dist/linux/armv7/${exe} $gocmd | ||||
| echo "ARMv6" | ||||
| GOOS=linux GOARCH=arm GOARM=6 go build -mod=vendor -o dist/linux/armv6/${exe} $gocmd | ||||
| echo "RPi Zero ARMv5" | ||||
| GOOS=linux GOARCH=arm GOARM=5 go build -mod=vendor -o dist/linux/armv5/${exe} $gocmd | ||||
| 
 | ||||
| echo "" | ||||
| rsync -av ./dist/ ubuntu@rootprojects.org:/srv/www/rootprojects.org/serviceman/dist/ | ||||
| # https://rootprojects.org/serviceman/dist/windows/amd64/serviceman.exe | ||||
| @ -1,7 +1,7 @@ | ||||
| // Package installer can be used cross-platform to install apps | ||||
| // Package manager can be used cross-platform to add apps | ||||
| // as either userspace or system services for fairly simple applications. | ||||
| // This is not intended for complex installers. | ||||
| // This is not intended for complex or highly platform-specific service installers. | ||||
| // | ||||
| // I'm prototyping this out to be useful for more than just watchdog | ||||
| // hence there are a few unnecessary things for the sake of the trying it out | ||||
| package installer | ||||
| package manager | ||||
| @ -1,4 +1,4 @@ | ||||
| package installer | ||||
| package manager | ||||
| 
 | ||||
| import ( | ||||
| 	"io" | ||||
| @ -1,6 +1,6 @@ | ||||
| //go:generate go run -mod=vendor github.com/UnnoTed/fileb0x b0x.toml | ||||
| 
 | ||||
| package installer | ||||
| package manager | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| @ -1,4 +1,4 @@ | ||||
| package installer | ||||
| package manager | ||||
| 
 | ||||
| import ( | ||||
| 	"bytes" | ||||
| @ -9,7 +9,7 @@ import ( | ||||
| 	"strings" | ||||
| 	"text/template" | ||||
| 
 | ||||
| 	"git.rootprojects.org/root/go-serviceman/installer/static" | ||||
| 	"git.rootprojects.org/root/go-serviceman/manager/static" | ||||
| 	"git.rootprojects.org/root/go-serviceman/service" | ||||
| ) | ||||
| 
 | ||||
| @ -1,4 +1,4 @@ | ||||
| package installer | ||||
| package manager | ||||
| 
 | ||||
| import ( | ||||
| 	"bytes" | ||||
| @ -8,7 +8,7 @@ import ( | ||||
| 	"path/filepath" | ||||
| 	"text/template" | ||||
| 
 | ||||
| 	"git.rootprojects.org/root/go-serviceman/installer/static" | ||||
| 	"git.rootprojects.org/root/go-serviceman/manager/static" | ||||
| 	"git.rootprojects.org/root/go-serviceman/service" | ||||
| ) | ||||
| 
 | ||||
| @ -1,6 +1,6 @@ | ||||
| // +build !windows,!linux,!darwin | ||||
| 
 | ||||
| package installer | ||||
| package manager | ||||
| 
 | ||||
| import ( | ||||
| 	"git.rootprojects.org/root/go-serviceman/service" | ||||
| @ -1,4 +1,4 @@ | ||||
| package installer | ||||
| package manager | ||||
| 
 | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| @ -1,4 +1,4 @@ | ||||
| // Code generated by fileb0x at "2019-07-02 00:24:56.633505 -0600 MDT m=+0.003518020" from config file "b0x.toml" DO NOT EDIT. | ||||
| // Code generated by fileb0x at "2019-07-04 01:21:07.139664 -0600 MDT m=+0.003157447" from config file "b0x.toml" DO NOT EDIT. | ||||
| // modification hash(7ce890c82a9c0a430fe55cf7f579e8b4.acdb557394f98d3c09c0bb4d4b9142f8) | ||||
| 
 | ||||
| package static | ||||
| @ -1,6 +1,6 @@ | ||||
| // +build !windows | ||||
| 
 | ||||
| package installer | ||||
| package manager | ||||
| 
 | ||||
| import "os/user" | ||||
| 
 | ||||
| @ -1,4 +1,4 @@ | ||||
| package installer | ||||
| package manager | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| @ -12,7 +12,7 @@ import ( | ||||
| 	"strings" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"git.rootprojects.org/root/go-serviceman/installer" | ||||
| 	"git.rootprojects.org/root/go-serviceman/manager" | ||||
| 	"git.rootprojects.org/root/go-serviceman/runner" | ||||
| 	"git.rootprojects.org/root/go-serviceman/service" | ||||
| ) | ||||
| @ -22,7 +22,7 @@ var GitVersion = "v0.0.0" | ||||
| var GitTimestamp = time.Now().Format(time.RFC3339) | ||||
| 
 | ||||
| func usage() { | ||||
| 	fmt.Println("Usage: serviceman install ./foo-app -- --foo-arg") | ||||
| 	fmt.Println("Usage: serviceman add ./foo-app -- --foo-arg") | ||||
| 	fmt.Println("Usage: serviceman run --config ./foo-app.json") | ||||
| } | ||||
| 
 | ||||
| @ -36,8 +36,10 @@ func main() { | ||||
| 	top := os.Args[1] | ||||
| 	os.Args = append(os.Args[:1], os.Args[2:]...) | ||||
| 	switch top { | ||||
| 	case "install": | ||||
| 		install() | ||||
| 	case "version": | ||||
| 		fmt.Println(GitVersion, GitTimestamp, GitRev) | ||||
| 	case "add": | ||||
| 		add() | ||||
| 	case "run": | ||||
| 		run() | ||||
| 	default: | ||||
| @ -47,7 +49,7 @@ func main() { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func install() { | ||||
| func add() { | ||||
| 	conf := &service.Service{ | ||||
| 		Restart: true, | ||||
| 	} | ||||
| @ -73,8 +75,8 @@ func install() { | ||||
| 	flag.StringVar(&conf.URL, "url", "", "the documentation on home page of the service") | ||||
| 	//flag.StringVar(&conf.Workdir, "workdir", "", "the directory in which the service should be started") | ||||
| 	flag.StringVar(&conf.ReverseDNS, "rdns", "", "a plist-friendly Reverse DNS name for launchctl (ex: com.example.foo-app)") | ||||
| 	flag.BoolVar(&forSystem, "system", false, "attempt to install system service as an unprivileged/unelevated user") | ||||
| 	flag.BoolVar(&forUser, "user", false, "install user space / user mode service even when admin/root/sudo/elevated") | ||||
| 	flag.BoolVar(&forSystem, "system", false, "attempt to add system service as an unprivileged/unelevated user") | ||||
| 	flag.BoolVar(&forUser, "user", false, "add user space / user mode service even when admin/root/sudo/elevated") | ||||
| 	flag.BoolVar(&force, "force", false, "if the interpreter or executable doesn't exist, or things don't make sense, try anyway") | ||||
| 	flag.StringVar(&conf.User, "username", "", "run the service as this user") | ||||
| 	flag.StringVar(&conf.Group, "groupname", "", "run the service as this group") | ||||
| @ -92,17 +94,17 @@ func install() { | ||||
| 	} else if forSystem { | ||||
| 		conf.System = true | ||||
| 	} else { | ||||
| 		conf.System = installer.IsPrivileged() | ||||
| 		conf.System = manager.IsPrivileged() | ||||
| 	} | ||||
| 
 | ||||
| 	n := len(args) | ||||
| 	if 0 == n { | ||||
| 		fmt.Println("Usage: serviceman install ./foo-app -- --foo-arg") | ||||
| 		fmt.Println("Usage: serviceman add ./foo-app -- --foo-arg") | ||||
| 		os.Exit(2) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	execpath, err := installer.WhereIs(args[0]) | ||||
| 	execpath, err := manager.WhereIs(args[0]) | ||||
| 	if nil != err { | ||||
| 		fmt.Fprintf(os.Stderr, "Error: '%s' could not be found.\n", args[0]) | ||||
| 		if !force { | ||||
| @ -125,11 +127,11 @@ func install() { | ||||
| 
 | ||||
| 	//fmt.Printf("\n%#v\n\n", conf) | ||||
| 
 | ||||
| 	err = installer.Install(conf) | ||||
| 	err = manager.Install(conf) | ||||
| 	if nil != err { | ||||
| 		fmt.Fprintf(os.Stderr, "%s\n", err) | ||||
| 		fmt.Fprintf(os.Stderr, "Use 'sudo' to install as a privileged system service.\n") | ||||
| 		fmt.Fprintf(os.Stderr, "Use '--user' to install as an user service.\n") | ||||
| 		fmt.Fprintf(os.Stderr, "Use 'sudo' to add service as a privileged system service.\n") | ||||
| 		fmt.Fprintf(os.Stderr, "Use '--user' to add service as an user service.\n") | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user