<commit_before>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package tar implements access to tar archives.
// It aims to cover most of the variations, including those produced
// by GNU and BSD tars.
//
// References:
//   http://www.freebsd.org/cgi/man.cgi?query=tar&sektion=5
//   http://www.gnu.org/software/tar/manual/html_node/Standard.html
package tar

import (
	"errors"
	"fmt"
	"os"
	"time"
)

const (
	blockSize = 512

	// Types
	TypeReg           = '0'    // regular file
	TypeRegA          = '\x00' // regular file
	TypeLink          = '1'    // hard link
	TypeSymlink       = '2'    // symbolic link
	TypeChar          = '3'    // character device node
	TypeBlock         = '4'    // block device node
	TypeDir           = '5'    // directory
	TypeFifo          = '6'    // fifo node
	TypeCont          = '7'    // reserved
	TypeXHeader       = 'x'    // extended header
	TypeXGlobalHeader = 'g'    // global extended header
)

// A Header represents a single header in a tar archive.
// Some fields may not be populated.
type Header struct {
	Name       string    // name of header file entry
	Mode       int64     // permission and mode bits
	Uid        int       // user id of owner
	Gid        int       // group id of owner
	Size       int64     // length in bytes
	ModTime    time.Time // modified time
	Typeflag   byte      // type of header entry
	Linkname   string    // target name of link
	Uname      string    // user name of owner
	Gname      string    // group name of owner
	Devmajor   int64     // major number of character or block device
	Devminor   int64     // minor number of character or block device
	AccessTime time.Time // access time
	ChangeTime time.Time // status change time
}

// sysStat, if non-nil, populates h from system-dependent fields of fi.
var sysStat func(fi os.FileInfo, h *Header) error

// Mode constants from the tar spec.
const (
	c_ISDIR  = 040000
	c_ISFIFO = 010000
	c_ISREG  = 0100000
	c_ISLNK  = 0120000
	c_ISBLK  = 060000
	c_ISCHR  = 020000
	c_ISSOCK = 0140000
)

// FileInfoHeader creates a partially-populated Header from fi.
// If fi describes a symlink, FileInfoHeader records link as the link target.
func FileInfoHeader(fi os.FileInfo, link string) (*Header, error) {
	if fi == nil {
		return nil, errors.New("tar: FileInfo is nil")
	}
	h := &Header{
		Name:    fi.Name(),
		ModTime: fi.ModTime(),
		Mode:    int64(fi.Mode().Perm()), // or'd with c_IS* constants later
	}
	switch {
	case fi.Mode()&os.ModeType == 0:
		h.Mode |= c_ISREG
		h.Typeflag = TypeReg
		h.Size = fi.Size()
	case fi.IsDir():
		h.Typeflag = TypeDir
		h.Mode |= c_ISDIR
	case fi.Mode()&os.ModeSymlink != 0:
		h.Typeflag = TypeSymlink
		h.Mode |= c_ISLNK
		h.Linkname = link
	case fi.Mode()&os.ModeDevice != 0:
		if fi.Mode()&os.ModeCharDevice != 0 {
			h.Mode |= c_ISCHR
			h.Typeflag = TypeChar
		} else {
			h.Mode |= c_ISBLK
			h.Typeflag = TypeBlock
		}
	case fi.Mode()&os.ModeSocket != 0:
		h.Mode |= c_ISSOCK
	default:
		return nil, fmt.Errorf("archive/tar: unknown file mode %v", fi.Mode())
	}
	if sysStat != nil {
		return h, sysStat(fi, h)
	}
	return h, nil
}

var zeroBlock = make([]byte, blockSize)

// POSIX specifies a sum of the unsigned byte values, but the Sun tar uses signed byte values.
// We compute and return both.
func checksum(header []byte) (unsigned int64, signed int64) {
	for i := 0; i < len(header); i++ {
		if i == 148 {
			// The chksum field (header[148:156]) is special: it should be treated as space bytes.
			unsigned += ' ' * 8
			signed += ' ' * 8
			i += 7
			continue
		}
		unsigned += int64(header[i])
		signed += int64(int8(header[i]))
	}
	return
}

type slicer []byte

func (sp *slicer) next(n int) (b []byte) {
	s := *sp
	b, *sp = s[0:n], s[n:]
	return
}
<commit_msg>archive/tar: small simplification using FileMode.<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package tar implements access to tar archives.
// It aims to cover most of the variations, including those produced
// by GNU and BSD tars.
//
// References:
//   http://www.freebsd.org/cgi/man.cgi?query=tar&sektion=5
//   http://www.gnu.org/software/tar/manual/html_node/Standard.html
package tar

import (
	"errors"
	"fmt"
	"os"
	"time"
)

const (
	blockSize = 512

	// Types
	TypeReg           = '0'    // regular file
	TypeRegA          = '\x00' // regular file
	TypeLink          = '1'    // hard link
	TypeSymlink       = '2'    // symbolic link
	TypeChar          = '3'    // character device node
	TypeBlock         = '4'    // block device node
	TypeDir           = '5'    // directory
	TypeFifo          = '6'    // fifo node
	TypeCont          = '7'    // reserved
	TypeXHeader       = 'x'    // extended header
	TypeXGlobalHeader = 'g'    // global extended header
)

// A Header represents a single header in a tar archive.
// Some fields may not be populated.
type Header struct {
	Name       string    // name of header file entry
	Mode       int64     // permission and mode bits
	Uid        int       // user id of owner
	Gid        int       // group id of owner
	Size       int64     // length in bytes
	ModTime    time.Time // modified time
	Typeflag   byte      // type of header entry
	Linkname   string    // target name of link
	Uname      string    // user name of owner
	Gname      string    // group name of owner
	Devmajor   int64     // major number of character or block device
	Devminor   int64     // minor number of character or block device
	AccessTime time.Time // access time
	ChangeTime time.Time // status change time
}

// sysStat, if non-nil, populates h from system-dependent fields of fi.
var sysStat func(fi os.FileInfo, h *Header) error

// Mode constants from the tar spec.
const (
	c_ISDIR  = 040000
	c_ISFIFO = 010000
	c_ISREG  = 0100000
	c_ISLNK  = 0120000
	c_ISBLK  = 060000
	c_ISCHR  = 020000
	c_ISSOCK = 0140000
)

// FileInfoHeader creates a partially-populated Header from fi.
// If fi describes a symlink, FileInfoHeader records link as the link target.
func FileInfoHeader(fi os.FileInfo, link string) (*Header, error) {
	if fi == nil {
		return nil, errors.New("tar: FileInfo is nil")
	}
	h := &Header{
		Name:    fi.Name(),
		ModTime: fi.ModTime(),
		Mode:    int64(fi.Mode().Perm()), // or'd with c_IS* constants later
	}
	switch {
	case fi.Mode().IsRegular():
		h.Mode |= c_ISREG
		h.Typeflag = TypeReg
		h.Size = fi.Size()
	case fi.IsDir():
		h.Typeflag = TypeDir
		h.Mode |= c_ISDIR
	case fi.Mode()&os.ModeSymlink != 0:
		h.Typeflag = TypeSymlink
		h.Mode |= c_ISLNK
		h.Linkname = link
	case fi.Mode()&os.ModeDevice != 0:
		if fi.Mode()&os.ModeCharDevice != 0 {
			h.Mode |= c_ISCHR
			h.Typeflag = TypeChar
		} else {
			h.Mode |= c_ISBLK
			h.Typeflag = TypeBlock
		}
	case fi.Mode()&os.ModeSocket != 0:
		h.Mode |= c_ISSOCK
	default:
		return nil, fmt.Errorf("archive/tar: unknown file mode %v", fi.Mode())
	}
	if sysStat != nil {
		return h, sysStat(fi, h)
	}
	return h, nil
}

var zeroBlock = make([]byte, blockSize)

// POSIX specifies a sum of the unsigned byte values, but the Sun tar uses signed byte values.
// We compute and return both.
func checksum(header []byte) (unsigned int64, signed int64) {
	for i := 0; i < len(header); i++ {
		if i == 148 {
			// The chksum field (header[148:156]) is special: it should be treated as space bytes.
			unsigned += ' ' * 8
			signed += ' ' * 8
			i += 7
			continue
		}
		unsigned += int64(header[i])
		signed += int64(int8(header[i]))
	}
	return
}

type slicer []byte

func (sp *slicer) next(n int) (b []byte) {
	s := *sp
	b, *sp = s[0:n], s[n:]
	return
}
<|endoftext|>


<commit_before>// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// FILE UNDER CONSTRUCTION. ANY AND ALL PARTS MAY CHANGE.
// This file implements the universe and unsafe package scopes.

package types

import "go/ast"

var (
	scope    *ast.Scope // current scope to use for initialization
	Universe *ast.Scope
	Unsafe   *ast.Object // package unsafe
)

func define(kind ast.ObjKind, name string) *ast.Object {
	obj := ast.NewObj(kind, name)
	if scope.Insert(obj) != nil {
		panic("types internal error: double declaration")
	}
	return obj
}

func defType(name string) *Name {
	obj := define(ast.Typ, name)
	typ := &Name{Underlying: &Basic{}, Obj: obj}
	obj.Type = typ
	return typ
}

func defConst(name string) {
	obj := define(ast.Con, name)
	_ = obj // TODO(gri) fill in other properties
}

func defFun(name string) {
	obj := define(ast.Fun, name)
	_ = obj // TODO(gri) fill in other properties
}

var (
	Bool,
	Int,
	Float64,
	Complex128,
	String *Name
)

func init() {
	scope = ast.NewScope(nil)
	Universe = scope

	Bool = defType("bool")
	defType("byte") // TODO(gri) should be an alias for uint8
	defType("rune") // TODO(gri) should be an alias for int
	defType("complex64")
	Complex128 = defType("complex128")
	defType("float32")
	Float64 = defType("float64")
	defType("int8")
	defType("int16")
	defType("int32")
	defType("int64")
	String = defType("string")
	defType("uint8")
	defType("uint16")
	defType("uint32")
	defType("uint64")
	Int = defType("int")
	defType("uint")
	defType("uintptr")

	defConst("true")
	defConst("false")
	defConst("iota")
	defConst("nil")

	defFun("append")
	defFun("cap")
	defFun("close")
	defFun("complex")
	defFun("copy")
	defFun("delete")
	defFun("imag")
	defFun("len")
	defFun("make")
	defFun("new")
	defFun("panic")
	defFun("print")
	defFun("println")
	defFun("real")
	defFun("recover")

	scope = ast.NewScope(nil)
	Unsafe = ast.NewObj(ast.Pkg, "unsafe")
	Unsafe.Data = scope

	defType("Pointer")

	defFun("Alignof")
	defFun("New")
	defFun("NewArray")
	defFun("Offsetof")
	defFun("Reflect")
	defFun("Sizeof")
	defFun("Typeof")
	defFun("Unreflect")
}
<commit_msg>exp/types: add error type to universe<commit_after>// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// FILE UNDER CONSTRUCTION. ANY AND ALL PARTS MAY CHANGE.
// This file implements the universe and unsafe package scopes.

package types

import "go/ast"

var (
	scope    *ast.Scope // current scope to use for initialization
	Universe *ast.Scope
	Unsafe   *ast.Object // package unsafe
)

func define(kind ast.ObjKind, name string) *ast.Object {
	obj := ast.NewObj(kind, name)
	if scope.Insert(obj) != nil {
		panic("types internal error: double declaration")
	}
	return obj
}

func defType(name string) *Name {
	obj := define(ast.Typ, name)
	typ := &Name{Underlying: &Basic{}, Obj: obj}
	obj.Type = typ
	return typ
}

func defConst(name string) {
	obj := define(ast.Con, name)
	_ = obj // TODO(gri) fill in other properties
}

func defFun(name string) {
	obj := define(ast.Fun, name)
	_ = obj // TODO(gri) fill in other properties
}

var (
	Bool,
	Int,
	Float64,
	Complex128,
	String *Name
)

func init() {
	scope = ast.NewScope(nil)
	Universe = scope

	Bool = defType("bool")
	defType("byte") // TODO(gri) should be an alias for uint8
	defType("rune") // TODO(gri) should be an alias for int
	defType("complex64")
	Complex128 = defType("complex128")
	defType("error")
	defType("float32")
	Float64 = defType("float64")
	defType("int8")
	defType("int16")
	defType("int32")
	defType("int64")
	String = defType("string")
	defType("uint8")
	defType("uint16")
	defType("uint32")
	defType("uint64")
	Int = defType("int")
	defType("uint")
	defType("uintptr")

	defConst("true")
	defConst("false")
	defConst("iota")
	defConst("nil")

	defFun("append")
	defFun("cap")
	defFun("close")
	defFun("complex")
	defFun("copy")
	defFun("delete")
	defFun("imag")
	defFun("len")
	defFun("make")
	defFun("new")
	defFun("panic")
	defFun("print")
	defFun("println")
	defFun("real")
	defFun("recover")

	scope = ast.NewScope(nil)
	Unsafe = ast.NewObj(ast.Pkg, "unsafe")
	Unsafe.Data = scope

	defType("Pointer")

	defFun("Alignof")
	defFun("New")
	defFun("NewArray")
	defFun("Offsetof")
	defFun("Reflect")
	defFun("Sizeof")
	defFun("Typeof")
	defFun("Unreflect")
}
<|endoftext|>


