mirror of
https://github.com/go-sylixos/elvish.git
synced 2024-12-05 03:17:50 +08:00
pkg/prog: Move all Program implementations into own packages.
This fixes #985.
This commit is contained in:
parent
5b88057c94
commit
928949077b
10
main.go
10
main.go
|
@ -7,13 +7,15 @@ package main
|
|||
import (
|
||||
"os"
|
||||
|
||||
"github.com/elves/elvish/pkg/buildinfo"
|
||||
"github.com/elves/elvish/pkg/daemon"
|
||||
"github.com/elves/elvish/pkg/prog"
|
||||
"github.com/elves/elvish/pkg/prog/shell"
|
||||
"github.com/elves/elvish/pkg/prog/web"
|
||||
)
|
||||
|
||||
func main() {
|
||||
os.Exit(prog.Run(
|
||||
[3]*os.File{os.Stdin, os.Stdout, os.Stderr},
|
||||
os.Args,
|
||||
prog.VersionProgram{}, prog.BuildInfoProgram{}, prog.DaemonProgram{},
|
||||
prog.WebProgram{}, prog.ShellProgram{}))
|
||||
[3]*os.File{os.Stdin, os.Stdout, os.Stderr}, os.Args,
|
||||
buildinfo.Program, daemon.Program, web.Program, shell.Program))
|
||||
}
|
||||
|
|
|
@ -5,8 +5,40 @@
|
|||
// "go get".
|
||||
package buildinfo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
|
||||
"github.com/elves/elvish/pkg/prog"
|
||||
)
|
||||
|
||||
// Build information.
|
||||
var (
|
||||
Version = "unknown"
|
||||
Reproducible = "false"
|
||||
)
|
||||
|
||||
// Program is the buildinfo subprogram.
|
||||
var Program prog.Program = program{}
|
||||
|
||||
type program struct{}
|
||||
|
||||
func (program) ShouldRun(f *prog.Flags) bool { return f.Version || f.BuildInfo }
|
||||
|
||||
func (program) Run(fds [3]*os.File, f *prog.Flags, _ []string) error {
|
||||
if f.Version {
|
||||
fmt.Fprintln(fds[1], Version)
|
||||
return nil
|
||||
}
|
||||
if f.JSON {
|
||||
fmt.Fprintf(fds[1],
|
||||
`{"version":%s,"goversion":%s,"reproducible":%v}`+"\n",
|
||||
quoteJSON(Version), quoteJSON(runtime.Version()), Reproducible)
|
||||
} else {
|
||||
fmt.Fprintln(fds[1], "Version:", Version)
|
||||
fmt.Fprintln(fds[1], "Go version:", runtime.Version())
|
||||
fmt.Fprintln(fds[1], "Reproducible build:", Reproducible)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
60
pkg/buildinfo/buildinfo_test.go
Normal file
60
pkg/buildinfo/buildinfo_test.go
Normal file
|
@ -0,0 +1,60 @@
|
|||
package buildinfo
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/elves/elvish/pkg/prog"
|
||||
. "github.com/elves/elvish/pkg/prog/progtest"
|
||||
)
|
||||
|
||||
func TestVersion(t *testing.T) {
|
||||
f := Setup()
|
||||
defer f.Cleanup()
|
||||
|
||||
prog.Run(f.Fds(), Elvish("-version"), Program)
|
||||
|
||||
f.TestOut(t, 1, Version+"\n")
|
||||
}
|
||||
|
||||
func TestBuildInfo(t *testing.T) {
|
||||
f := Setup()
|
||||
defer f.Cleanup()
|
||||
|
||||
prog.Run(f.Fds(), Elvish("-buildinfo"), Program)
|
||||
|
||||
f.TestOut(t, 1,
|
||||
fmt.Sprintf(
|
||||
"Version: %v\nGo version: %v\nReproducible build: %v\n",
|
||||
Version,
|
||||
runtime.Version(),
|
||||
Reproducible))
|
||||
}
|
||||
|
||||
func TestBuildInfo_JSON(t *testing.T) {
|
||||
f := Setup()
|
||||
defer f.Cleanup()
|
||||
|
||||
prog.Run(f.Fds(), Elvish("-buildinfo", "-json"), Program)
|
||||
|
||||
f.TestOut(t, 1,
|
||||
mustToJSON(struct {
|
||||
Version string `json:"version"`
|
||||
GoVersion string `json:"goversion"`
|
||||
Reproducible bool `json:"reproducible"`
|
||||
}{
|
||||
Version,
|
||||
runtime.Version(),
|
||||
Reproducible == "true",
|
||||
})+"\n")
|
||||
}
|
||||
|
||||
func mustToJSON(v interface{}) string {
|
||||
b, err := json.Marshal(v)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return string(b)
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package prog
|
||||
package buildinfo
|
||||
|
||||
import (
|
||||
"bytes"
|
|
@ -1,4 +1,4 @@
|
|||
package prog
|
||||
package buildinfo
|
||||
|
||||
import "testing"
|
||||
|
|
@ -5,9 +5,30 @@
|
|||
// store package and are not documented here.
|
||||
package daemon
|
||||
|
||||
import "github.com/elves/elvish/pkg/util"
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/elves/elvish/pkg/prog"
|
||||
"github.com/elves/elvish/pkg/util"
|
||||
)
|
||||
|
||||
var logger = util.GetLogger("[daemon] ")
|
||||
|
||||
// Version is the API version. It should be bumped any time the API changes.
|
||||
const Version = -93
|
||||
|
||||
// Program is the daemon subprogram.
|
||||
var Program prog.Program = program{}
|
||||
|
||||
type program struct{}
|
||||
|
||||
func (program) ShouldRun(f *prog.Flags) bool { return f.Daemon }
|
||||
|
||||
func (program) Run(fds [3]*os.File, f *prog.Flags, args []string) error {
|
||||
if len(args) > 0 {
|
||||
return prog.BadUsage("arguments are not allowed with -daemon")
|
||||
}
|
||||
setUmaskForDaemon()
|
||||
Serve(f.Sock, f.DB)
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -5,6 +5,8 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/elves/elvish/pkg/prog"
|
||||
. "github.com/elves/elvish/pkg/prog/progtest"
|
||||
"github.com/elves/elvish/pkg/store/storetest"
|
||||
"github.com/elves/elvish/pkg/testutil"
|
||||
"github.com/elves/elvish/pkg/util"
|
||||
|
@ -54,3 +56,12 @@ func TestDaemon(t *testing.T) {
|
|||
storetest.TestDir(t, client)
|
||||
storetest.TestSharedVar(t, client)
|
||||
}
|
||||
|
||||
func TestProgram_SpuriousArgument(t *testing.T) {
|
||||
f := Setup()
|
||||
defer f.Cleanup()
|
||||
|
||||
exit := prog.Run(f.Fds(), Elvish("-daemon", "x"), Program)
|
||||
|
||||
TestError(t, f, exit, "arguments are not allowed with -daemon")
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// +build !windows,!plan9,!js
|
||||
|
||||
package prog
|
||||
package daemon
|
||||
|
||||
import "golang.org/x/sys/unix"
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package prog
|
||||
package daemon
|
||||
|
||||
// No-op on Windows.
|
||||
func setUmaskForDaemon() {}
|
|
@ -1,36 +0,0 @@
|
|||
package prog
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
|
||||
"github.com/elves/elvish/pkg/buildinfo"
|
||||
)
|
||||
|
||||
type BuildInfoProgram struct{}
|
||||
|
||||
func (BuildInfoProgram) ShouldRun(f *Flags) bool { return f.BuildInfo }
|
||||
|
||||
func (BuildInfoProgram) Run(fds [3]*os.File, f *Flags, _ []string) error {
|
||||
if f.JSON {
|
||||
fmt.Fprintf(fds[1],
|
||||
`{"version":%s,"goversion":%s,"reproducible":%v}`+"\n",
|
||||
quoteJSON(buildinfo.Version), quoteJSON(runtime.Version()),
|
||||
buildinfo.Reproducible)
|
||||
} else {
|
||||
fmt.Fprintln(fds[1], "Version:", buildinfo.Version)
|
||||
fmt.Fprintln(fds[1], "Go version:", runtime.Version())
|
||||
fmt.Fprintln(fds[1], "Reproducible build:", buildinfo.Reproducible)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type VersionProgram struct{}
|
||||
|
||||
func (VersionProgram) ShouldRun(f *Flags) bool { return f.Version }
|
||||
|
||||
func (VersionProgram) Run(fds [3]*os.File, _ *Flags, _ []string) error {
|
||||
fmt.Fprintln(fds[1], buildinfo.Version)
|
||||
return nil
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
package prog
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/elves/elvish/pkg/daemon"
|
||||
)
|
||||
|
||||
type DaemonProgram struct{}
|
||||
|
||||
func (DaemonProgram) ShouldRun(f *Flags) bool { return f.Daemon }
|
||||
|
||||
func (DaemonProgram) Run(fds [3]*os.File, f *Flags, args []string) error {
|
||||
if len(args) > 0 {
|
||||
return BadUsage("arguments are not allowed with -daemon")
|
||||
}
|
||||
setUmaskForDaemon()
|
||||
daemon.Serve(f.Sock, f.DB)
|
||||
return nil
|
||||
}
|
|
@ -2,60 +2,16 @@ package prog
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/elves/elvish/pkg/buildinfo"
|
||||
. "github.com/elves/elvish/pkg/prog/progtest"
|
||||
)
|
||||
|
||||
func TestVersion(t *testing.T) {
|
||||
f := Setup()
|
||||
defer f.Cleanup()
|
||||
|
||||
Run(f.Fds(), elvish("-version"), VersionProgram{})
|
||||
|
||||
f.TestOut(t, 1, buildinfo.Version+"\n")
|
||||
}
|
||||
|
||||
func TestBuildInfo(t *testing.T) {
|
||||
f := Setup()
|
||||
defer f.Cleanup()
|
||||
|
||||
Run(f.Fds(), elvish("-buildinfo"), BuildInfoProgram{})
|
||||
|
||||
f.TestOut(t, 1,
|
||||
fmt.Sprintf(
|
||||
"Version: %v\nGo version: %v\nReproducible build: %v\n",
|
||||
buildinfo.Version,
|
||||
runtime.Version(),
|
||||
buildinfo.Reproducible))
|
||||
}
|
||||
|
||||
func TestBuildInfo_JSON(t *testing.T) {
|
||||
f := Setup()
|
||||
defer f.Cleanup()
|
||||
|
||||
Run(f.Fds(), elvish("-buildinfo", "-json"), BuildInfoProgram{})
|
||||
|
||||
f.TestOut(t, 1,
|
||||
mustToJSON(struct {
|
||||
Version string `json:"version"`
|
||||
GoVersion string `json:"goversion"`
|
||||
Reproducible bool `json:"reproducible"`
|
||||
}{
|
||||
buildinfo.Version,
|
||||
runtime.Version(),
|
||||
buildinfo.Reproducible == "true",
|
||||
})+"\n")
|
||||
}
|
||||
|
||||
func TestHelp(t *testing.T) {
|
||||
f := Setup()
|
||||
defer f.Cleanup()
|
||||
|
||||
Run(f.Fds(), elvish("-help"))
|
||||
Run(f.Fds(), Elvish("-help"))
|
||||
|
||||
f.TestOutSnippet(t, 1, "Usage: elvish [flags] [script]")
|
||||
}
|
||||
|
@ -64,40 +20,9 @@ func TestBadFlag(t *testing.T) {
|
|||
f := Setup()
|
||||
defer f.Cleanup()
|
||||
|
||||
exit := Run(f.Fds(), elvish("-bad-flag"))
|
||||
exit := Run(f.Fds(), Elvish("-bad-flag"))
|
||||
|
||||
testError(t, f, exit, "flag provided but not defined: -bad-flag")
|
||||
}
|
||||
|
||||
func TestWeb_SpuriousArgument(t *testing.T) {
|
||||
f := Setup()
|
||||
defer f.Cleanup()
|
||||
|
||||
exit := Run(f.Fds(), elvish("-web", "x"), WebProgram{})
|
||||
|
||||
testError(t, f, exit, "arguments are not allowed with -web")
|
||||
}
|
||||
|
||||
func TestWeb_SpuriousC(t *testing.T) {
|
||||
f := Setup()
|
||||
defer f.Cleanup()
|
||||
|
||||
exit := Run(f.Fds(), elvish("-web", "-c"), WebProgram{})
|
||||
|
||||
testError(t, f, exit, "-c cannot be used together with -web")
|
||||
}
|
||||
|
||||
func TestDaemon_SpuriousArgument(t *testing.T) {
|
||||
f := Setup()
|
||||
defer f.Cleanup()
|
||||
|
||||
exit := Run(f.Fds(), elvish("-daemon", "x"), DaemonProgram{})
|
||||
|
||||
testError(t, f, exit, "arguments are not allowed with -daemon")
|
||||
}
|
||||
|
||||
func elvish(args ...string) []string {
|
||||
return append([]string{"elvish"}, args...)
|
||||
TestError(t, f, exit, "flag provided but not defined: -bad-flag")
|
||||
}
|
||||
|
||||
func mustToJSON(v interface{}) string {
|
||||
|
@ -107,11 +32,3 @@ func mustToJSON(v interface{}) string {
|
|||
}
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func testError(t *testing.T, f *Fixture, exit int, wantErrSnippet string) {
|
||||
t.Helper()
|
||||
if exit != 2 {
|
||||
t.Errorf("got exit %v, want 2", exit)
|
||||
}
|
||||
f.TestOutSnippet(t, 2, wantErrSnippet)
|
||||
}
|
||||
|
|
|
@ -113,3 +113,17 @@ func MustWriteFile(name, content string) {
|
|||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Elvish returns an argument slice starting with "elvish".
|
||||
func Elvish(args ...string) []string {
|
||||
return append([]string{"elvish"}, args...)
|
||||
}
|
||||
|
||||
// TestError tests the error result of a program.
|
||||
func TestError(t *testing.T, f *Fixture, exit int, wantErrSnippet string) {
|
||||
t.Helper()
|
||||
if exit != 2 {
|
||||
t.Errorf("got exit %v, want 2", exit)
|
||||
}
|
||||
f.TestOutSnippet(t, 2, wantErrSnippet)
|
||||
}
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
package prog
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/elves/elvish/pkg/prog/shell"
|
||||
)
|
||||
|
||||
type ShellProgram struct{}
|
||||
|
||||
func (ShellProgram) ShouldRun(*Flags) bool { return true }
|
||||
|
||||
func (ShellProgram) Run(fds [3]*os.File, f *Flags, args []string) error {
|
||||
p := shell.MakePaths(fds[2],
|
||||
shell.Paths{Bin: f.Bin, Sock: f.Sock, Db: f.DB})
|
||||
if f.NoRc {
|
||||
p.Rc = ""
|
||||
}
|
||||
if len(args) > 0 {
|
||||
exit := shell.Script(
|
||||
fds, args, &shell.ScriptConfig{
|
||||
SpawnDaemon: true, Paths: p,
|
||||
Cmd: f.CodeInArg, CompileOnly: f.CompileOnly, JSON: f.JSON})
|
||||
return Exit(exit)
|
||||
}
|
||||
shell.Interact(fds, &shell.InteractConfig{SpawnDaemon: true, Paths: p})
|
||||
return nil
|
||||
}
|
|
@ -9,12 +9,37 @@ import (
|
|||
|
||||
"github.com/elves/elvish/pkg/cli/term"
|
||||
"github.com/elves/elvish/pkg/eval"
|
||||
"github.com/elves/elvish/pkg/prog"
|
||||
"github.com/elves/elvish/pkg/sys"
|
||||
"github.com/elves/elvish/pkg/util"
|
||||
)
|
||||
|
||||
var logger = util.GetLogger("[shell] ")
|
||||
|
||||
// Program is the shell subprogram.
|
||||
var Program prog.Program = program{}
|
||||
|
||||
type program struct{}
|
||||
|
||||
func (program) ShouldRun(*prog.Flags) bool { return true }
|
||||
|
||||
func (program) Run(fds [3]*os.File, f *prog.Flags, args []string) error {
|
||||
p := MakePaths(fds[2],
|
||||
Paths{Bin: f.Bin, Sock: f.Sock, Db: f.DB})
|
||||
if f.NoRc {
|
||||
p.Rc = ""
|
||||
}
|
||||
if len(args) > 0 {
|
||||
exit := Script(
|
||||
fds, args, &ScriptConfig{
|
||||
SpawnDaemon: true, Paths: p,
|
||||
Cmd: f.CodeInArg, CompileOnly: f.CompileOnly, JSON: f.JSON})
|
||||
return prog.Exit(exit)
|
||||
}
|
||||
Interact(fds, &InteractConfig{SpawnDaemon: true, Paths: p})
|
||||
return nil
|
||||
}
|
||||
|
||||
func setupShell(fds [3]*os.File, p Paths, spawn bool) (*eval.Evaler, func()) {
|
||||
restoreTTY := term.SetupGlobal()
|
||||
ev := InitRuntime(fds[2], p, spawn)
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
package prog
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/elves/elvish/pkg/prog/web"
|
||||
)
|
||||
|
||||
type WebProgram struct{}
|
||||
|
||||
func (WebProgram) ShouldRun(f *Flags) bool { return f.Web }
|
||||
|
||||
func (WebProgram) Run(fds [3]*os.File, f *Flags, args []string) error {
|
||||
if len(args) > 0 {
|
||||
return BadUsage("arguments are not allowed with -web")
|
||||
}
|
||||
if f.CodeInArg {
|
||||
return BadUsage("-c cannot be used together with -web")
|
||||
}
|
||||
p := web.Web{BinPath: f.Bin, SockPath: f.Sock, DbPath: f.DB, Port: f.Port}
|
||||
return p.Main(fds, nil)
|
||||
}
|
|
@ -12,9 +12,28 @@ import (
|
|||
"os"
|
||||
|
||||
"github.com/elves/elvish/pkg/eval"
|
||||
"github.com/elves/elvish/pkg/prog"
|
||||
"github.com/elves/elvish/pkg/prog/shell"
|
||||
)
|
||||
|
||||
// Program is the web subprogram.
|
||||
var Program prog.Program = program{}
|
||||
|
||||
type program struct{}
|
||||
|
||||
func (program) ShouldRun(f *prog.Flags) bool { return f.Web }
|
||||
|
||||
func (program) Run(fds [3]*os.File, f *prog.Flags, args []string) error {
|
||||
if len(args) > 0 {
|
||||
return prog.BadUsage("arguments are not allowed with -web")
|
||||
}
|
||||
if f.CodeInArg {
|
||||
return prog.BadUsage("-c cannot be used together with -web")
|
||||
}
|
||||
p := Web{BinPath: f.Bin, SockPath: f.Sock, DbPath: f.DB, Port: f.Port}
|
||||
return p.Main(fds, nil)
|
||||
}
|
||||
|
||||
type Web struct {
|
||||
BinPath string
|
||||
SockPath string
|
||||
|
|
|
@ -1,7 +1,26 @@
|
|||
package web
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"testing"
|
||||
|
||||
func TestWeb(t *testing.T) {
|
||||
// TODO(xiaq): Add tests.
|
||||
"github.com/elves/elvish/pkg/prog"
|
||||
. "github.com/elves/elvish/pkg/prog/progtest"
|
||||
)
|
||||
|
||||
func TestWeb_SpuriousArgument(t *testing.T) {
|
||||
f := Setup()
|
||||
defer f.Cleanup()
|
||||
|
||||
exit := prog.Run(f.Fds(), Elvish("-web", "x"), Program)
|
||||
|
||||
TestError(t, f, exit, "arguments are not allowed with -web")
|
||||
}
|
||||
|
||||
func TestWeb_SpuriousC(t *testing.T) {
|
||||
f := Setup()
|
||||
defer f.Cleanup()
|
||||
|
||||
exit := prog.Run(f.Fds(), Elvish("-web", "-c"), Program)
|
||||
|
||||
TestError(t, f, exit, "-c cannot be used together with -web")
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user