Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions command.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"strings"
)

var flagEnv string
var flagProcfile string

type Command struct {
Expand Down Expand Up @@ -37,7 +36,7 @@ func (c *Command) Name() string {
}

func (c *Command) Runnable() bool {
return c.Run != nil && c.Disabled != true
return c.Run != nil && !c.Disabled
}

func (c *Command) List() bool {
Expand Down
61 changes: 44 additions & 17 deletions env.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,35 @@ package main
import (
"fmt"
"os"
"regexp"
"sync"

"github.com/subosito/gotenv"
)

var envEntryRegexp = regexp.MustCompile("^([A-Za-z_0-9]+)=(.*)$")
type Env struct {
m sync.Map
}

type Env map[string]string
func (e *Env) Get(key string) string {
value, ok := e.m.Load(key)
if !ok {
return ""
}
return value.(string)
}

func (e *Env) Set(key, value string) {
e.m.Store(key, value)
}

func (e *Env) Delete(key string) {
e.m.Delete(key)
}

// NewEnv makes a new environment
func NewEnv() *Env {
return &Env{sync.Map{}}
}

type envFiles []string

Expand All @@ -23,13 +44,14 @@ func (e *envFiles) Set(value string) error {
return nil
}

func loadEnvs(files []string) (Env, error) {
func loadEnvs(files []string) (*Env, error) {
if len(files) == 0 {
files = []string{".env"}
}

env := make(Env)
env := NewEnv()

// don't need to lock either environment
for _, file := range files {
tmpEnv, err := ReadEnv(file)

Expand All @@ -38,35 +60,40 @@ func loadEnvs(files []string) (Env, error) {
}

// Merge the file I just read into the env.
for k, v := range tmpEnv {
env[k] = v
}
tmpEnv.m.Range(func(key, value interface{}) bool {
env.m.Store(key, value)
return true
})
}
return env, nil
}

func ReadEnv(filename string) (Env, error) {
func ReadEnv(filename string) (*Env, error) {
env := NewEnv()

if _, err := os.Stat(filename); os.IsNotExist(err) {
return make(Env), nil
return env, nil
}

fd, err := os.Open(filename)
if err != nil {
return nil, err
}
defer fd.Close()
env := make(Env)

for key, val := range gotenv.Parse(fd) {
env[key] = val
env.Set(key, val)
}
return env, nil
}

func (e *Env) asArray() (env []string) {
for _, pair := range os.Environ() {
env = append(env, pair)
}
for name, val := range *e {
env = append(env, os.Environ()...)

e.m.Range(func(name, val interface{}) bool {
env = append(env, fmt.Sprintf("%s=%s", name, val))
}
return true
})

return
}
4 changes: 2 additions & 2 deletions env_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ func TestMultipleEnvironmentFiles(t *testing.T) {
t.Fatalf("Could not read environments: %s", err)
}

if env["env1"] == "" {
if env.Get("env1") == "" {
t.Fatal("$env1 should be present and is not")
}

if env["env2"] == "" {
if env.Get("env2") == "" {
t.Fatal("$env2 should be present and is not")
}
}
4 changes: 2 additions & 2 deletions process.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ import (

type Process struct {
Command string
Env Env
Env *Env
Interactive bool

*exec.Cmd
}

func NewProcess(workdir, command string, env Env, interactive bool) (p *Process) {
func NewProcess(workdir, command string, env *Env, interactive bool) (p *Process) {
argv := ShellInvocationCommand(interactive, workdir, command)
return &Process{
command, env, interactive, exec.Command(argv[0], argv[1:]...),
Expand Down
4 changes: 2 additions & 2 deletions procfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
"regexp"
)

var procfileEntryRegexp = regexp.MustCompile("^([A-Za-z0-9_-]+):\\s*(.+)$")
var procfileEntryRegexp = regexp.MustCompile(`^([A-Za-z0-9_-]+):\s*(.+)$`)

type ProcfileEntry struct {
Name string
Expand Down Expand Up @@ -68,7 +68,7 @@ func parseProcfile(r io.Reader) (*Procfile, error) {
}
}
if err := scanner.Err(); err != nil {
return nil, fmt.Errorf("Reading Procfile: %s", err)
return nil, fmt.Errorf("reading Procfile: %s", err)
}
return pf, nil
}
16 changes: 9 additions & 7 deletions start.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,13 +121,13 @@ func parseConcurrency(value string) (map[string]int, error) {
parts := strings.Split(value, ",")
for _, part := range parts {
if !strings.Contains(part, "=") {
return concurrency, errors.New("Concurrency should be in the format: foo=1,bar=2")
return concurrency, errors.New("concurrency should be in the format: foo=1,bar=2")
}

nameValue := strings.Split(part, "=")
n, v := strings.TrimSpace(nameValue[0]), strings.TrimSpace(nameValue[1])
if n == "" || v == "" {
return concurrency, errors.New("Concurrency should be in the format: foo=1,bar=2")
return concurrency, errors.New("concurrency should be in the format: foo=1,bar=2")
}

numProcs, err := strconv.ParseInt(v, 10, 16)
Expand Down Expand Up @@ -169,18 +169,19 @@ func (f *Forego) monitorInterrupt() {
}
}

func basePort(env Env) (int, error) {
func basePort(env *Env) (int, error) {

if flagPort != defaultPort {
return flagPort, nil
} else if env["PORT"] != "" {
return strconv.Atoi(env["PORT"])
} else if port := env.Get("PORT"); port != "" {
return strconv.Atoi(port)
} else if os.Getenv("PORT") != "" {
return strconv.Atoi(os.Getenv("PORT"))
}
return defaultPort, nil
}

func (f *Forego) startProcess(idx, procNum int, proc ProcfileEntry, env Env, of *OutletFactory) {
func (f *Forego) startProcess(idx, procNum int, proc ProcfileEntry, env *Env, of *OutletFactory) {
port, err := basePort(env)
if err != nil {
panic(err)
Expand All @@ -192,7 +193,8 @@ func (f *Forego) startProcess(idx, procNum int, proc ProcfileEntry, env Env, of
workDir := filepath.Dir(flagProcfile)
ps := NewProcess(workDir, proc.Command, env, interactive)
procName := fmt.Sprint(proc.Name, ".", procNum+1)
ps.Env["PORT"] = strconv.Itoa(port)

ps.Env.Set("PORT", strconv.Itoa(port))

ps.Stdin = nil

Expand Down
8 changes: 4 additions & 4 deletions start_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ func TestParseConcurrencyFlagNoValue(t *testing.T) {
}

func TestPortFromEnv(t *testing.T) {
env := make(Env)
env := NewEnv()
port, err := basePort(env)
if err != nil {
t.Fatalf("Can not get base port: %s", err)
Expand All @@ -129,7 +129,7 @@ func TestPortFromEnv(t *testing.T) {
t.Fatal("Base port should be 4000")
}

env["PORT"] = "6000"
env.Set("PORT", "6000")
port, err = basePort(env)
if err != nil {
t.Fatalf("Can not get base port: %s", err)
Expand All @@ -138,8 +138,8 @@ func TestPortFromEnv(t *testing.T) {
t.Fatal("Base port should be 6000")
}

env["PORT"] = "forego"
port, err = basePort(env)
env.Set("PORT", "forego")
_, err = basePort(env)
if err == nil {
t.Fatalf("Port 'forego' should fail: %s", err)
}
Expand Down
5 changes: 3 additions & 2 deletions unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import (
"syscall"
)

var osShell string = "bash"

const osHaveSigTerm = true

func ShellInvocationCommand(interactive bool, root, command string) []string {
Expand All @@ -15,15 +17,14 @@ func ShellInvocationCommand(interactive bool, root, command string) []string {
shellArgument = "-ic"
}
shellCommand := fmt.Sprintf("cd \"%s\"; source .profile 2>/dev/null; exec %s", root, command)
return []string{"sh", shellArgument, shellCommand}
return []string{osShell, shellArgument, shellCommand}
}

func (p *Process) PlatformSpecificInit() {
if !p.Interactive {
p.SysProcAttr = &syscall.SysProcAttr{}
p.SysProcAttr.Setsid = true
}
return
}

func (p *Process) SendSigTerm() {
Expand Down