<commit_before>// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package runtime_test

import (
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"testing"
	"text/template"
)

type crashTest struct {
	Cgo bool
}

// This test is a separate program, because it is testing
// both main (m0) and non-main threads (m).

func testCrashHandler(t *testing.T, ct *crashTest) {
	if runtime.GOOS == "freebsd" || runtime.GOOS == "netbsd" {
		// TODO(brainman): do not know why this test fails on freebsd
		// TODO(jsing): figure out why this causes delayed failures
		// on NetBSD - http://golang.org/issue/3954
		t.Logf("skipping test on %q", runtime.GOOS)
		return
	}

	st := template.Must(template.New("crashSource").Parse(crashSource))

	dir, err := ioutil.TempDir("", "go-build")
	if err != nil {
		t.Fatalf("failed to create temp directory: %v", err)
	}
	defer os.RemoveAll(dir)

	src := filepath.Join(dir, "main.go")
	f, err := os.Create(src)
	if err != nil {
		t.Fatalf("failed to create %v: %v", src, err)
	}
	err = st.Execute(f, ct)
	if err != nil {
		f.Close()
		t.Fatalf("failed to execute template: %v", err)
	}
	f.Close()

	got, err := exec.Command("go", "run", src).CombinedOutput()
	if err != nil {
		t.Fatalf("program exited with error: %v\n%v", err, string(got))
	}
	want := "main: recovered done\nnew-thread: recovered done\nsecond-new-thread: recovered done\nmain-again: recovered done\n"
	if string(got) != string(want) {
		t.Fatalf("expected %q, but got %q", string(want), string(got))
	}
}

func TestCrashHandler(t *testing.T) {
	testCrashHandler(t, &crashTest{Cgo: false})
}

const crashSource = `
package main

import (
	"fmt"
	"runtime"
)

{{if .Cgo}}
import "C"
{{end}}

func test(name string) {
	defer func() {
		if x := recover(); x != nil {
			fmt.Printf(" recovered")
		}
		fmt.Printf(" done\n")
	}()
	fmt.Printf("%s:", name)
	var s *string
	_ = *s
	fmt.Print("SHOULD NOT BE HERE")
}

func testInNewThread(name string) {
	c := make(chan bool)
	go func() {
		runtime.LockOSThread()
		test(name)
		c <- true
	}()
	<-c
}

func main() {
	runtime.LockOSThread()
	test("main")
	testInNewThread("new-thread")
	testInNewThread("second-new-thread")
	test("main-again")
}
`
<commit_msg>runtime: re-enable crash test on NetBSD<commit_after>// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package runtime_test

import (
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"testing"
	"text/template"
)

type crashTest struct {
	Cgo bool
}

// This test is a separate program, because it is testing
// both main (m0) and non-main threads (m).

func testCrashHandler(t *testing.T, ct *crashTest) {
	if runtime.GOOS == "freebsd" {
		// TODO(brainman): do not know why this test fails on freebsd
		t.Logf("skipping test on %q", runtime.GOOS)
		return
	}

	st := template.Must(template.New("crashSource").Parse(crashSource))

	dir, err := ioutil.TempDir("", "go-build")
	if err != nil {
		t.Fatalf("failed to create temp directory: %v", err)
	}
	defer os.RemoveAll(dir)

	src := filepath.Join(dir, "main.go")
	f, err := os.Create(src)
	if err != nil {
		t.Fatalf("failed to create %v: %v", src, err)
	}
	err = st.Execute(f, ct)
	if err != nil {
		f.Close()
		t.Fatalf("failed to execute template: %v", err)
	}
	f.Close()

	got, err := exec.Command("go", "run", src).CombinedOutput()
	if err != nil {
		t.Fatalf("program exited with error: %v\n%v", err, string(got))
	}
	want := "main: recovered done\nnew-thread: recovered done\nsecond-new-thread: recovered done\nmain-again: recovered done\n"
	if string(got) != string(want) {
		t.Fatalf("expected %q, but got %q", string(want), string(got))
	}
}

func TestCrashHandler(t *testing.T) {
	testCrashHandler(t, &crashTest{Cgo: false})
}

const crashSource = `
package main

import (
	"fmt"
	"runtime"
)

{{if .Cgo}}
import "C"
{{end}}

func test(name string) {
	defer func() {
		if x := recover(); x != nil {
			fmt.Printf(" recovered")
		}
		fmt.Printf(" done\n")
	}()
	fmt.Printf("%s:", name)
	var s *string
	_ = *s
	fmt.Print("SHOULD NOT BE HERE")
}

func testInNewThread(name string) {
	c := make(chan bool)
	go func() {
		runtime.LockOSThread()
		test(name)
		c <- true
	}()
	<-c
}

func main() {
	runtime.LockOSThread()
	test("main")
	testInNewThread("new-thread")
	testInNewThread("second-new-thread")
	test("main-again")
}
`
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"os"
	"os/exec"
	"os/signal"
	"path/filepath"
	"runtime"
	"sort"
	"strings"
	"syscall"

	"github.com/mitchellh/osext"
)

const envPrefix = "VAGRANT_OLD_ENV"

func main() {
	debug := os.Getenv("VAGRANT_DEBUG_LAUNCHER") != ""

	// Get the path to the executable. This path doesn't resolve symlinks
	// so we have to do that afterwards to find the real binary.
	path, err := osext.Executable()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to load Vagrant: %s\n", err)
		os.Exit(1)
	}
	if debug {
		log.Printf("launcher: path = %s", path)
	}
	for {
		fi, err := os.Lstat(path)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Failed to stat executable: %s\n", err)
			os.Exit(1)
		}
		if fi.Mode()&os.ModeSymlink == 0 {
			break
		}

		// The executable is a symlink, so resolve it
		path, err = os.Readlink(path)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Failed to load Vagrant: %s\n", err)
			os.Exit(1)
		}
		if debug {
			log.Printf("launcher: resolved symlink = %s", path)
		}
	}

	// Determine some basic directories that we use throughout
	path = filepath.Dir(filepath.Clean(path))
	installerDir := filepath.Dir(path)
	embeddedDir := filepath.Join(installerDir, "embedded")
	if debug {
		log.Printf("launcher: installerDir = %s", installerDir)
		log.Printf("launcher: embeddedDir = %s", embeddedDir)
	}

	// Find the Vagrant gem
	gemPaths, err := filepath.Glob(
		filepath.Join(embeddedDir, "gems", "gems", "vagrant-*"))
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to find Vagrant: %s\n", err)
		os.Exit(1)
	}
	if debug {
		log.Printf("launcher: gemPaths (initial) = %#v", gemPaths)
	}
	for i := 0; i < len(gemPaths); i++ {
		fullPath := filepath.Join(gemPaths[i], "lib", "vagrant", "pre-rubygems.rb")
		if _, err := os.Stat(fullPath); err != nil {
			if debug {
				log.Printf("launcher: bad gemPath += %s", fullPath)
			}

			gemPaths = append(gemPaths[:i], gemPaths[i+1:]...)
			i--
		}
	}
	if len(gemPaths) == 0 {
		fmt.Fprintf(os.Stderr, "Failed to find Vagrant!\n")
		os.Exit(1)
	}
	gemPath := gemPaths[len(gemPaths)-1]
	vagrantExecutable := filepath.Join(gemPath, "bin", "vagrant")
	if debug {
		log.Printf("launcher: gemPaths (final) = %#v", gemPaths)
		log.Printf("launcher: gemPath = %s", gemPath)
	}

	// Setup the CPP/LDFLAGS so that native extensions can be
	// properly compiled into the Vagrant environment.
	cppflags := "-I" + filepath.Join(embeddedDir, "include")
	ldflags := "-L" + filepath.Join(embeddedDir, "lib")
	if original := os.Getenv("CPPFLAGS"); original != "" {
		cppflags = original + " " + cppflags
	}
	if original := os.Getenv("LDFLAGS"); original != "" {
		ldflags = original + " " + ldflags
	}

	// Set the PATH to include the proper paths into our embedded dir
	path = os.Getenv("PATH")
	if runtime.GOOS == "windows" {
		path = fmt.Sprintf(
			"%s;%s;%s",
			filepath.Join(embeddedDir, "bin"),
			filepath.Join(embeddedDir, "gnuwin32", "bin"),
			path)
	} else {
		path = fmt.Sprintf("%s:%s",
			filepath.Join(embeddedDir, "bin"), path)
	}

	// Allow users to specify a custom SSL cert
	sslCertFile := os.Getenv("SSL_CERT_FILE")
	if sslCertFile == "" {
		sslCertFile = filepath.Join(embeddedDir, "cacert.pem")
	}

	newEnv := map[string]string{
		// Setup the environment to prefer our embedded dir over
		// anything the user might have setup on his/her system.
		"CPPFLAGS":      cppflags,
		"GEM_HOME":      filepath.Join(embeddedDir, "gems"),
		"GEM_PATH":      filepath.Join(embeddedDir, "gems"),
		"GEMRC":         filepath.Join(embeddedDir, "etc", "gemrc"),
		"LDFLAGS":       ldflags,
		"PATH":          path,
		"SSL_CERT_FILE": sslCertFile,

		// Environmental variables used by Vagrant itself
		"VAGRANT_EXECUTABLE":             vagrantExecutable,
		"VAGRANT_INSTALLER_ENV":          "1",
		"VAGRANT_INSTALLER_EMBEDDED_DIR": embeddedDir,
		"VAGRANT_INSTALLER_VERSION":      "2",
	}

	// Unset any RUBYOPT, we don't want this bleeding into our runtime
	newEnv["RUBYOPT"] = ""

	// Store the "current" environment so Vagrant can restore it when shelling
	// out.
	for _, value := range os.Environ() {
		idx := strings.IndexRune(value, '=')
		key := fmt.Sprintf("%s_%s", envPrefix, value[:idx])
		newEnv[key] = value[idx+1:]
	}
	if debug {
		keys := make([]string, 0, len(newEnv))
		for k, _ := range newEnv {
			keys = append(keys, k)
		}
		sort.Strings(keys)

		for _, k := range keys {
			log.Printf("launcher: env %q = %q", k, newEnv[k])
		}
	}

	// Set all the environmental variables
	for k, v := range newEnv {
		if err := os.Setenv(k, v); err != nil {
			fmt.Fprintf(os.Stderr, "Error setting env var %s: %s\n", k, err)
			os.Exit(1)
		}
	}

	// Determine the path to Ruby and then start the Vagrant process
	rubyPath := filepath.Join(embeddedDir, "bin", "ruby")
	if runtime.GOOS == "windows" {
		rubyPath += ".exe"
	}

	// Prior to starting the command, we ignore interrupts. Vagrant itself
	// handles these, so the launcher should just wait until that exits.
	signal.Ignore(os.Interrupt)

	cmd := exec.Command(rubyPath)
	cmd.Args = make([]string, len(os.Args)+1)
	cmd.Args[0] = "ruby"
	cmd.Args[1] = filepath.Join(gemPath, "lib", "vagrant", "pre-rubygems.rb")
	copy(cmd.Args[2:], os.Args[1:])
	if debug {
		log.Printf("launcher: rubyPath = %s", rubyPath)
		log.Printf("launcher: args = %#v", cmd.Args)
	}

	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	if err := cmd.Start(); err != nil {
		fmt.Fprintf(os.Stderr, "Exec error: %s\n", err)
		os.Exit(1)
	}

	exitCode := 0
	if err := cmd.Wait(); err != nil {
		if exiterr, ok := err.(*exec.ExitError); ok {
			// The program has exited with an exit code != 0

			// This works on both Unix and Windows. Although package
			// syscall is generally platform dependent, WaitStatus is
			// defined for both Unix and Windows and in both cases has
			// an ExitStatus() method with the same signature.
			if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
				exitCode = status.ExitStatus()
			}
		}
	}

	os.Exit(exitCode)
}
<commit_msg>unset env RUBYLIB to avoid it leaking into vagrant.<commit_after>package main

import (
	"fmt"
	"log"
	"os"
	"os/exec"
	"os/signal"
	"path/filepath"
	"runtime"
	"sort"
	"strings"
	"syscall"

	"github.com/mitchellh/osext"
)

const envPrefix = "VAGRANT_OLD_ENV"

func main() {
	debug := os.Getenv("VAGRANT_DEBUG_LAUNCHER") != ""

	// Get the path to the executable. This path doesn't resolve symlinks
	// so we have to do that afterwards to find the real binary.
	path, err := osext.Executable()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to load Vagrant: %s\n", err)
		os.Exit(1)
	}
	if debug {
		log.Printf("launcher: path = %s", path)
	}
	for {
		fi, err := os.Lstat(path)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Failed to stat executable: %s\n", err)
			os.Exit(1)
		}
		if fi.Mode()&os.ModeSymlink == 0 {
			break
		}

		// The executable is a symlink, so resolve it
		path, err = os.Readlink(path)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Failed to load Vagrant: %s\n", err)
			os.Exit(1)
		}
		if debug {
			log.Printf("launcher: resolved symlink = %s", path)
		}
	}

	// Determine some basic directories that we use throughout
	path = filepath.Dir(filepath.Clean(path))
	installerDir := filepath.Dir(path)
	embeddedDir := filepath.Join(installerDir, "embedded")
	if debug {
		log.Printf("launcher: installerDir = %s", installerDir)
		log.Printf("launcher: embeddedDir = %s", embeddedDir)
	}

	// Find the Vagrant gem
	gemPaths, err := filepath.Glob(
		filepath.Join(embeddedDir, "gems", "gems", "vagrant-*"))
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to find Vagrant: %s\n", err)
		os.Exit(1)
	}
	if debug {
		log.Printf("launcher: gemPaths (initial) = %#v", gemPaths)
	}
	for i := 0; i < len(gemPaths); i++ {
		fullPath := filepath.Join(gemPaths[i], "lib", "vagrant", "pre-rubygems.rb")
		if _, err := os.Stat(fullPath); err != nil {
			if debug {
				log.Printf("launcher: bad gemPath += %s", fullPath)
			}

			gemPaths = append(gemPaths[:i], gemPaths[i+1:]...)
			i--
		}
	}
	if len(gemPaths) == 0 {
		fmt.Fprintf(os.Stderr, "Failed to find Vagrant!\n")
		os.Exit(1)
	}
	gemPath := gemPaths[len(gemPaths)-1]
	vagrantExecutable := filepath.Join(gemPath, "bin", "vagrant")
	if debug {
		log.Printf("launcher: gemPaths (final) = %#v", gemPaths)
		log.Printf("launcher: gemPath = %s", gemPath)
	}

	// Setup the CPP/LDFLAGS so that native extensions can be
	// properly compiled into the Vagrant environment.
	cppflags := "-I" + filepath.Join(embeddedDir, "include")
	ldflags := "-L" + filepath.Join(embeddedDir, "lib")
	if original := os.Getenv("CPPFLAGS"); original != "" {
		cppflags = original + " " + cppflags
	}
	if original := os.Getenv("LDFLAGS"); original != "" {
		ldflags = original + " " + ldflags
	}

	// Set the PATH to include the proper paths into our embedded dir
	path = os.Getenv("PATH")
	if runtime.GOOS == "windows" {
		path = fmt.Sprintf(
			"%s;%s;%s",
			filepath.Join(embeddedDir, "bin"),
			filepath.Join(embeddedDir, "gnuwin32", "bin"),
			path)
	} else {
		path = fmt.Sprintf("%s:%s",
			filepath.Join(embeddedDir, "bin"), path)
	}

	// Allow users to specify a custom SSL cert
	sslCertFile := os.Getenv("SSL_CERT_FILE")
	if sslCertFile == "" {
		sslCertFile = filepath.Join(embeddedDir, "cacert.pem")
	}

	newEnv := map[string]string{
		// Setup the environment to prefer our embedded dir over
		// anything the user might have setup on his/her system.
		"CPPFLAGS":      cppflags,
		"GEM_HOME":      filepath.Join(embeddedDir, "gems"),
		"GEM_PATH":      filepath.Join(embeddedDir, "gems"),
		"GEMRC":         filepath.Join(embeddedDir, "etc", "gemrc"),
		"LDFLAGS":       ldflags,
		"PATH":          path,
		"SSL_CERT_FILE": sslCertFile,

		// Environmental variables used by Vagrant itself
		"VAGRANT_EXECUTABLE":             vagrantExecutable,
		"VAGRANT_INSTALLER_ENV":          "1",
		"VAGRANT_INSTALLER_EMBEDDED_DIR": embeddedDir,
		"VAGRANT_INSTALLER_VERSION":      "2",
	}

	// Unset any RUBYOPT, we don't want this bleeding into our runtime
	newEnv["RUBYOPT"] = ""
	// Unset any RUBYLIB, we don't want this bleeding into our runtime
	newEnv["RUBYLIB"] = ""

	// Store the "current" environment so Vagrant can restore it when shelling
	// out.
	for _, value := range os.Environ() {
		idx := strings.IndexRune(value, '=')
		key := fmt.Sprintf("%s_%s", envPrefix, value[:idx])
		newEnv[key] = value[idx+1:]
	}
	if debug {
		keys := make([]string, 0, len(newEnv))
		for k, _ := range newEnv {
			keys = append(keys, k)
		}
		sort.Strings(keys)

		for _, k := range keys {
			log.Printf("launcher: env %q = %q", k, newEnv[k])
		}
	}

	// Set all the environmental variables
	for k, v := range newEnv {
		if err := os.Setenv(k, v); err != nil {
			fmt.Fprintf(os.Stderr, "Error setting env var %s: %s\n", k, err)
			os.Exit(1)
		}
	}

	// Determine the path to Ruby and then start the Vagrant process
	rubyPath := filepath.Join(embeddedDir, "bin", "ruby")
	if runtime.GOOS == "windows" {
		rubyPath += ".exe"
	}

	// Prior to starting the command, we ignore interrupts. Vagrant itself
	// handles these, so the launcher should just wait until that exits.
	signal.Ignore(os.Interrupt)

	cmd := exec.Command(rubyPath)
	cmd.Args = make([]string, len(os.Args)+1)
	cmd.Args[0] = "ruby"
	cmd.Args[1] = filepath.Join(gemPath, "lib", "vagrant", "pre-rubygems.rb")
	copy(cmd.Args[2:], os.Args[1:])
	if debug {
		log.Printf("launcher: rubyPath = %s", rubyPath)
		log.Printf("launcher: args = %#v", cmd.Args)
	}

	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	if err := cmd.Start(); err != nil {
		fmt.Fprintf(os.Stderr, "Exec error: %s\n", err)
		os.Exit(1)
	}

	exitCode := 0
	if err := cmd.Wait(); err != nil {
		if exiterr, ok := err.(*exec.ExitError); ok {
			// The program has exited with an exit code != 0

			// This works on both Unix and Windows. Although package
			// syscall is generally platform dependent, WaitStatus is
			// defined for both Unix and Windows and in both cases has
			// an ExitStatus() method with the same signature.
			if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
				exitCode = status.ExitStatus()
			}
		}
	}

	os.Exit(exitCode)
}
<|endoftext|>


<commit_before>package dashboard

import (
	"testing"

	"github.com/stretchr/testify/assert"
)

var (
	dbMigrator = NewMigrator("test.db", "./migrations")
	dbManager  = NewDbManager("test.db")
)

func teardown(t *testing.T) {
	errors, ok := dbMigrator.Down()
	t.Log("Down migrations")
	if !ok {
		t.Fatal("Migrations Down: ", errors)
	}
}

func up(t *testing.T) {
	errors, ok := dbMigrator.Up()
	t.Log("Up migrations")
	if !ok {
		t.Fatal("Migrations Up: ", errors)
	}
}

func TestDbManager(t *testing.T) {
	t.Run("Successfully insert widget info", func(t *testing.T) {
		up(t)
		var widget = &Widget{Url: "http://example.com", Id: "test_widget_1", Height: 350, Width: 400}
		count, err := dbManager.InsertWidget(widget)
		if err != nil {
			t.Fatal("ERROR:", err)
		}
		assert.Equal(t, int64(1), count)
		teardown(t)
	})
	t.Run("Fail to insert widget with same name", func(t *testing.T) {
		up(t)
		var widget = &Widget{Url: "http://example.com", Id: "test_widget_1", Height: 350, Width: 400}
		var widget2 = &Widget{Url: "http://some.site.com", Id: "test_widget_1", Height: 450, Width: 350}
		dbManager.InsertWidget(widget)
		count, err := dbManager.InsertWidget(widget2)
		assert.NotNil(t, err)
		assert.Equal(t, "UNIQUE constraint failed: widgets.id", err.Error())
		assert.Equal(t, int64(0), count)
		teardown(t)
	})
	t.Run("Should update widget data if widget exists", func(t *testing.T) {
		up(t)
		var widget = &Widget{Url: "http://example.com", Id: "test_widget_1", Height: 350, Width: 400}
		var widget2 = &Widget{Url: "http://some.site.com", Id: "test_widget_1", Height: 450, Width: 310}
		dbManager.InsertWidget(widget)
		id, err := dbManager.InsertOrUpdateWidget(widget2)
		assert.Nil(t, err)
		assert.True(t, id > 0)
		teardown(t)
	})
	t.Run("Should return all widgets", func(t *testing.T) {
		up(t)
		var widget = Widget{Url: "http://example.com", Id: "test_widget_1", Height: 350, Width: 400}
		var widget2 = Widget{Url: "http://some.site.com", Id: "test_widget_2", Height: 450, Width: 310}
		_, err := dbManager.InsertWidget(&widget)
		assert.Nil(t, err)
		_, err = dbManager.InsertWidget(&widget2)
		assert.Nil(t, err)
		actual, err := dbManager.GetAll(10, 0)
		assert.Nil(t, err)
		assert.Equal(t, widget, actual[0])
		assert.Equal(t, widget2, actual[1])
		teardown(t)
	})
	t.Run("Should return valid count rows per page", func(t *testing.T) {
		up(t)
		var widget1 = Widget{Url: "http://example.com", Id: "l_test_widget_1", Height: 350, Width: 400}
		var widget2 = Widget{Url: "http://some.site1.com", Id: "j_test_widget_2", Height: 450, Width: 310}
		var widget3 = Widget{Url: "http://some.site2.com", Id: "a_test_widget_3", Height: 450, Width: 310}
		var widget4 = Widget{Url: "http://some.site3.com", Id: "s_test_widget_4", Height: 450, Width: 310}
		var widget5 = Widget{Url: "http://some.site4.com", Id: "f_test_widget_5", Height: 450, Width: 310}
		var widget6 = Widget{Url: "http://some.site5.com", Id: "e_test_widget_6", Height: 450, Width: 310}
		var widget7 = Widget{Url: "http://some.site6.com", Id: "b_test_widget_7", Height: 450, Width: 310}
		var widget8 = Widget{Url: "http://some.site7.com", Id: "c_test_widget_8", Height: 450, Width: 310}
		var all = []Widget{widget1, widget2, widget3, widget4, widget5, widget6, widget7, widget8}
		var expected = []Widget{widget1, widget2, widget3, widget4}
		for _, widget := range all {
			dbManager.InsertWidget(&widget)
		}
		actual, err := dbManager.GetAll(4, 0)
		assert.Nil(t, err)
		assert.Equal(t, expected, actual)
		teardown(t)
	})

	t.Run("Should return empty array if no wigets in db", func(t *testing.T) {
		up(t)
		actual, err := dbManager.GetAll(4, 0)
		assert.Nil(t, err)
		assert.Empty(t, actual)
		teardown(t)
	})

	t.Run("Should success create page", func(t *testing.T) {
		up(t)
		var page = &Page{Title: "Page 1", Visible: true}
		count, err := dbManager.InsertPage(page)
		assert.Equal(t, int64(1), count)
		assert.Nil(t, err)
		teardown(t)
	})

	t.Run("Should not insert page with same title", func(t *testing.T) {
		up(t)
		var page = &Page{Title: "Page 1", Visible: true}
		var page2 = &Page{Title: "Page 1", Visible: true}
		dbManager.InsertPage(page)
		count, err := dbManager.InsertPage(page2)
		assert.NotNil(t, err)
		assert.Equal(t, "UNIQUE constraint failed: pages.title", err.Error())
		assert.Equal(t, int64(0), count)
		teardown(t)
	})

	t.Run("Should update page by id", func(t *testing.T) {
		up(t)
		var page = &Page{Title: "Page 2", Visible: true}
		id, err := dbManager.InsertPage(page)
		page.Id = id
		page.Visible = false
		page.Title = "Page title changed"
		count, err := dbManager.UpdatePage(page)
		assert.Nil(t, err)
		assert.Equal(t, int64(1), count)
		teardown(t)
	})

	t.Run("Should link widget to page", func(t *testing.T) {
		up(t)
		var page = &Page{Title: "Page 3", Visible: true}
		var widget = &Widget{Url: "http://example1.com", Id: "widget_page_3", Height: 450, Width: 300}
		pid, err := dbManager.InsertPage(page)
		if err != nil {
			t.Fatal("Error creating page: ", err)
		}
		_, err = dbManager.InsertWidget(widget)
		if err != nil {
			t.Fatal("Error creating widget: ", err)
		}

		count, err := dbManager.InsertWidgetToPage(pid, widget.Id)
		assert.Nil(t, err)
		assert.Equal(t, int64(1), count)
		teardown(t)
	})

	t.Run("Get widgets by page Id", func(t *testing.T) {
		up(t)
		var page = &Page{Title: "Page 1", Visible: true}
		var page2 = &Page{Title: "Page 2", Visible: true}
		var widget = Widget{Url: "http://example1.com", Id: "widget_page_1", Height: 450, Width: 300}
		var widget2 = Widget{Url: "http://example2.com", Id: "widget_page_2", Height: 420, Width: 200}
		var widget3 = Widget{Url: "http://example3.com", Id: "widget_page_3", Height: 320, Width: 210}
		pid, err := dbManager.InsertPage(page)
		pid2, err := dbManager.InsertPage(page2)
		dbManager.InsertWidget(&widget)
		dbManager.InsertWidget(&widget2)
		dbManager.InsertWidget(&widget3)

		_, err = dbManager.InsertWidgetToPage(pid, widget.Id)
		t.Log(err)
		_, err = dbManager.InsertWidgetToPage(pid, widget2.Id)
		t.Log(err)
		_, err = dbManager.InsertWidgetToPage(pid2, widget3.Id)
		t.Log(err)

		expected := []Widget{widget, widget2}
		expected2 := []Widget{widget3}

		actual, err := dbManager.GetPageWidgets(pid)
		actual2, err := dbManager.GetPageWidgets(pid2)

		assert.Nil(t, err)
		assert.Equal(t, expected, actual)
		assert.Equal(t, expected2, actual2)
		teardown(t)
	})

	err := dbManager.Close()
	if err != nil {
		t.Fatal("DB MANAGER: ", err)
	}
}
<commit_msg>SM-6 #time 12m Added test for checking uniqueness page -> widget<commit_after>package dashboard

import (
	"testing"

	"github.com/stretchr/testify/assert"
)

var (
	dbMigrator = NewMigrator("test.db", "./migrations")
	dbManager  = NewDbManager("test.db")
)

const (
	PAGE_WIDGET_UNIQUE_ERROR = "UNIQUE constraint failed: page_widgets.id_widget, page_widgets.id_page"
)

func teardown(t *testing.T) {
	errors, ok := dbMigrator.Down()
	t.Log("Down migrations")
	if !ok {
		t.Fatal("Migrations Down: ", errors)
	}
}

func up(t *testing.T) {
	errors, ok := dbMigrator.Up()
	t.Log("Up migrations")
	if !ok {
		t.Fatal("Migrations Up: ", errors)
	}
}

func TestDbManager(t *testing.T) {
	t.Run("Successfully insert widget info", func(t *testing.T) {
		up(t)
		var widget = &Widget{Url: "http://example.com", Id: "test_widget_1", Height: 350, Width: 400}
		count, err := dbManager.InsertWidget(widget)
		if err != nil {
			t.Fatal("ERROR:", err)
		}
		assert.Equal(t, int64(1), count)
		teardown(t)
	})
	t.Run("Fail to insert widget with same name", func(t *testing.T) {
		up(t)
		var widget = &Widget{Url: "http://example.com", Id: "test_widget_1", Height: 350, Width: 400}
		var widget2 = &Widget{Url: "http://some.site.com", Id: "test_widget_1", Height: 450, Width: 350}
		dbManager.InsertWidget(widget)
		count, err := dbManager.InsertWidget(widget2)
		assert.NotNil(t, err)
		assert.Equal(t, "UNIQUE constraint failed: widgets.id", err.Error())
		assert.Equal(t, int64(0), count)
		teardown(t)
	})
	t.Run("Should update widget data if widget exists", func(t *testing.T) {
		up(t)
		var widget = &Widget{Url: "http://example.com", Id: "test_widget_1", Height: 350, Width: 400}
		var widget2 = &Widget{Url: "http://some.site.com", Id: "test_widget_1", Height: 450, Width: 310}
		dbManager.InsertWidget(widget)
		id, err := dbManager.InsertOrUpdateWidget(widget2)
		assert.Nil(t, err)
		assert.True(t, id > 0)
		teardown(t)
	})
	t.Run("Should return all widgets", func(t *testing.T) {
		up(t)
		var widget = Widget{Url: "http://example.com", Id: "test_widget_1", Height: 350, Width: 400}
		var widget2 = Widget{Url: "http://some.site.com", Id: "test_widget_2", Height: 450, Width: 310}
		_, err := dbManager.InsertWidget(&widget)
		assert.Nil(t, err)
		_, err = dbManager.InsertWidget(&widget2)
		assert.Nil(t, err)
		actual, err := dbManager.GetAll(10, 0)
		assert.Nil(t, err)
		assert.Equal(t, widget, actual[0])
		assert.Equal(t, widget2, actual[1])
		teardown(t)
	})
	t.Run("Should return valid count rows per page", func(t *testing.T) {
		up(t)
		var widget1 = Widget{Url: "http://example.com", Id: "l_test_widget_1", Height: 350, Width: 400}
		var widget2 = Widget{Url: "http://some.site1.com", Id: "j_test_widget_2", Height: 450, Width: 310}
		var widget3 = Widget{Url: "http://some.site2.com", Id: "a_test_widget_3", Height: 450, Width: 310}
		var widget4 = Widget{Url: "http://some.site3.com", Id: "s_test_widget_4", Height: 450, Width: 310}
		var widget5 = Widget{Url: "http://some.site4.com", Id: "f_test_widget_5", Height: 450, Width: 310}
		var widget6 = Widget{Url: "http://some.site5.com", Id: "e_test_widget_6", Height: 450, Width: 310}
		var widget7 = Widget{Url: "http://some.site6.com", Id: "b_test_widget_7", Height: 450, Width: 310}
		var widget8 = Widget{Url: "http://some.site7.com", Id: "c_test_widget_8", Height: 450, Width: 310}
		var all = []Widget{widget1, widget2, widget3, widget4, widget5, widget6, widget7, widget8}
		var expected = []Widget{widget1, widget2, widget3, widget4}
		for _, widget := range all {
			dbManager.InsertWidget(&widget)
		}
		actual, err := dbManager.GetAll(4, 0)
		assert.Nil(t, err)
		assert.Equal(t, expected, actual)
		teardown(t)
	})

	t.Run("Should return empty array if no wigets in db", func(t *testing.T) {
		up(t)
		actual, err := dbManager.GetAll(4, 0)
		assert.Nil(t, err)
		assert.Empty(t, actual)
		teardown(t)
	})

	t.Run("Should success create page", func(t *testing.T) {
		up(t)
		var page = &Page{Title: "Page 1", Visible: true}
		count, err := dbManager.InsertPage(page)
		assert.Equal(t, int64(1), count)
		assert.Nil(t, err)
		teardown(t)
	})

	t.Run("Should not insert page with same title", func(t *testing.T) {
		up(t)
		var page = &Page{Title: "Page 1", Visible: true}
		var page2 = &Page{Title: "Page 1", Visible: true}
		dbManager.InsertPage(page)
		count, err := dbManager.InsertPage(page2)
		assert.NotNil(t, err)
		assert.Equal(t, "UNIQUE constraint failed: pages.title", err.Error())
		assert.Equal(t, int64(0), count)
		teardown(t)
	})

	t.Run("Should update page by id", func(t *testing.T) {
		up(t)
		var page = &Page{Title: "Page 2", Visible: true}
		id, err := dbManager.InsertPage(page)
		page.Id = id
		page.Visible = false
		page.Title = "Page title changed"
		count, err := dbManager.UpdatePage(page)
		assert.Nil(t, err)
		assert.Equal(t, int64(1), count)
		teardown(t)
	})

	t.Run("Should link widget to page", func(t *testing.T) {
		up(t)
		var page = &Page{Title: "Page 3", Visible: true}
		var widget = &Widget{Url: "http://example1.com", Id: "widget_page_3", Height: 450, Width: 300}
		pid, err := dbManager.InsertPage(page)
		if err != nil {
			t.Fatal("Error creating page: ", err)
		}
		_, err = dbManager.InsertWidget(widget)
		if err != nil {
			t.Fatal("Error creating widget: ", err)
		}

		count, err := dbManager.InsertWidgetToPage(pid, widget.Id)
		assert.Nil(t, err)
		assert.Equal(t, int64(1), count)
		teardown(t)
	})

	t.Run("Should link widget to page twice with same widget id", func(t *testing.T) {
		up(t)
		var page = &Page{Title: "Page 3", Visible: true}
		var widget = &Widget{Url: "http://example1.com", Id: "widget_page_3", Height: 450, Width: 300}
		pid, err := dbManager.InsertPage(page)
		if err != nil {
			t.Fatal("Error creating page: ", err)
		}
		_, err = dbManager.InsertWidget(widget)
		if err != nil {
			t.Fatal("Error creating widget: ", err)
		}

		_, err = dbManager.InsertWidgetToPage(pid, widget.Id)
		count, err := dbManager.InsertWidgetToPage(pid, widget.Id)
		assert.NotNil(t, err)
		assert.Equal(t, PAGE_WIDGET_UNIQUE_ERROR, err.Error())
		assert.Equal(t, int64(0), count)
		teardown(t)
	})

	t.Run("Get widgets by page Id", func(t *testing.T) {
		up(t)
		var page = &Page{Title: "Page 1", Visible: true}
		var page2 = &Page{Title: "Page 2", Visible: true}
		var widget = Widget{Url: "http://example1.com", Id: "widget_page_1", Height: 450, Width: 300}
		var widget2 = Widget{Url: "http://example2.com", Id: "widget_page_2", Height: 420, Width: 200}
		var widget3 = Widget{Url: "http://example3.com", Id: "widget_page_3", Height: 320, Width: 210}
		pid, err := dbManager.InsertPage(page)
		pid2, err := dbManager.InsertPage(page2)
		dbManager.InsertWidget(&widget)
		dbManager.InsertWidget(&widget2)
		dbManager.InsertWidget(&widget3)

		_, err = dbManager.InsertWidgetToPage(pid, widget.Id)
		t.Log(err)
		_, err = dbManager.InsertWidgetToPage(pid, widget2.Id)
		t.Log(err)
		_, err = dbManager.InsertWidgetToPage(pid2, widget3.Id)
		t.Log(err)

		expected := []Widget{widget, widget2}
		expected2 := []Widget{widget3}

		actual, err := dbManager.GetPageWidgets(pid)
		actual2, err := dbManager.GetPageWidgets(pid2)

		assert.Nil(t, err)
		assert.Equal(t, expected, actual)
		assert.Equal(t, expected2, actual2)
		teardown(t)
	})

	err := dbManager.Close()
	if err != nil {
		t.Fatal("DB MANAGER: ", err)
	}
}
<|endoftext|>


<commit_before>package scanner_test

import (
	"github.com/Southern/scanner"
	"io/ioutil"
	"strings"
	"testing"
)

var s = scanner.New()

func TestScannerBasics(t *testing.T) {
	str := "test-1 test + 1 test+1 -1 1000 -1000"
	expects := [][]string{
		{"WORD", "test"},
		{"CHAR", "-"},
		{"NUMBER", "1"},
		{"WHITESPACE", " "},
		{"WORD", "test"},
		{"WHITESPACE", " "},
		{"CHAR", "+"},
		{"WHITESPACE", " "},
		{"NUMBER", "1"},
		{"WHITESPACE", " "},
		{"WORD", "test"},
		{"CHAR", "+"},
		{"NUMBER", "1"},
		{"WHITESPACE", " "},
		{"CHAR", "-"},
		{"NUMBER", "1"},
		{"WHITESPACE", " "},
		{"NUMBER", "1000"},
		{"WHITESPACE", " "},
		{"CHAR", "-"},
		{"NUMBER", "1000"},
	}
	Status("Parsing \"%s\"", str)

	s, err := s.Parse(str)

	if err != nil {
		t.Errorf("Unexpected error: %s", err)
		return
	}

	for i := 0; i < len(s.Tokens); i++ {
		if s.Tokens[i][0] != expects[i][0] || s.Tokens[i][1] != expects[i][1] {
			t.Errorf("Expected %+v, got %+v", expects[i], s.Tokens[i])
			return
		}
	}

	Status("Parsed: %s", s)
}

func TestScannerManipulation(t *testing.T) {
	str := "test test test"
	expects := [][]string{
		{"WORD", "test"},
		{"WHITESPACE", " "},
		{"WORD", "test2"},
		{"WHITESPACE", " "},
		{"WORD", "test"},
	}

	Status("Parsing \"%s\"", str)
	s, err := s.Parse(str)

	if err != nil {
		t.Errorf("Unexpected error: %s", err)
		return
	}

	Status("Parsed data: %+v\n", s)
	s.Tokens[2][1] = "test2"
	for i := 0; i < len(s.Tokens); i++ {
		if s.Tokens[i][0] != expects[i][0] || s.Tokens[i][1] != expects[i][1] {
			t.Errorf("Expected %+v, got %+v", expects[i], s.Tokens[i])
			return
		}
	}

	Status("Data after manipulation: %s", s.Join())
}

func TestScannerReadFile(t *testing.T) {
	Status("Reading all files in testdata directory")
	files, err := ioutil.ReadDir("testdata")

	if err != nil {
		t.Errorf("Unexpected error: %s", err)
		return
	}

	Status("Scanning all files found in testdata directory")
	for len(files) > 0 {
		file := strings.Join([]string{"testdata", files[0].Name()}, "/")
		Status("Scanning file: %s", file)

		s, err = s.ReadFile(file)

		if err != nil {
			t.Errorf("Unexpected error: %s", err)
			return
		}

		Status("Scanned: %+v", s)
		files = files[1:]
	}
}

func TestScannerNonexistentFile(t *testing.T) {
	s := scanner.New()
	Status("Trying to read nonexistent file")
	s, err := s.ReadFile("idontevenexist")

	Status("Scan: %+v\n", s)

	if len(s.Tokens) > 0 || err == nil {
		t.Errorf("Expected this test to fail.")
	}
}

func TestJoiningLexBackToString(t *testing.T) {
	data, err := s.ReadFile(strings.Join([]string{"testdata", "html.txt"}, "/"))

	if err != nil {
		t.Errorf("Unexpected error: %s", err)
		return
	}

	Status("Scanned data: %+v", data)

	joined := data.Join()

	Status("Joined data: %+v", joined)
}

func TestInvalidDataType(t *testing.T) {
	Status("Trying to parse an invalid data type")

	_, err := s.Parse([]int{1, 2, 3, 4})

	Status("Error returned: %s", err)

	if err == nil {
		t.Errorf("Expected this test to fail.")
	}
}

func TestScannerRandomString(t *testing.T) {
	str := "ZoMg testΩ≈∂œ™£¢˜Ωπππ¬˜£™¡¢∞•ªº test< > & ; ?"
	Status("Trying to parse random string")

	s, err := s.Parse(str)

	if err != nil {
		t.Errorf("Unexpected error: %s", err)
		return
	}

	Status("Scanned: %+v", s)

	Status("String was parsed. Joining back together and checking the result.")

	joined := s.Join()

	if joined != str {
		t.Errorf("The joined string was not the same as what was input.")
		return
	}

	Status("String parsed correctly.")
}

func TestScannerRussianString(t *testing.T) {
	str := "This isn't Russian, but this is: ру́сский язы́к"
	Status("Trying to parse Russian string")

	s, err := s.Parse(str)

	if err != nil {
		t.Errorf("Unexpected error: %s", err)
		return
	}

	Status("Scanned: %+v", s)

	Status("String was parsed. Joining back together and checking the result.")

	joined := s.Join()

	if joined != str {
		t.Errorf("The joined string was not the same as what was input.")
		return
	}

	Status("String parsed correctly.")
}

func TestScannerGreekString(t *testing.T) {
	str := "This isn't Greek, but this is: ελληνικά"
	Status("Trying to parse Greek string")

	s, err := s.Parse(str)

	if err != nil {
		t.Errorf("Unexpected error: %s", err)
		return
	}

	Status("Scanned: %+v", s)

	Status("String was parsed. Joining back together and checking the result.")

	joined := s.Join()

	if joined != str {
		t.Errorf("The joined string was not the same as what was input.")
		return
	}

	Status("String parsed correctly")
}

func TestScannerArabicString(t *testing.T) {
	str := "This isn't Arabic, but this is: عربي ,عربى"
	Status("Trying to parse Arabic string")

	s, err := s.Parse(str)

	if err != nil {
		t.Errorf("Unexpected error: %s", err)
		return
	}

	Status("Scanned: %+v", s)

	Status("String was parsed. Joining back together and checking the result.")

	joined := s.Join()

	if joined != str {
		t.Errorf("The joined string was not the same as what was input.")
		return
	}

	Status("String parsed correctly")
}
<commit_msg>Update tests; cleanup<commit_after>package scanner_test

import (
	"github.com/Southern/scanner"
	"io/ioutil"
	"strings"
	"testing"
)

var s = scanner.New()

func TestScannerBasics(t *testing.T) {
	str := "test-1 test + 1 test+1 -1 1000 -1000"
	expects := [][]string{
		{"WORD", "test"},
		{"CHAR", "-"},
		{"NUMBER", "1"},
		{"WHITESPACE", " "},
		{"WORD", "test"},
		{"WHITESPACE", " "},
		{"CHAR", "+"},
		{"WHITESPACE", " "},
		{"NUMBER", "1"},
		{"WHITESPACE", " "},
		{"WORD", "test"},
		{"CHAR", "+"},
		{"NUMBER", "1"},
		{"WHITESPACE", " "},
		{"CHAR", "-"},
		{"NUMBER", "1"},
		{"WHITESPACE", " "},
		{"NUMBER", "1000"},
		{"WHITESPACE", " "},
		{"CHAR", "-"},
		{"NUMBER", "1000"},
	}
	Status("Parsing \"%s\"", str)

	s, err := s.Parse(str)

	if err != nil {
		t.Fatalf("Unexpected error: %s", err)
	}

	for i, expect := range expects {
		if i > len(s.Tokens)-1 {
			t.Fatalf("Excpected more output: %+v\n", expects[i:])
		}
		if s.Tokens[i][0] != expect[0] || s.Tokens[i][1] != expect[1] {
			t.Fatalf("Expected %+v, got %+v", expect, s.Tokens[i])
		}
	}

	Status("Parsed: %s", s)
}

func TestScannerManipulation(t *testing.T) {
	str := "test test test"
	expects := [][]string{
		{"WORD", "test"},
		{"WHITESPACE", " "},
		{"WORD", "test2"},
		{"WHITESPACE", " "},
		{"WORD", "test"},
	}

	Status("Parsing \"%s\"", str)
	s, err := s.Parse(str)

	if err != nil {
		t.Fatalf("Unexpected error: %s", err)
	}

	Status("Parsed data: %+v\n", s)
	s.Tokens[2][1] = "test2"

	for i, expect := range expects {
		if i > len(s.Tokens)-1 {
			t.Fatalf("Excpected more output: %+v\n", expects[i:])
		}
		if s.Tokens[i][0] != expect[0] || s.Tokens[i][1] != expect[1] {
			t.Fatalf("Expected %+v, got %+v", expect, s.Tokens[i])
		}
	}

	Status("Data after manipulation: %s", s.Join())
}

func TestScannerReadFile(t *testing.T) {
	Status("Reading all files in testdata directory")
	files, err := ioutil.ReadDir("testdata")

	if err != nil {
		t.Fatalf("Unexpected error: %s", err)
	}

	Status("Scanning all files found in testdata directory")
	for len(files) > 0 {
		file := strings.Join([]string{"testdata", files[0].Name()}, "/")
		Status("Scanning file: %s", file)

		s, err = s.ReadFile(file)

		if err != nil {
			t.Fatalf("Unexpected error: %s", err)
		}

		Status("Scanned: %+v", s)
		files = files[1:]
	}
}

func TestScannerNonexistentFile(t *testing.T) {
	s := scanner.New()
	Status("Trying to read nonexistent file")
	s, err := s.ReadFile("idontevenexist")

	Status("Scan: %+v\n", s)

	if len(s.Tokens) > 0 || err == nil {
		t.Fatal("Expected this test to fail.")
	}
}

func TestJoiningLexBackToString(t *testing.T) {
	data, err := s.ReadFile(strings.Join([]string{"testdata", "html.txt"}, "/"))

	if err != nil {
		t.Fatalf("Unexpected error: %s", err)
	}

	Status("Scanned data: %+v", data)

	joined := data.Join()

	Status("Joined data: %+v", joined)
}

func TestInvalidDataType(t *testing.T) {
	Status("Trying to parse an invalid data type")

	_, err := s.Parse([]int{1, 2, 3, 4})

	Status("Error returned: %s", err)

	if err == nil {
		t.Fatalf("Expected this test to fail.")
	}
}

func TestScannerRandomString(t *testing.T) {
	str := "ZoMg testΩ≈∂œ™£¢˜Ωπππ¬˜£™¡¢∞•ªº test< > & ; ?"
	Status("Trying to parse random string")

	s, err := s.Parse(str)

	if err != nil {
		t.Fatalf("Unexpected error: %s", err)
	}

	Status("Scanned: %+v", s)

	Status("String was parsed. Joining back together and checking the result.")

	joined := s.Join()

	if joined != str {
		t.Fatal("The joined string was not the same as what was input.")
	}

	Status("String parsed correctly.")
}

func TestScannerRussianString(t *testing.T) {
	str := "This isn't Russian, but this is: ру́сский язы́к"
	Status("Trying to parse Russian string")

	s, err := s.Parse(str)

	if err != nil {
		t.Fatalf("Unexpected error: %s", err)
	}

	Status("Scanned: %+v", s)

	Status("String was parsed. Joining back together and checking the result.")

	joined := s.Join()

	if joined != str {
		t.Fatal("The joined string was not the same as what was input.")
	}

	Status("String parsed correctly.")
}

func TestScannerGreekString(t *testing.T) {
	str := "This isn't Greek, but this is: ελληνικά"
	Status("Trying to parse Greek string")

	s, err := s.Parse(str)

	if err != nil {
		t.Fatalf("Unexpected error: %s", err)
	}

	Status("Scanned: %+v", s)

	Status("String was parsed. Joining back together and checking the result.")

	joined := s.Join()

	if joined != str {
		t.Fatal("The joined string was not the same as what was input.")
	}

	Status("String parsed correctly")
}

func TestScannerArabicString(t *testing.T) {
	str := "This isn't Arabic, but this is: عربي ,عربى"
	Status("Trying to parse Arabic string")

	s, err := s.Parse(str)

	if err != nil {
		t.Fatalf("Unexpected error: %s", err)
		return
	}

	Status("Scanned: %+v", s)

	Status("String was parsed. Joining back together and checking the result.")

	joined := s.Join()

	if joined != str {
		t.Fatal("The joined string was not the same as what was input.")
	}

	Status("String parsed correctly")
}
<|endoftext|>


<commit_before>package watch

import (
	"fmt"
	"log"
	"sync"
	"time"

	"github.com/hashicorp/consul-template/dependency"
	"github.com/hashicorp/consul/api"
)

// defaultRetryFunc is the default return function, which just echos whatever
// duration it was given.
var defaultRetryFunc RetryFunc = func(t time.Duration) time.Duration {
	return t
}

// RetryFunc is a function that defines the retry for a given watcher. The
// function parameter is the current retry (which might be nil), and the
// return value is the new retry. In this way, you can build complex retry
// functions that are based off the previous values.
type RetryFunc func(time.Duration) time.Duration

type Watcher struct {
	sync.Mutex

	// once is used to determine if the views should poll for data exactly once
	once bool

	// DataCh is the chan where Views will be published
	DataCh chan *View

	// ErrCh is the chan where any errors will be published
	ErrCh chan error

	// FinishCh is the chan where the watcher reports it is "done"
	FinishCh chan struct{}

	// client is the mechanism for communicating with the Consul API
	client *api.Client

	// retryFunc is a RetryFunc that represents the way retrys and backoffs
	// should occur.
	retryFunc RetryFunc

	// waitGroup is the WaitGroup to ensure all Go routines return when we stop
	waitGroup sync.WaitGroup

	// depViewMap is a map of Templates to Views. Templates are keyed by
	// HashCode().
	depViewMap map[string]*View
}

// NewWatcher creates a new watcher using the given API client.
func NewWatcher(c *api.Client, once bool) (*Watcher, error) {
	watcher := &Watcher{
		client: c,
		once:   once,
	}
	if err := watcher.init(); err != nil {
		return nil, err
	}

	return watcher, nil
}

// AddDependency adds the given dependency to the list of monitored depedencies
// and start the associated view. If the dependency already exists, no action is
// taken.
//
// If the Dependency already existed, it this function will return false. If the
// view was successfully created, it will return true. If an error occurs while
// creating the view, it will be returned here (but future errors returned by
// the view will happen on the channel).
func (w *Watcher) AddDependency(dep dependency.Dependency) (bool, error) {
	log.Printf("[INFO] (watcher) adding dependency %s", dep.Display())

	if _, ok := w.depViewMap[dep.HashCode()]; ok {
		log.Printf("[DEBUG] (watcher) dependency %s already exists, skipping", dep.Display())
		return false, nil
	}

	view, err := NewView(w.client, dep)
	if err != nil {
		return false, err
	}

	log.Printf("[DEBUG] (watcher) dependency %s starting", dep.Display())

	w.waitGroup.Add(1)
	go func(once bool, v *View) {
		defer w.waitGroup.Done()
		v.poll(once, w.DataCh, w.ErrCh, w.retryFunc)
	}(w.once, view)

	return true, nil
}

// RemoveDependency removes the given dependency from the list and stops the
// associated View. If a View for the given dependency does not exist, this
// function will return false. If the View does exist, this function will return
// true upon successful deletion.
func (w *Watcher) RemoveDependency(dep dependency.Dependency) bool {
	log.Printf("[INFO] (watcher) removing dependency %s", dep.Display())

	if view, ok := w.depViewMap[dep.HashCode()]; ok {
		log.Printf("[DEBUG] (watcher) actually removing dependency %s", dep.Display())
		view.stop()
		delete(w.depViewMap, dep.HashCode())
		return true
	}

	log.Printf("[DEBUG] (watcher) dependency %s did not exist, skipping", dep.Display())
	return false
}

// SetRetry is used to set the retry to a static value. See SetRetryFunc for
// more informatoin.
func (w *Watcher) SetRetry(duration time.Duration) {
	w.SetRetryFunc(func(current time.Duration) time.Duration {
		return duration
	})
}

// SetRetryFunc is used to set a dynamic retry function. Only new views created
// after this function has been set will inherit the new retry functionality.
// Existing views will use the retry functionality with which they were created.
func (w *Watcher) SetRetryFunc(f RetryFunc) {
	w.Lock()
	defer w.Unlock()
	w.retryFunc = f
}

// Watch creates a series of Consul views which poll for data in parallel. If
// the `once` flag is true, each view will return data (or an error) exactly
// once and terminate. If the `once` flag is false, views will continue to poll
// indefinitely unless they encounter an irrecoverable error.
//
// TODO: Refactor me!
func (w *Watcher) Watch(once bool) {
	log.Printf("[DEBUG] (watcher) starting watch")

	// Wait for them to stop
	log.Printf("[DEBUG] (watcher) all pollers have started, waiting for finish")
	w.waitGroup.Wait()

	// Close everything up
	if once {
		log.Printf("[DEBUG] (watcher) closing finish channel")
		close(w.FinishCh)
	}
}

// Stop halts this watcher and any currently polling views immediately. If a
// view was in the middle of a poll, no data will be returned.
func (w *Watcher) Stop() {
	log.Printf("[INFO] (watcher) stopping all views")

	for _, view := range w.depViewMap {
		log.Printf("[DEBUG] (watcher) stopping %+v", view)
		view.stop()
	}
}

// init sets up the initial values for the watcher.
func (w *Watcher) init() error {
	if w.client == nil {
		return fmt.Errorf("watcher: missing Consul API client")
	}

	// Setup the channels
	w.DataCh = make(chan *View)
	w.ErrCh = make(chan error)
	w.FinishCh = make(chan struct{})

	// Setup the default retry
	w.SetRetryFunc(defaultRetryFunc)

	// Setup our map of dependencies to views
	w.depViewMap = make(map[string]*View)

	return nil
}
<commit_msg>Lock when adding and removing dependencies<commit_after>package watch

import (
	"fmt"
	"log"
	"sync"
	"time"

	"github.com/hashicorp/consul-template/dependency"
	"github.com/hashicorp/consul/api"
)

// defaultRetryFunc is the default return function, which just echos whatever
// duration it was given.
var defaultRetryFunc RetryFunc = func(t time.Duration) time.Duration {
	return t
}

// RetryFunc is a function that defines the retry for a given watcher. The
// function parameter is the current retry (which might be nil), and the
// return value is the new retry. In this way, you can build complex retry
// functions that are based off the previous values.
type RetryFunc func(time.Duration) time.Duration

type Watcher struct {
	sync.Mutex

	// once is used to determine if the views should poll for data exactly once
	once bool

	// DataCh is the chan where Views will be published
	DataCh chan *View

	// ErrCh is the chan where any errors will be published
	ErrCh chan error

	// FinishCh is the chan where the watcher reports it is "done"
	FinishCh chan struct{}

	// client is the mechanism for communicating with the Consul API
	client *api.Client

	// retryFunc is a RetryFunc that represents the way retrys and backoffs
	// should occur.
	retryFunc RetryFunc

	// waitGroup is the WaitGroup to ensure all Go routines return when we stop
	waitGroup sync.WaitGroup

	// depViewMap is a map of Templates to Views. Templates are keyed by
	// HashCode().
	depViewMap map[string]*View
}

// NewWatcher creates a new watcher using the given API client.
func NewWatcher(c *api.Client, once bool) (*Watcher, error) {
	watcher := &Watcher{
		client: c,
		once:   once,
	}
	if err := watcher.init(); err != nil {
		return nil, err
	}

	return watcher, nil
}

// AddDependency adds the given dependency to the list of monitored depedencies
// and start the associated view. If the dependency already exists, no action is
// taken.
//
// If the Dependency already existed, it this function will return false. If the
// view was successfully created, it will return true. If an error occurs while
// creating the view, it will be returned here (but future errors returned by
// the view will happen on the channel).
func (w *Watcher) AddDependency(dep dependency.Dependency) (bool, error) {
	w.Lock()
	defer w.Unlock()

	log.Printf("[INFO] (watcher) adding dependency %s", dep.Display())

	if _, ok := w.depViewMap[dep.HashCode()]; ok {
		log.Printf("[DEBUG] (watcher) dependency %s already exists, skipping", dep.Display())
		return false, nil
	}

	view, err := NewView(w.client, dep)
	if err != nil {
		return false, err
	}

	log.Printf("[DEBUG] (watcher) dependency %s starting", dep.Display())

	w.waitGroup.Add(1)
	go func(once bool, v *View) {
		defer w.waitGroup.Done()
		v.poll(once, w.DataCh, w.ErrCh, w.retryFunc)
	}(w.once, view)

	return true, nil
}

// RemoveDependency removes the given dependency from the list and stops the
// associated View. If a View for the given dependency does not exist, this
// function will return false. If the View does exist, this function will return
// true upon successful deletion.
func (w *Watcher) RemoveDependency(dep dependency.Dependency) bool {
	w.Lock()
	defer w.Unlock()

	log.Printf("[INFO] (watcher) removing dependency %s", dep.Display())

	if view, ok := w.depViewMap[dep.HashCode()]; ok {
		log.Printf("[DEBUG] (watcher) actually removing dependency %s", dep.Display())
		view.stop()
		delete(w.depViewMap, dep.HashCode())
		return true
	}

	log.Printf("[DEBUG] (watcher) dependency %s did not exist, skipping", dep.Display())
	return false
}

// SetRetry is used to set the retry to a static value. See SetRetryFunc for
// more informatoin.
func (w *Watcher) SetRetry(duration time.Duration) {
	w.SetRetryFunc(func(current time.Duration) time.Duration {
		return duration
	})
}

// SetRetryFunc is used to set a dynamic retry function. Only new views created
// after this function has been set will inherit the new retry functionality.
// Existing views will use the retry functionality with which they were created.
func (w *Watcher) SetRetryFunc(f RetryFunc) {
	w.Lock()
	defer w.Unlock()
	w.retryFunc = f
}

// Watch creates a series of Consul views which poll for data in parallel. If
// the `once` flag is true, each view will return data (or an error) exactly
// once and terminate. If the `once` flag is false, views will continue to poll
// indefinitely unless they encounter an irrecoverable error.
//
// TODO: Refactor me!
func (w *Watcher) Watch(once bool) {
	log.Printf("[DEBUG] (watcher) starting watch")

	// Wait for them to stop
	log.Printf("[DEBUG] (watcher) all pollers have started, waiting for finish")
	w.waitGroup.Wait()

	// Close everything up
	if once {
		log.Printf("[DEBUG] (watcher) closing finish channel")
		close(w.FinishCh)
	}
}

// Stop halts this watcher and any currently polling views immediately. If a
// view was in the middle of a poll, no data will be returned.
func (w *Watcher) Stop() {
	log.Printf("[INFO] (watcher) stopping all views")

	for _, view := range w.depViewMap {
		log.Printf("[DEBUG] (watcher) stopping %+v", view)
		view.stop()
	}
}

// init sets up the initial values for the watcher.
func (w *Watcher) init() error {
	if w.client == nil {
		return fmt.Errorf("watcher: missing Consul API client")
	}

	// Setup the channels
	w.DataCh = make(chan *View)
	w.ErrCh = make(chan error)
	w.FinishCh = make(chan struct{})

	// Setup the default retry
	w.SetRetryFunc(defaultRetryFunc)

	// Setup our map of dependencies to views
	w.depViewMap = make(map[string]*View)

	return nil
}
<|endoftext|>


<commit_before>// Copyright (c) Alex Ellis 2017. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"strings"
	"sync"
	"time"

	"github.com/alexellis/faas/watchdog/types"
)

func buildFunctionInput(config *WatchdogConfig, r *http.Request) ([]byte, error) {
	var res []byte
	var requestBytes []byte
	var err error

	if r.Body != nil {
		defer r.Body.Close()
	}

	requestBytes, err = ioutil.ReadAll(r.Body)
	if config.marshalRequest {
		marshalRes, marshalErr := types.MarshalRequest(requestBytes, &r.Header)
		err = marshalErr
		res = marshalRes
	} else {
		res = requestBytes
	}
	return res, err
}

func debugHeaders(source *http.Header, direction string) {
	for k, vv := range *source {
		fmt.Printf("[%s] %s=%s\n", direction, k, vv)
	}
}

type requestInfo struct {
	headerWritten bool
}

func pipeRequest(config *WatchdogConfig, w http.ResponseWriter, r *http.Request, method string, hasBody bool) {
	startTime := time.Now()

	parts := strings.Split(config.faasProcess, " ")

	ri := &requestInfo{}

	if config.debugHeaders {
		debugHeaders(&r.Header, "in")
	}

	targetCmd := exec.Command(parts[0], parts[1:]...)

	envs := getAdditionalEnvs(config, r, method)
	if len(envs) > 0 {
		targetCmd.Env = envs
	}

	writer, _ := targetCmd.StdinPipe()

	var out []byte
	var err error
	var requestBody []byte

	var wg sync.WaitGroup

	wgCount := 2
	if hasBody == false {
		wgCount = 1
	}

	if hasBody {
		var buildInputErr error
		requestBody, buildInputErr = buildFunctionInput(config, r)
		if buildInputErr != nil {
			ri.headerWritten = true
			w.WriteHeader(http.StatusBadRequest)
			// I.e. "exit code 1"
			w.Write([]byte(buildInputErr.Error()))

			// Verbose message - i.e. stack trace
			w.Write([]byte("\n"))
			w.Write(out)

			return
		}
	}

	wg.Add(wgCount)

	var timer *time.Timer

	if config.execTimeout > 0*time.Second {
		timer = time.NewTimer(config.execTimeout)

		go func() {
			<-timer.C
			log.Printf("Killing process: %s\n", config.faasProcess)
			if targetCmd != nil && targetCmd.Process != nil {
				ri.headerWritten = true
				w.WriteHeader(http.StatusRequestTimeout)

				w.Write([]byte("Killed process.\n"))

				val := targetCmd.Process.Kill()
				if val != nil {
					log.Printf("Killed process: %s - error %s\n", config.faasProcess, val.Error())
				}
			}
		}()
	}

	// Only write body if this is appropriate for the method.
	if hasBody {
		// Write to pipe in separate go-routine to prevent blocking
		go func() {
			defer wg.Done()
			writer.Write(requestBody)
			writer.Close()
		}()
	}

	go func() {
		defer wg.Done()
		out, err = targetCmd.CombinedOutput()
	}()

	wg.Wait()
	if timer != nil {
		timer.Stop()
	}

	if err != nil {
		if config.writeDebug == true {
			log.Printf("Success=%t, Error=%s\n", targetCmd.ProcessState.Success(), err.Error())
			log.Printf("Out=%s\n", out)
		}

		if ri.headerWritten == false {
			w.WriteHeader(http.StatusInternalServerError)
			response := bytes.NewBufferString(err.Error())
			w.Write(response.Bytes())
            w.Write([]byte("\n"))
            if len(out) > 0 {
                w.Write(out)
            }
			ri.headerWritten = true
		}
		return
	}

	if config.writeDebug == true {
		os.Stdout.Write(out)
	}

	if len(config.contentType) > 0 {
		w.Header().Set("Content-Type", config.contentType)
	} else {

		// Match content-type of caller if no override specified.
		clientContentType := r.Header.Get("Content-Type")
		if len(clientContentType) > 0 {
			w.Header().Set("Content-Type", clientContentType)
		}
	}

	if ri.headerWritten == false {
		execTime := time.Since(startTime).Seconds()
		w.Header().Set("X-Duration-Seconds", fmt.Sprintf("%f", execTime))
		ri.headerWritten = true
		w.WriteHeader(200)
		w.Write(out)
	}

	if config.debugHeaders {
		header := w.Header()
		debugHeaders(&header, "out")
	}
}

func getAdditionalEnvs(config *WatchdogConfig, r *http.Request, method string) []string {
	var envs []string

	if config.cgiHeaders {
		envs = os.Environ()
		for k, v := range r.Header {
			kv := fmt.Sprintf("Http_%s=%s", k, v[0])
			envs = append(envs, kv)
		}
		envs = append(envs, fmt.Sprintf("Http_Method=%s", method))

		if len(r.URL.RawQuery) > 0 {
			envs = append(envs, fmt.Sprintf("Http_Query=%s", r.URL.RawQuery))
		}
	}

	return envs
}

func makeRequestHandler(config *WatchdogConfig) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		switch r.Method {
		case
			"POST",
			"PUT",
			"DELETE",
			"UPDATE":
			pipeRequest(config, w, r, r.Method, true)
			break
		case
			"GET":
			pipeRequest(config, w, r, r.Method, false)
			break
		default:
			w.WriteHeader(http.StatusMethodNotAllowed)

		}
	}
}

func main() {
	osEnv := types.OsEnv{}
	readConfig := ReadConfig{}
	config := readConfig.Read(osEnv)

	if len(config.faasProcess) == 0 {
		log.Panicln("Provide a valid process via fprocess environmental variable.")
		return
	}

	readTimeout := config.readTimeout
	writeTimeout := config.writeTimeout

	s := &http.Server{
		Addr:           ":8080",
		ReadTimeout:    readTimeout,
		WriteTimeout:   writeTimeout,
		MaxHeaderBytes: 1 << 20, // Max header of 1MB
	}

	http.HandleFunc("/", makeRequestHandler(&config))

	if config.suppressLock == false {
		path := "/tmp/.lock"
		log.Printf("Writing lock-file to: %s\n", path)
		writeErr := ioutil.WriteFile(path, []byte{}, 0660)
		if writeErr != nil {
			log.Panicf("Cannot write %s. To disable lock-file set env suppress_lock=true.\n Error: %s.\n", path, writeErr.Error())
		}
	}
	log.Fatal(s.ListenAndServe())
}
<commit_msg>watchdog - Write out headers with underscores<commit_after>// Copyright (c) Alex Ellis 2017. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"strings"
	"sync"
	"time"

	"github.com/alexellis/faas/watchdog/types"
)

func buildFunctionInput(config *WatchdogConfig, r *http.Request) ([]byte, error) {
	var res []byte
	var requestBytes []byte
	var err error

	if r.Body != nil {
		defer r.Body.Close()
	}

	requestBytes, err = ioutil.ReadAll(r.Body)
	if config.marshalRequest {
		marshalRes, marshalErr := types.MarshalRequest(requestBytes, &r.Header)
		err = marshalErr
		res = marshalRes
	} else {
		res = requestBytes
	}
	return res, err
}

func debugHeaders(source *http.Header, direction string) {
	for k, vv := range *source {
		fmt.Printf("[%s] %s=%s\n", direction, k, vv)
	}
}

type requestInfo struct {
	headerWritten bool
}

func pipeRequest(config *WatchdogConfig, w http.ResponseWriter, r *http.Request, method string, hasBody bool) {
	startTime := time.Now()

	parts := strings.Split(config.faasProcess, " ")

	ri := &requestInfo{}

	if config.debugHeaders {
		debugHeaders(&r.Header, "in")
	}

	targetCmd := exec.Command(parts[0], parts[1:]...)

	envs := getAdditionalEnvs(config, r, method)
	if len(envs) > 0 {
		targetCmd.Env = envs
	}

	writer, _ := targetCmd.StdinPipe()

	var out []byte
	var err error
	var requestBody []byte

	var wg sync.WaitGroup

	wgCount := 2
	if hasBody == false {
		wgCount = 1
	}

	if hasBody {
		var buildInputErr error
		requestBody, buildInputErr = buildFunctionInput(config, r)
		if buildInputErr != nil {
			ri.headerWritten = true
			w.WriteHeader(http.StatusBadRequest)
			// I.e. "exit code 1"
			w.Write([]byte(buildInputErr.Error()))

			// Verbose message - i.e. stack trace
			w.Write([]byte("\n"))
			w.Write(out)

			return
		}
	}

	wg.Add(wgCount)

	var timer *time.Timer

	if config.execTimeout > 0*time.Second {
		timer = time.NewTimer(config.execTimeout)

		go func() {
			<-timer.C
			log.Printf("Killing process: %s\n", config.faasProcess)
			if targetCmd != nil && targetCmd.Process != nil {
				ri.headerWritten = true
				w.WriteHeader(http.StatusRequestTimeout)

				w.Write([]byte("Killed process.\n"))

				val := targetCmd.Process.Kill()
				if val != nil {
					log.Printf("Killed process: %s - error %s\n", config.faasProcess, val.Error())
				}
			}
		}()
	}

	// Only write body if this is appropriate for the method.
	if hasBody {
		// Write to pipe in separate go-routine to prevent blocking
		go func() {
			defer wg.Done()
			writer.Write(requestBody)
			writer.Close()
		}()
	}

	go func() {
		defer wg.Done()
		out, err = targetCmd.CombinedOutput()
	}()

	wg.Wait()
	if timer != nil {
		timer.Stop()
	}

	if err != nil {
		if config.writeDebug == true {
			log.Printf("Success=%t, Error=%s\n", targetCmd.ProcessState.Success(), err.Error())
			log.Printf("Out=%s\n", out)
		}

		if ri.headerWritten == false {
			w.WriteHeader(http.StatusInternalServerError)
			response := bytes.NewBufferString(err.Error())
			w.Write(response.Bytes())
			w.Write([]byte("\n"))
			if len(out) > 0 {
				w.Write(out)
			}
			ri.headerWritten = true
		}
		return
	}

	if config.writeDebug == true {
		os.Stdout.Write(out)
	}

	if len(config.contentType) > 0 {
		w.Header().Set("Content-Type", config.contentType)
	} else {

		// Match content-type of caller if no override specified.
		clientContentType := r.Header.Get("Content-Type")
		if len(clientContentType) > 0 {
			w.Header().Set("Content-Type", clientContentType)
		}
	}

	if ri.headerWritten == false {
		execTime := time.Since(startTime).Seconds()
		w.Header().Set("X-Duration-Seconds", fmt.Sprintf("%f", execTime))
		ri.headerWritten = true
		w.WriteHeader(200)
		w.Write(out)
	}

	if config.debugHeaders {
		header := w.Header()
		debugHeaders(&header, "out")
	}
}

func getAdditionalEnvs(config *WatchdogConfig, r *http.Request, method string) []string {
	var envs []string

	if config.cgiHeaders {
		envs = os.Environ()
		for k, v := range r.Header {
			kv := fmt.Sprintf("Http_%s=%s", strings.Replace(k, "-", "_", -1), v[0])
			envs = append(envs, kv)
		}

		envs = append(envs, fmt.Sprintf("Http_Method=%s", method))

		if len(r.URL.RawQuery) > 0 {
			envs = append(envs, fmt.Sprintf("Http_Query=%s", r.URL.RawQuery))
		}
	}

	return envs
}

func makeRequestHandler(config *WatchdogConfig) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		switch r.Method {
		case
			"POST",
			"PUT",
			"DELETE",
			"UPDATE":
			pipeRequest(config, w, r, r.Method, true)
			break
		case
			"GET":
			pipeRequest(config, w, r, r.Method, false)
			break
		default:
			w.WriteHeader(http.StatusMethodNotAllowed)

		}
	}
}

func main() {
	osEnv := types.OsEnv{}
	readConfig := ReadConfig{}
	config := readConfig.Read(osEnv)

	if len(config.faasProcess) == 0 {
		log.Panicln("Provide a valid process via fprocess environmental variable.")
		return
	}

	readTimeout := config.readTimeout
	writeTimeout := config.writeTimeout

	s := &http.Server{
		Addr:           ":8080",
		ReadTimeout:    readTimeout,
		WriteTimeout:   writeTimeout,
		MaxHeaderBytes: 1 << 20, // Max header of 1MB
	}

	http.HandleFunc("/", makeRequestHandler(&config))

	if config.suppressLock == false {
		path := "/tmp/.lock"
		log.Printf("Writing lock-file to: %s\n", path)
		writeErr := ioutil.WriteFile(path, []byte{}, 0660)
		if writeErr != nil {
			log.Panicf("Cannot write %s. To disable lock-file set env suppress_lock=true.\n Error: %s.\n", path, writeErr.Error())
		}
	}
	log.Fatal(s.ListenAndServe())
}
<|endoftext|>


<commit_before>package depot

import (
	"crypto/rand"
	"crypto/x509"
	"time"

	"github.com/micromdm/scep/v2/cryptoutil"
	"github.com/micromdm/scep/v2/scep"
)

// Signer signs x509 certificates and stores them in a Depot
type Signer struct {
	depot            Depot
	caPass           string
	allowRenewalDays int
	validityDays     int
}

// Option customizes Signer
type Option func(*Signer)

// NewSigner creates a new Signer
func NewSigner(depot Depot, opts ...Option) *Signer {
	s := &Signer{
		depot:            depot,
		allowRenewalDays: 14,
		validityDays:     365,
	}
	for _, opt := range opts {
		opt(s)
	}
	return s
}

// WithCAPass specifies the password to use with an encrypted CA key
func WithCAPass(pass string) Option {
	return func(s *Signer) {
		s.caPass = pass
	}
}

// WithAllowRenewalDays sets the allowable renewal time for existing certs
func WithAllowRenewalDays(r int) Option {
	return func(s *Signer) {
		s.allowRenewalDays = r
	}
}

// WithValidityDays sets the validity period new certs will use
func WithValidityDays(v int) Option {
	return func(s *Signer) {
		s.validityDays = v
	}
}

// SignCSR signs a certificate using Signer's Depot CA
func (s *Signer) SignCSR(m *scep.CSRReqMessage) (*x509.Certificate, error) {
	id, err := cryptoutil.GenerateSubjectKeyID(m.CSR.PublicKey)
	if err != nil {
		return nil, err
	}

	serial, err := s.depot.Serial()
	if err != nil {
		return nil, err
	}

	// create cert template
	tmpl := &x509.Certificate{
		SerialNumber: serial,
		Subject:      m.CSR.Subject,
		NotBefore:    time.Now().Add(-600).UTC(),
		NotAfter:     time.Now().AddDate(0, 0, s.validityDays).UTC(),
		SubjectKeyId: id,
		KeyUsage:     x509.KeyUsageDigitalSignature,
		ExtKeyUsage: []x509.ExtKeyUsage{
			x509.ExtKeyUsageClientAuth,
		},
		SignatureAlgorithm: m.CSR.SignatureAlgorithm,
		DNSNames:           m.CSR.DNSNames,
		EmailAddresses:     m.CSR.EmailAddresses,
		IPAddresses:        m.CSR.IPAddresses,
		URIs:               m.CSR.URIs,
	}

	caCerts, caKey, err := s.depot.CA([]byte(s.caPass))
	if err != nil {
		return nil, err
	}

	crtBytes, err := x509.CreateCertificate(rand.Reader, tmpl, caCerts[0], m.CSR.PublicKey, caKey)
	if err != nil {
		return nil, err
	}

	crt, err := x509.ParseCertificate(crtBytes)
	if err != nil {
		return nil, err
	}

	name := certName(crt)

	// Test if this certificate is already in the CADB, revoke if needed
	// revocation is done if the validity of the existing certificate is
	// less than allowRenewalDays
	_, err = s.depot.HasCN(name, s.allowRenewalDays, crt, false)
	if err != nil {
		return nil, err
	}

	if err := s.depot.Put(name, crt); err != nil {
		return nil, err
	}

	return crt, nil
}

func certName(crt *x509.Certificate) string {
	if crt.Subject.CommonName != "" {
		return crt.Subject.CommonName
	}
	return string(crt.Signature)
}
<commit_msg>protect depot with mutex in SignCSR (#185)<commit_after>package depot

import (
	"crypto/rand"
	"crypto/x509"
	"sync"
	"time"

	"github.com/micromdm/scep/v2/cryptoutil"
	"github.com/micromdm/scep/v2/scep"
)

// Signer signs x509 certificates and stores them in a Depot
type Signer struct {
	depot            Depot
	mu               sync.Mutex
	caPass           string
	allowRenewalDays int
	validityDays     int
}

// Option customizes Signer
type Option func(*Signer)

// NewSigner creates a new Signer
func NewSigner(depot Depot, opts ...Option) *Signer {
	s := &Signer{
		depot:            depot,
		allowRenewalDays: 14,
		validityDays:     365,
	}
	for _, opt := range opts {
		opt(s)
	}
	return s
}

// WithCAPass specifies the password to use with an encrypted CA key
func WithCAPass(pass string) Option {
	return func(s *Signer) {
		s.caPass = pass
	}
}

// WithAllowRenewalDays sets the allowable renewal time for existing certs
func WithAllowRenewalDays(r int) Option {
	return func(s *Signer) {
		s.allowRenewalDays = r
	}
}

// WithValidityDays sets the validity period new certs will use
func WithValidityDays(v int) Option {
	return func(s *Signer) {
		s.validityDays = v
	}
}

// SignCSR signs a certificate using Signer's Depot CA
func (s *Signer) SignCSR(m *scep.CSRReqMessage) (*x509.Certificate, error) {
	id, err := cryptoutil.GenerateSubjectKeyID(m.CSR.PublicKey)
	if err != nil {
		return nil, err
	}

	s.mu.Lock()
	defer s.mu.Unlock()

	serial, err := s.depot.Serial()
	if err != nil {
		return nil, err
	}

	// create cert template
	tmpl := &x509.Certificate{
		SerialNumber: serial,
		Subject:      m.CSR.Subject,
		NotBefore:    time.Now().Add(-600).UTC(),
		NotAfter:     time.Now().AddDate(0, 0, s.validityDays).UTC(),
		SubjectKeyId: id,
		KeyUsage:     x509.KeyUsageDigitalSignature,
		ExtKeyUsage: []x509.ExtKeyUsage{
			x509.ExtKeyUsageClientAuth,
		},
		SignatureAlgorithm: m.CSR.SignatureAlgorithm,
		DNSNames:           m.CSR.DNSNames,
		EmailAddresses:     m.CSR.EmailAddresses,
		IPAddresses:        m.CSR.IPAddresses,
		URIs:               m.CSR.URIs,
	}

	caCerts, caKey, err := s.depot.CA([]byte(s.caPass))
	if err != nil {
		return nil, err
	}

	crtBytes, err := x509.CreateCertificate(rand.Reader, tmpl, caCerts[0], m.CSR.PublicKey, caKey)
	if err != nil {
		return nil, err
	}

	crt, err := x509.ParseCertificate(crtBytes)
	if err != nil {
		return nil, err
	}

	name := certName(crt)

	// Test if this certificate is already in the CADB, revoke if needed
	// revocation is done if the validity of the existing certificate is
	// less than allowRenewalDays
	_, err = s.depot.HasCN(name, s.allowRenewalDays, crt, false)
	if err != nil {
		return nil, err
	}

	if err := s.depot.Put(name, crt); err != nil {
		return nil, err
	}

	return crt, nil
}

func certName(crt *x509.Certificate) string {
	if crt.Subject.CommonName != "" {
		return crt.Subject.CommonName
	}
	return string(crt.Signature)
}
<|endoftext|>


<commit_before>package args

import (
	"fmt"
	"github.com/docopt/docopt-go"
	"os"
	"path"
	"sort"
	"strings"
)

type Args struct {
	ConfigFile string
	Keyword    string
	Clean      bool
	List       bool
	Read       bool
	Remove     bool
	Save       bool
	Verbose    bool
}

func NewArgs() *Args {
	var configFile, defaultConfig, directory, usage string

	defaultConfig = getDefaultConfigurationFilename()

	usage = `CURD - Change to a User's Recurring Directory 1.0.0
H. Dale McBane<h.dale.mcbane@gmail.com>
Save and return to paths you visit often.

Usage:
    curd clean [--config <file>] [--verbose]
    curd (ls | list) [--config <file>] [--verbose]
    curd remove [KEYWORD] [--config <file>] [--verbose]
    curd save [KEYWORD] [--dir <directory>] [--config <file>] [--verbose]
    curd [KEYWORD] [--config <file>] [--verbose]

Options:
    --config=<file>  Specify configuration filename [default: <<replaceme>>].
    --dir=<directory>  Specify configuration filename [default: <current directory>].
    -h, --help     Show this screen.
    -V, --version  Show version.
    -v, --verbose  Display extra information.

Examples:
    List all of the paths defined in the default configuration file.
        curd ls

    List all of the paths in a specified configuration file.
        curd list --config some_configuration_file

    Clean paths from the default configuration that do not exist in the
    filesystem.
        curd clean

    Read the default path from the default configuration file.
        curd

    Save the current directory as the default path in the default configuration
    file.
        curd save

    Save the specified directory as the specified path in the default
	configuration file.
        curd save curd --dir=~/go/src/github.com/dmcbane/curd

    Remove the specified path from the default configuration file.
        curd remove essay

`

	usage = strings.Replace(usage, "<<replaceme>>", defaultConfig, 1)

	// parse the usage string
	// nil means use os.Args
	// true means display usage as the help message
	// the string to display for version
	// don't require options to be provided before positional arguments
	// have Parse call os.Exit() if help or version are requested by the user
	arguments, err := docopt.Parse(usage, nil, true, "Curd 1.0.0", false, false)
	if err != nil {
		fmt.Print(err)
	}
	var keys []string
	for k, _ := range arguments {
		keys = append(keys, k)
	}
	sort.Strings(keys)
	for _, k := range keys {
		fmt.Printf("%9v: %v\n", k, arguments[k])
	}
	os.Exit(0)

	var cleanBool, listBool, readBool, removeBool, saveBool, verboseBool bool
	var keyword string

	configFile, _ = arguments["--config"].(string)
	directory, _ = arguments["--directory"].(string)
	keyword, _ = arguments["keyword"].(string)
	removeString, _ := arguments["--remove"]
	rString, _ := arguments["-r"]
	saveString, _ := arguments["--save"]
	sString, _ := arguments["-s"]
	cleanBool = arguments["--clean"].(bool) || arguments["-n"].(bool)
	listBool = arguments["--list"].(bool) || arguments["-l"].(bool)
	verboseBool = arguments["--verbose"].(bool)
	switch {
	case removeString != nil:
		removeBool = true
		keyword = removeString.(string)
	case rString != nil:
		removeBool = true
	case saveString != nil:
		saveBool = true
		keyword = saveString.(string)
	case sString != nil:
		saveBool = true
	}

	readBool = !cleanBool && !listBool && !removeBool && !saveBool

	if configFile == "" {
		configFile = defaultConfig
	}

	if directory == "<current directory>" {
		directory = ""
	}

	if keyword == "" {
		keyword = "<default>"
	}

	if verboseBool {
		fmt.Printf("ConfigFile: %v\n", configFile)
		fmt.Printf("Keyword:    %v\n", keyword)
		fmt.Printf("Clean:      %v\n", cleanBool)
		fmt.Printf("List:       %v\n", listBool)
		fmt.Printf("Read:       %v\n", readBool)
		fmt.Printf("Remove:     %v\n", removeBool)
		fmt.Printf("Save:       %v\n", saveBool)
		fmt.Printf("Directory:  %v\n", directory)
		fmt.Printf("Verbose:    %v\n", verboseBool)
	}

	return &Args{ConfigFile: configFile, Keyword: keyword, Clean: cleanBool, List: listBool, Read: readBool, Remove: removeBool, Save: saveBool, Verbose: verboseBool}
}

func getDefaultConfigurationFilename() string {
	const default_config = ".curdrc"
	var home string
	if home = os.Getenv("HOME"); home == "" {
		home = os.Getenv("USERPROFILE")
	}
	return path.Join(home, default_config)
}
<commit_msg>Adjust to corrected parameters...<commit_after>package args

import (
	"fmt"
	"github.com/docopt/docopt-go"
	"os"
	"path"
	"strings"
)

type Args struct {
	ConfigFile string
	Keyword    string
	Clean      bool
	List       bool
	Read       bool
	Remove     bool
	Save       bool
	Verbose    bool
}

func NewArgs() *Args {
	var configFile, defaultConfig, directory, usage string

	defaultConfig = getDefaultConfigurationFilename()

	usage = `CURD - Change to a User's Recurring Directory 1.0.0
H. Dale McBane<h.dale.mcbane@gmail.com>
Save and return to paths you visit often.

Usage:
    curd clean [--config <file>] [--verbose]
    curd (ls | list) [--config <file>] [--verbose]
    curd remove [KEYWORD] [--config <file>] [--verbose]
    curd save [KEYWORD] [--dir <directory>] [--config <file>] [--verbose]
    curd [KEYWORD] [--config <file>] [--verbose]

Options:
    --config=<file>  Specify configuration filename [default: <<replaceme>>].
    --dir=<directory>  Specify configuration filename [default: <current directory>].
    -h, --help     Show this screen.
    -V, --version  Show version.
    -v, --verbose  Display extra information.

Examples:
    List all of the paths defined in the default configuration file.
        curd ls

    List all of the paths in a specified configuration file.
        curd list --config some_configuration_file

    Clean paths from the default configuration that do not exist in the
    filesystem.
        curd clean

    Read the default path from the default configuration file.
        curd

    Save the current directory as the default path in the default configuration
    file.
        curd save

    Save the specified directory as the specified path in the default
	configuration file.
        curd save curd --dir=~/go/src/github.com/dmcbane/curd

    Remove the specified path from the default configuration file.
        curd remove essay

`

	usage = strings.Replace(usage, "<<replaceme>>", defaultConfig, 1)

	// parse the usage string
	// nil means use os.Args
	// true means display usage as the help message
	// the string to display for version
	// don't require options to be provided before positional arguments
	// have Parse call os.Exit() if help or version are requested by the user
	arguments, err := docopt.Parse(usage, nil, true, "Curd 1.0.0", false, false)
	if err != nil {
		fmt.Print(err)
	}

	var cleanBool, listBool, readBool, removeBool, saveBool, verboseBool bool
	var keyword string

	configFile, _ = arguments["--config"].(string)
	directory, _ = arguments["--dir"].(string)
	keyword, _ = arguments["KEYWORD"].(string)
	cleanBool = arguments["clean"].(bool)
	listBool = arguments["list"].(bool) || arguments["ls"].(bool)
	removeBool = arguments["remove"].(bool)
	saveBool = arguments["save"].(bool)
	readBool = !cleanBool && !listBool && !removeBool && !saveBool
	verboseBool = arguments["--verbose"].(bool)

	if configFile == "" {
		configFile = defaultConfig
	}

	if directory == "<current directory>" {
		directory = ""
	}

	if keyword == "" {
		keyword = "<default>"
	}

	if verboseBool {
		fmt.Printf("ConfigFile: %v\n", configFile)
		fmt.Printf("Keyword:    %v\n", keyword)
		fmt.Printf("Clean:      %v\n", cleanBool)
		fmt.Printf("List:       %v\n", listBool)
		fmt.Printf("Read:       %v\n", readBool)
		fmt.Printf("Remove:     %v\n", removeBool)
		fmt.Printf("Save:       %v\n", saveBool)
		fmt.Printf("Directory:  %v\n", directory)
		fmt.Printf("Verbose:    %v\n", verboseBool)
	}

	return &Args{ConfigFile: configFile, Keyword: keyword, Clean: cleanBool, List: listBool, Read: readBool, Remove: removeBool, Save: saveBool, Verbose: verboseBool}
}

func getDefaultConfigurationFilename() string {
	const default_config = ".curdrc"
	var home string
	if home = os.Getenv("HOME"); home == "" {
		home = os.Getenv("USERPROFILE")
	}
	return path.Join(home, default_config)
}
<|endoftext|>