<commit_before>package build

import (
	"encoding/json"
	"fmt"
	"regexp"
	"strconv"
)

// Parse attempts to create a version based on a given string
func Parse(raw string) (ver ProtocolVersion, err error) {
	parts := versionReg.FindStringSubmatch(raw)
	if len(parts) != 5 {
		err = InvalidVersionError(raw)
		return
	}

	// because of the regexp we can be sure that this will always succeed
	// an empty string automatically results in 0, even though it also returns an err
	major, _ := strconv.ParseUint(parts[1], 10, 8)
	minor, _ := strconv.ParseUint(parts[2], 10, 8)
	patch, _ := strconv.ParseUint(parts[3], 10, 8)

	ver = NewPrereleaseVersion(uint8(major), uint8(minor), uint8(patch), parts[4])
	return
}

// MustParse creates a version based on a given string,
// panics in case the given string is invalid
func MustParse(raw string) ProtocolVersion {
	version, err := Parse(raw)
	if err != nil {
		panic(err)
	}
	return version
}

// NewVersion creates a new protocol version
func NewVersion(major, minor, patch uint8) ProtocolVersion {
	return NewPrereleaseVersion(major, minor, patch, "")
}

// NewPrereleaseVersion creates a new protocol prerelease version
func NewPrereleaseVersion(major, minor, patch uint8, prerelease string) ProtocolVersion {
	var v ProtocolVersion
	v.Version = (uint32(major) << 24) | (uint32(minor) << 16) | (uint32(patch) << 8)
	copy(v.Prerelease[:], prerelease[:])
	return v
}

// ProtocolVersion defines the protocol version that a node uses
type ProtocolVersion struct {
	Version    uint32  // Semantic Versioning
	Prerelease [8]byte // Any pre-release tag (eg. 'alpha' or the git commit hash)
}

// InvalidVersionError indicates a protocol version is invalid.
type InvalidVersionError string

// Error implements the error interface for InvalidVersionError.
func (e InvalidVersionError) Error() string {
	if len(e) == 0 {
		return "invalid version: <nil>"
	}

	return "invalid version: " + string(e)
}

// Compare returns an integer comparing this version with another version.
func (pv ProtocolVersion) Compare(other ProtocolVersion) int {
	if pv.Version < other.Version {
		return -1
	} else if pv.Version > other.Version {
		return 1
	}

	isAPrerelease := pv.Prerelease != nilPreRelease
	isBPrerelease := other.Prerelease != nilPreRelease

	if !isAPrerelease && isBPrerelease {
		return 1
	} else if isAPrerelease && !isBPrerelease {
		return -1
	}

	// NOTE: if the 2 versions both have a prerelease defined we count them as equal,
	//       regardless if those prerelease values are different or not

	return 0
}

// String returns the string version of this ProtocolVersion
func (pv ProtocolVersion) String() string {
	str := fmt.Sprintf("%d.%d.%d",
		(pv.Version>>24)&0xFF, // major
		(pv.Version>>16)&0xFF, // minor
		(pv.Version>>8)&0xFF,  // patch
	)

	// optional prerelease
	if pv.Prerelease != nilPreRelease {
		str += "-" + string(pv.Prerelease[:])
	}

	return str
}

// MarshalJSON implements json.Marshaler.MarshalJSON
func (pv ProtocolVersion) MarshalJSON() ([]byte, error) {
	return json.Marshal(pv.String())
}

// UnmarshalJSON implements json.Unmarshaler.UnmarshalJSON
func (pv *ProtocolVersion) UnmarshalJSON(b []byte) error {
	var raw string
	if err := json.Unmarshal(b, &raw); err != nil {
		return InvalidVersionError(string(b))
	}

	result, err := Parse(raw)
	if err != nil {
		return err
	}

	pv.Version = result.Version
	pv.Prerelease = result.Prerelease
	return nil
}

var (
	nilPreRelease = [8]byte{0, 0, 0, 0, 0, 0, 0, 0}
)

var (
	// rawVersion used to generate rivine's protocol version
	rawVersion = "v1.0.6-alpha"
	// Version is the current version of rivined.
	Version ProtocolVersion
)

const (
	// EncodedVersionLength is the static length of a sia-encoded ProtocolVersion.
	EncodedVersionLength = 16 // sizeof(uint32==64) + sizeof([8]uint8)
)

const versionRe = `^v?(0{0,2}[0-9]|[0-1]?[0-9]{1,2}|2[0-4][0-9]|25[0-5])(?:\.(0{0,2}[0-9]|[0-1]?[0-9]{1,2}|2[0-4][0-9]|25[0-5]))?(?:\.(0{0,2}[0-9]|[0-1]?[0-9]{1,2}|2[0-4][0-9]|25[0-5]))?(?:-(.+?))?$`

// contains the regexp for all valid versions
var versionReg = regexp.MustCompile(versionRe)

func init() {
	Version = MustParse(rawVersion)
}
<commit_msg>Bump rawVersion to v1.0.6<commit_after>package build

import (
	"encoding/json"
	"fmt"
	"regexp"
	"strconv"
)

// Parse attempts to create a version based on a given string
func Parse(raw string) (ver ProtocolVersion, err error) {
	parts := versionReg.FindStringSubmatch(raw)
	if len(parts) != 5 {
		err = InvalidVersionError(raw)
		return
	}

	// because of the regexp we can be sure that this will always succeed
	// an empty string automatically results in 0, even though it also returns an err
	major, _ := strconv.ParseUint(parts[1], 10, 8)
	minor, _ := strconv.ParseUint(parts[2], 10, 8)
	patch, _ := strconv.ParseUint(parts[3], 10, 8)

	ver = NewPrereleaseVersion(uint8(major), uint8(minor), uint8(patch), parts[4])
	return
}

// MustParse creates a version based on a given string,
// panics in case the given string is invalid
func MustParse(raw string) ProtocolVersion {
	version, err := Parse(raw)
	if err != nil {
		panic(err)
	}
	return version
}

// NewVersion creates a new protocol version
func NewVersion(major, minor, patch uint8) ProtocolVersion {
	return NewPrereleaseVersion(major, minor, patch, "")
}

// NewPrereleaseVersion creates a new protocol prerelease version
func NewPrereleaseVersion(major, minor, patch uint8, prerelease string) ProtocolVersion {
	var v ProtocolVersion
	v.Version = (uint32(major) << 24) | (uint32(minor) << 16) | (uint32(patch) << 8)
	copy(v.Prerelease[:], prerelease[:])
	return v
}

// ProtocolVersion defines the protocol version that a node uses
type ProtocolVersion struct {
	Version    uint32  // Semantic Versioning
	Prerelease [8]byte // Any pre-release tag (eg. 'alpha' or the git commit hash)
}

// InvalidVersionError indicates a protocol version is invalid.
type InvalidVersionError string

// Error implements the error interface for InvalidVersionError.
func (e InvalidVersionError) Error() string {
	if len(e) == 0 {
		return "invalid version: <nil>"
	}

	return "invalid version: " + string(e)
}

// Compare returns an integer comparing this version with another version.
func (pv ProtocolVersion) Compare(other ProtocolVersion) int {
	if pv.Version < other.Version {
		return -1
	} else if pv.Version > other.Version {
		return 1
	}

	isAPrerelease := pv.Prerelease != nilPreRelease
	isBPrerelease := other.Prerelease != nilPreRelease

	if !isAPrerelease && isBPrerelease {
		return 1
	} else if isAPrerelease && !isBPrerelease {
		return -1
	}

	// NOTE: if the 2 versions both have a prerelease defined we count them as equal,
	//       regardless if those prerelease values are different or not

	return 0
}

// String returns the string version of this ProtocolVersion
func (pv ProtocolVersion) String() string {
	str := fmt.Sprintf("%d.%d.%d",
		(pv.Version>>24)&0xFF, // major
		(pv.Version>>16)&0xFF, // minor
		(pv.Version>>8)&0xFF,  // patch
	)

	// optional prerelease
	if pv.Prerelease != nilPreRelease {
		str += "-" + string(pv.Prerelease[:])
	}

	return str
}

// MarshalJSON implements json.Marshaler.MarshalJSON
func (pv ProtocolVersion) MarshalJSON() ([]byte, error) {
	return json.Marshal(pv.String())
}

// UnmarshalJSON implements json.Unmarshaler.UnmarshalJSON
func (pv *ProtocolVersion) UnmarshalJSON(b []byte) error {
	var raw string
	if err := json.Unmarshal(b, &raw); err != nil {
		return InvalidVersionError(string(b))
	}

	result, err := Parse(raw)
	if err != nil {
		return err
	}

	pv.Version = result.Version
	pv.Prerelease = result.Prerelease
	return nil
}

var (
	nilPreRelease = [8]byte{0, 0, 0, 0, 0, 0, 0, 0}
)

var (
	// rawVersion used to generate rivine's protocol version
	rawVersion = "v1.0.6"
	// Version is the current version of rivined.
	Version ProtocolVersion
)

const (
	// EncodedVersionLength is the static length of a sia-encoded ProtocolVersion.
	EncodedVersionLength = 16 // sizeof(uint32==64) + sizeof([8]uint8)
)

const versionRe = `^v?(0{0,2}[0-9]|[0-1]?[0-9]{1,2}|2[0-4][0-9]|25[0-5])(?:\.(0{0,2}[0-9]|[0-1]?[0-9]{1,2}|2[0-4][0-9]|25[0-5]))?(?:\.(0{0,2}[0-9]|[0-1]?[0-9]{1,2}|2[0-4][0-9]|25[0-5]))?(?:-(.+?))?$`

// contains the regexp for all valid versions
var versionReg = regexp.MustCompile(versionRe)

func init() {
	Version = MustParse(rawVersion)
}
<|endoftext|>


<commit_before>// 27 september 2014

package main

import (
	"flag"
	"runtime"
)

type GCCBase struct {
	CC		string
	CXX		string
	LD		string
	RC		string
	ArchFlag	[]string
}

func (g *GCCBase) buildRegularFile(cc string, std string, cflags []string, filename string) (stages []Stage, object string) {
	object = objectName(filename, ".o")
	line := []string{
		cc,
		filename,
		"-c",
		std,
		"-Wall",
		"-Wextra",
		// for the case where we are implementing an interface and are not using some parameter
		"-Wno-unused-parameter",
	}
	if g.ArchFlag != nil {
		line = append(line, g.ArchFlag...)
	}
	line = append(line, cflags...)
	if *debug {
		line = append(line, "-g")
	}
	line = append(line, "-o", object)
	e := &Executor{
		Name:	"Compiled " + filename,
		Line:		line,
	}
	stages = []Stage{
		nil,
		Stage{e},
		nil,
	}
	return stages, object
}

func (g *GCCBase) BuildCFile(filename string, cflags []string) (stages []Stage, object string) {
	return g.buildRegularFile(
		g.CC,
		"--std=c99",		// I refuse to support C11.
		cflags,
		filename)
}

func (g *GCCBase) BuildCXXFile(filename string, cflags []string) (stages []Stage, object string) {
	g.LD = g.CXX
	return g.buildRegularFile(
		g.CXX,
		"--std=c++11",
		cflags,
		filename)
}

// apart from needing -lobjc at link time, Objective-C/C++ are identical to C/C++; the --std flags are the same (thanks Beelsebob in irc.freenode.net/#macdev)
// TODO provide -lobjc?

func (g *GCCBase) BuildMFile(filename string, cflags []string) (stages []Stage, object string) {
	return g.BuildCFile(filename, cflags)
}

func (g *GCCBase) BuildMMFile(filename string, cflags []string) (stages []Stage, object string) {
	return g.BuildCXXFile(filename, cflags)
}

func (g *GCCBase) BuildRCFile(filename string, cflags []string) (stages []Stage, object string) {
	if g.RC == "" {
		fail("LLVM/clang does not come with a Windows resource compiler (if this message appears in other situations in error, contact andlabs)")
	}
	object = objectName(filename, ".o")
	line := append([]string{
		g.RC,
		filename,
		object,
	}, cflags...)
	e := &Executor{
		Name:	"Compiled " + filename,
		Line:		line,
	}
	stages = []Stage{
		nil,
		Stage{e},
		nil,
	}
	return stages, object
}

func (g *GCCBase) Link(objects []string, ldflags []string, libs []string) *Executor {
	if g.LD == "" {
		g.LD = g.CC
	}
	target := targetName()
	for i := 0; i < len(libs); i++ {
		libs[i] = "-l" + libs[i]
	}
	line := []string{
		g.LD,
	}
	if g.ArchFlag != nil {
		line = append(line, g.ArchFlag...)
	}
	line = append(line, objects...)
	line = append(line, ldflags...)
	line = append(line, libs...)
	if *debug {
		line = append(line, "-g")
	}
	line = append(line, "-o", target)
	return &Executor{
		Name:	"Linking " + target,
		Line:		line,
	}
}

// TODO:
// - MinGW static libgcc/libsjlj/libwinpthread/etc.

var triplet = flag.String("triplet", "", "gcc/clang target triplet to use; see README")

var garchs = map[string]string{
	"386":		"i686",
	"amd64":		"x86_64",
}

// 386 and amd64 are commonly configured using multilib rather than targets
// everything else will be a nil slice
var garchflags = map[string][]string{
	"386":		[]string{"-m32"},
	"amd64":		[]string{"-m64"},
}

type GCC struct {
	*GCCBase
}

func isMultilib() bool {
	if *targetOS == runtime.GOOS && runtime.GOOS != "windows" {
		// MinGW for Windows is not multilib
		// assume everything else is
		if runtime.GOARCH == "386" || runtime.GOARCH == "amd64" {
			if *targetArch == "386" || *targetArch == "amd64" {
				// multilib only
				return true
			}
		}
	}
	return false
}

func (g *GCC) Prepare() {
	garch := garchs[*targetArch]
	prefix := ""
	if *triplet != "" {
		prefix = *triplet + "-"
		goto out
	}
	// set this before any of the following in case target == host
	g.ArchFlag = garchflags[*targetArch]
	if *targetOS == runtime.GOOS && *targetArch == runtime.GOARCH {
		return
	}
	if isMultilib() {
		return
	}
	switch *targetOS {
	case "windows":
		prefix = garch + "-w64-mingw32-"
	case "linux":
		// TODO abi override
		prefix = garch + "-linux-gnu-"
	default:
		fail("Sorry, cross-compiling for gcc on %s requires specifying an explicit target triple with -target", *targetOS)
	}
out:
	g.CC = prefix + g.CC
	g.CXX = prefix + g.CXX
	g.RC = prefix + g.RC
}

type Clang struct {
	*GCCBase
}

var clangOS = map[string]string{
	"windows":	"TODO",
	"linux":		"linux",
	"darwin":		"TODO",
	"freebsd":		"TODO",
	// TODO others
}

func (g *Clang) Prepare() {
	if *triplet != "" {
		g.ArchFlag = []string{"-target", *triplet}
		return
	}
	// set this before any of the following in case target == host
	g.ArchFlag = garchflags[*targetArch]
	if *targetOS == runtime.GOOS && *targetArch == runtime.GOARCH {
		return
	}
	if isMultilib() {
		return
	}
	// clang makes the job easier
	// TODO abi override
	g.ArchFlag = append(g.ArchFlag, "-target", garchs[*targetArch] + "-" + clangOS[*targetOS])
}

func init() {
	toolchains["gcc"] = &GCC{
		GCCBase:		&GCCBase{
			CC:		"gcc",
			CXX:		"g++",
			RC:		"windres",
		},
	}
	toolchains["clang"] = &Clang{
		GCCBase:		&GCCBase{
			CC:		"clang",
			CXX:		"clang++",
			// no RC in clang
		},
	}
}
<commit_msg>Filled in the clang OS table.<commit_after>// 27 september 2014

package main

import (
	"flag"
	"runtime"
)

type GCCBase struct {
	CC		string
	CXX		string
	LD		string
	RC		string
	ArchFlag	[]string
}

func (g *GCCBase) buildRegularFile(cc string, std string, cflags []string, filename string) (stages []Stage, object string) {
	object = objectName(filename, ".o")
	line := []string{
		cc,
		filename,
		"-c",
		std,
		"-Wall",
		"-Wextra",
		// for the case where we are implementing an interface and are not using some parameter
		"-Wno-unused-parameter",
	}
	if g.ArchFlag != nil {
		line = append(line, g.ArchFlag...)
	}
	line = append(line, cflags...)
	if *debug {
		line = append(line, "-g")
	}
	line = append(line, "-o", object)
	e := &Executor{
		Name:	"Compiled " + filename,
		Line:		line,
	}
	stages = []Stage{
		nil,
		Stage{e},
		nil,
	}
	return stages, object
}

func (g *GCCBase) BuildCFile(filename string, cflags []string) (stages []Stage, object string) {
	return g.buildRegularFile(
		g.CC,
		"--std=c99",		// I refuse to support C11.
		cflags,
		filename)
}

func (g *GCCBase) BuildCXXFile(filename string, cflags []string) (stages []Stage, object string) {
	g.LD = g.CXX
	return g.buildRegularFile(
		g.CXX,
		"--std=c++11",
		cflags,
		filename)
}

// apart from needing -lobjc at link time, Objective-C/C++ are identical to C/C++; the --std flags are the same (thanks Beelsebob in irc.freenode.net/#macdev)
// TODO provide -lobjc?

func (g *GCCBase) BuildMFile(filename string, cflags []string) (stages []Stage, object string) {
	return g.BuildCFile(filename, cflags)
}

func (g *GCCBase) BuildMMFile(filename string, cflags []string) (stages []Stage, object string) {
	return g.BuildCXXFile(filename, cflags)
}

func (g *GCCBase) BuildRCFile(filename string, cflags []string) (stages []Stage, object string) {
	if g.RC == "" {
		fail("LLVM/clang does not come with a Windows resource compiler (if this message appears in other situations in error, contact andlabs)")
	}
	object = objectName(filename, ".o")
	line := append([]string{
		g.RC,
		filename,
		object,
	}, cflags...)
	e := &Executor{
		Name:	"Compiled " + filename,
		Line:		line,
	}
	stages = []Stage{
		nil,
		Stage{e},
		nil,
	}
	return stages, object
}

func (g *GCCBase) Link(objects []string, ldflags []string, libs []string) *Executor {
	if g.LD == "" {
		g.LD = g.CC
	}
	target := targetName()
	for i := 0; i < len(libs); i++ {
		libs[i] = "-l" + libs[i]
	}
	line := []string{
		g.LD,
	}
	if g.ArchFlag != nil {
		line = append(line, g.ArchFlag...)
	}
	line = append(line, objects...)
	line = append(line, ldflags...)
	line = append(line, libs...)
	if *debug {
		line = append(line, "-g")
	}
	line = append(line, "-o", target)
	return &Executor{
		Name:	"Linking " + target,
		Line:		line,
	}
}

// TODO:
// - MinGW static libgcc/libsjlj/libwinpthread/etc.

var triplet = flag.String("triplet", "", "gcc/clang target triplet to use; see README")

var garchs = map[string]string{
	"386":		"i686",
	"amd64":		"x86_64",
}

// 386 and amd64 are commonly configured using multilib rather than targets
// everything else will be a nil slice
var garchflags = map[string][]string{
	"386":		[]string{"-m32"},
	"amd64":		[]string{"-m64"},
}

type GCC struct {
	*GCCBase
}

func isMultilib() bool {
	if *targetOS == runtime.GOOS && runtime.GOOS != "windows" {
		// MinGW for Windows is not multilib
		// assume everything else is
		if runtime.GOARCH == "386" || runtime.GOARCH == "amd64" {
			if *targetArch == "386" || *targetArch == "amd64" {
				// multilib only
				return true
			}
		}
	}
	return false
}

func (g *GCC) Prepare() {
	garch := garchs[*targetArch]
	prefix := ""
	if *triplet != "" {
		prefix = *triplet + "-"
		goto out
	}
	// set this before any of the following in case target == host
	g.ArchFlag = garchflags[*targetArch]
	if *targetOS == runtime.GOOS && *targetArch == runtime.GOARCH {
		return
	}
	if isMultilib() {
		return
	}
	switch *targetOS {
	case "windows":
		prefix = garch + "-w64-mingw32-"
	case "linux":
		// TODO abi override
		prefix = garch + "-linux-gnu-"
	default:
		fail("Sorry, cross-compiling for gcc on %s requires specifying an explicit target triple with -target", *targetOS)
	}
out:
	g.CC = prefix + g.CC
	g.CXX = prefix + g.CXX
	g.RC = prefix + g.RC
}

type Clang struct {
	*GCCBase
}

// see the LLVM source; file include/llvm/ADT/Triple.h (thanks jroelofs in irc.oftc.net/#llvm)
var clangOS = map[string]string{
	"windows":	"win32",
	"linux":		"linux",
	"darwin":		"darwin",
	"freebsd":		"freebsd",
	"openbsd":	"openbsd",
	"netbsd":		"netbsd",
	"dragonfly":	"dragonfly",
	"solaris":		"solaris",
}

func (g *Clang) Prepare() {
	if *triplet != "" {
		g.ArchFlag = []string{"-target", *triplet}
		return
	}
	// set this before any of the following in case target == host
	g.ArchFlag = garchflags[*targetArch]
	if *targetOS == runtime.GOOS && *targetArch == runtime.GOARCH {
		return
	}
	if isMultilib() {
		return
	}
	// clang makes the job easier
	// TODO abi override
	g.ArchFlag = append(g.ArchFlag, "-target", garchs[*targetArch] + "-" + clangOS[*targetOS])
}

func init() {
	toolchains["gcc"] = &GCC{
		GCCBase:		&GCCBase{
			CC:		"gcc",
			CXX:		"g++",
			RC:		"windres",
		},
	}
	toolchains["clang"] = &Clang{
		GCCBase:		&GCCBase{
			CC:		"clang",
			CXX:		"clang++",
			// no RC in clang
		},
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
)

type mpath struct {
	name string
	path string
}

type vdir string

func (vd vdir) trunc() string {
	s := string(vd)
	if len(s) > 0 {
		return s[:7]
	}
	return ""
}

var mpathre = regexp.MustCompile(`^\.(.*)###(.*)$`)
var vdirre = regexp.MustCompile(`^[a-f0-9]{64}$`)

func newmpath(mp string) *mpath {
	res := mpathre.FindAllStringSubmatch(mp, -1)
	var mres *mpath
	if res != nil && len(res) == 1 && len(res[0]) == 3 {
		name := res[0][1]
		path := res[0][2]
		path = strings.Replace(path, ",#,", "/", -1)
		mres = &mpath{name, path}
	}
	return mres
}

func (mp *mpath) String() string {
	return "." + mp.name + "###" + strings.Replace(mp.path, "/", ",#,", -1)
}

func newvdir(vd string) vdir {
	res := vdirre.FindString(vd)
	vres := vdir("")
	if res != "" && res == vd {
		vres = vdir(vd)
	}
	return vres
}

type marker struct {
	mp  *mpath
	dir vdir
}

func (mk *marker) String() string {
	return fmt.Sprintf("marker '%s'<%s->%s>", mk.dir.trunc(), mk.mp.name, mk.mp.path)
}

type markers []*marker

var allmarkers = markers{}

func (marks markers) getMarker(name string, path string, dir vdir) *marker {
	var mark *marker
	var pathdiff *marker
	for _, marker := range marks {
		if marker.mp.name == name {
			if marker.mp.path == path {
				mark = marker
				break
			} else {
				pathdiff = marker
			}
		}
	}
	if mark == nil {
		if pathdiff != nil {
			fmt.Printf("Invalid volume path detected: '%s' (not found in marker '%s')\n", path, pathdiff)
			return nil
		}
		mark = &marker{mp: &mpath{name: name, path: path}, dir: dir}
	}
	ldir := mark.dir
	if mark.dir != dir {
		// move dir and ln -s mark.dir dir
		ldir = dir
		cmd(fmt.Sprintf("sudo move /mnt/sda1/var/lib/docker/vfs/dir/%s /mnt/sda1/var/lib/docker/vfs/dir/_%s", dir, dir))
		fmt.Printf("Mark container named '%s' for path '%s' as link to '%s' (from '%s')\n", name, path, mark.dir, dir)
	}
	_, err := cmd(fmt.Sprintf("sudo ls -1L /mnt/sda1/var/lib/docker/vfs/dir/%s", mark.mp.String()))
	if err != nil {
		mustcmd(fmt.Sprintf("sudo ln -s %s /mnt/sda1/var/lib/docker/vfs/dir/%s", ldir, mark.mp.String()))
	}
	return mark
}

type volume struct {
	dir  vdir
	mark *marker
}

type volumes []*volume

var allvolumes = volumes{}

func (v *volume) String() string {
	return fmt.Sprintf("vol '%s'<%v>", v.dir.trunc(), v.mark)
}

func (vols volumes) getVolume(vd vdir, path string, name string) *volume {
	var vol *volume
	for _, volume := range vols {
		if string(volume.dir) == string(vd) {
			vol = volume
			if vol.mark == nil {
				vol.mark = allmarkers.getMarker(name, path, vol.dir)
			}
			if vol.mark == nil {
				return nil
			}
			break
		}
	}
	if vol == nil {
		vol = &volume{dir: vd}
		vol.mark = allmarkers.getMarker(name, path, vol.dir)
		if vol.mark == nil {
			return nil
		}
	}
	return vol
}

type container struct {
	name    string
	id      string
	stopped bool
	volumes []*volume
}

func (c *container) trunc() string {
	if len(c.id) > 0 {
		return c.id[:7]
	}
	return ""
}

func (c *container) String() string {
	return "cnt '" + c.name + "' (" + c.trunc() + ")" + fmt.Sprintf("[%v] - %d vol", c.stopped, len(c.volumes))
}

var containers = []*container{}

func mustcmd(acmd string) string {
	out, err := cmd(acmd)
	if err != nil {
		log.Fatal(fmt.Sprintf("out='%s', err='%s'", out, err))
	}
	return string(out)
}

type fcmd func(cmd string) (string, error)

var cmd = execcmd

func execcmd(cmd string) (string, error) {
	fmt.Println(cmd)
	out, err := exec.Command("sh", "-c", cmd).Output()
	return strings.TrimSpace(string(out)), err
}

func readVolumes() {
	out := mustcmd("sudo ls -a1F /mnt/sda1/var/lib/docker/vfs/dir")
	vollines := strings.Split(out, "\n")
	// fmt.Println(vollines)
	for _, volline := range vollines {
		dir := volline
		if dir == "./" || dir == "../" {
			continue
		}
		if strings.HasSuffix(dir, "@") {
			dir = dir[:len(dir)-1]
			fdir := fmt.Sprintf("/mnt/sda1/var/lib/docker/vfs/dir/%s", dir)
			mp := newmpath(dir)
			if mp == nil {
				fmt.Printf("Invalid marker detected: '%s'\n", dir)
				mustcmd("sudo rm " + fdir)
			} else {
				dirlink, err := cmd("sudo readlink " + fdir)
				fmt.Printf("---\ndir: '%s'\ndlk: '%s'\nerr='%v'\n", dir, dirlink, err)
				if err != nil {
					fmt.Printf("Invalid marker (no readlink) detected: '%s'\n", dir)
					mustcmd("sudo rm " + fdir)
				} else {
					_, err := cmd("sudo ls /mnt/sda1/var/lib/docker/vfs/dir/" + dirlink)
					if err != nil {
						fmt.Printf("Invalid marker (readlink no ls) detected: '%s'\n", dir)
						mustcmd("sudo rm " + fdir)
					} else {
						vd := newvdir(dirlink)
						if vd == "" {
							fmt.Printf("Invalid marker (readlink no vdir) detected: '%s'\n", dir)
							mustcmd("sudo rm " + fdir)
						} else {
							allmarkers = append(allmarkers, &marker{mp, vd})
						}
					}
				}
			}
		} else if strings.HasSuffix(dir, "/") {

			dir = dir[:len(dir)-1]
			fdir := fmt.Sprintf("/mnt/sda1/var/lib/docker/vfs/dir/%s", dir)
			vd := newvdir(dir)
			if vd == "" {
				fmt.Printf("Invalid volume folder detected: '%s'\n", dir)
				mustcmd("sudo rm " + fdir)
			} else {
				allvolumes = append(allvolumes, &volume{dir: vd})
			}
		} else {
			fdir := fmt.Sprintf("/mnt/sda1/var/lib/docker/vfs/dir/%s", dir)
			fmt.Printf("Invalid file detected: '%s'\n", dir)
			mustcmd("sudo rm " + fdir)
		}
	}
	fmt.Printf("volumes: %v\nmarkers: %v\n", allvolumes, allmarkers)
}

func readContainer() {

	out := mustcmd("docker ps -aq --no-trunc")
	contlines := strings.Split(out, "\n")
	// fmt.Println(contlines)
	for _, contline := range contlines {
		id := contline
		res := mustcmd("docker inspect -f '{{ .Name }},{{ range $key, $value := .Volumes }}{{ $key }},{{ $value }}##~#{{ end }}' " + id)
		// fmt.Println("res1: '" + res + "'")
		name := res[1:strings.Index(res, ",")]
		cont := &container{name: name, id: id}
		res = res[strings.Index(res, ",")+1:]
		// fmt.Println("res2: '" + res + "'")
		vols := strings.Split(res, "##~#")
		// fmt.Println(vols)
		for _, vol := range vols {
			elts := strings.Split(vol, ",")
			if len(elts) == 2 {
				// fmt.Printf("elts: '%v'\n", elts)
				path := elts[0]
				vfs := elts[1]
				if strings.Contains(vfs, "/var/lib/docker/vfs/dir/") {
					vd := newvdir(filepath.Base(vfs))
					if vd == "" {
						fmt.Printf("Invalid volume folder detected: '%s'\n", vfs)
						break
					}
					newvol := allvolumes.getVolume(vd, path, name)
					cont.volumes = append(cont.volumes, newvol)
				}
			}
		}
		containers = append(containers, cont)
		if len(cont.volumes) == 0 {
			fmt.Printf("Orphan container detected: '%s'\n", cont)
		}
	}
	fmt.Printf("containers: %v\n", containers)
}

// docker run --rm -i -t -v `pwd`:`pwd` -w `pwd` --entrypoint="/bin/bash" go -c 'go build gcl.go'
func main() {
	fmt.Println("### 1/2 readVolumes     ###")
	readVolumes()
	fmt.Println("### 2/2 readContainer   ###")
	readContainer()
}
<commit_msg>gcl.go: make it silent<commit_after>package main

import (
	"fmt"
	"log"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
)

type mpath struct {
	name string
	path string
}

type vdir string

func (vd vdir) trunc() string {
	s := string(vd)
	if len(s) > 0 {
		return s[:7]
	}
	return ""
}

var mpathre = regexp.MustCompile(`^\.(.*)###(.*)$`)
var vdirre = regexp.MustCompile(`^[a-f0-9]{64}$`)

func newmpath(mp string) *mpath {
	res := mpathre.FindAllStringSubmatch(mp, -1)
	var mres *mpath
	if res != nil && len(res) == 1 && len(res[0]) == 3 {
		name := res[0][1]
		path := res[0][2]
		path = strings.Replace(path, ",#,", "/", -1)
		mres = &mpath{name, path}
	}
	return mres
}

func (mp *mpath) String() string {
	return "." + mp.name + "###" + strings.Replace(mp.path, "/", ",#,", -1)
}

func newvdir(vd string) vdir {
	res := vdirre.FindString(vd)
	vres := vdir("")
	if res != "" && res == vd {
		vres = vdir(vd)
	}
	return vres
}

type marker struct {
	mp  *mpath
	dir vdir
}

func (mk *marker) String() string {
	return fmt.Sprintf("marker '%s'<%s->%s>", mk.dir.trunc(), mk.mp.name, mk.mp.path)
}

type markers []*marker

var allmarkers = markers{}

func (marks markers) getMarker(name string, path string, dir vdir) *marker {
	var mark *marker
	var pathdiff *marker
	for _, marker := range marks {
		if marker.mp.name == name {
			if marker.mp.path == path {
				mark = marker
				break
			} else {
				pathdiff = marker
			}
		}
	}
	if mark == nil {
		if pathdiff != nil {
			fmt.Printf("Invalid volume path detected: '%s' (not found in marker '%s')\n", path, pathdiff)
			return nil
		}
		mark = &marker{mp: &mpath{name: name, path: path}, dir: dir}
	}
	ldir := mark.dir
	if mark.dir != dir {
		// move dir and ln -s mark.dir dir
		ldir = dir
		cmd(fmt.Sprintf("sudo move /mnt/sda1/var/lib/docker/vfs/dir/%s /mnt/sda1/var/lib/docker/vfs/dir/_%s", dir, dir))
		fmt.Printf("Mark container named '%s' for path '%s' as link to '%s' (from '%s')\n", name, path, mark.dir, dir)
	}
	_, err := cmd(fmt.Sprintf("sudo ls -1L /mnt/sda1/var/lib/docker/vfs/dir/%s", mark.mp.String()))
	if err != nil {
		mustcmd(fmt.Sprintf("sudo ln -s %s /mnt/sda1/var/lib/docker/vfs/dir/%s", ldir, mark.mp.String()))
	}
	return mark
}

type volume struct {
	dir  vdir
	mark *marker
}

type volumes []*volume

var allvolumes = volumes{}

func (v *volume) String() string {
	return fmt.Sprintf("vol '%s'<%v>", v.dir.trunc(), v.mark)
}

func (vols volumes) getVolume(vd vdir, path string, name string) *volume {
	var vol *volume
	for _, volume := range vols {
		if string(volume.dir) == string(vd) {
			vol = volume
			if vol.mark == nil {
				vol.mark = allmarkers.getMarker(name, path, vol.dir)
			}
			if vol.mark == nil {
				return nil
			}
			break
		}
	}
	if vol == nil {
		vol = &volume{dir: vd}
		vol.mark = allmarkers.getMarker(name, path, vol.dir)
		if vol.mark == nil {
			return nil
		}
	}
	return vol
}

type container struct {
	name    string
	id      string
	stopped bool
	volumes []*volume
}

func (c *container) trunc() string {
	if len(c.id) > 0 {
		return c.id[:7]
	}
	return ""
}

func (c *container) String() string {
	return "cnt '" + c.name + "' (" + c.trunc() + ")" + fmt.Sprintf("[%v] - %d vol", c.stopped, len(c.volumes))
}

var containers = []*container{}

func mustcmd(acmd string) string {
	out, err := cmd(acmd)
	if err != nil {
		log.Fatal(fmt.Sprintf("out='%s', err='%s'", out, err))
	}
	return string(out)
}

type fcmd func(cmd string) (string, error)

var cmd = execcmd

func execcmd(cmd string) (string, error) {
	fmt.Println(cmd)
	out, err := exec.Command("sh", "-c", cmd).Output()
	return strings.TrimSpace(string(out)), err
}

func readVolumes() {
	out := mustcmd("sudo ls -a1F /mnt/sda1/var/lib/docker/vfs/dir")
	vollines := strings.Split(out, "\n")
	for _, volline := range vollines {
		dir := volline
		if dir == "./" || dir == "../" {
			continue
		}
		if strings.HasSuffix(dir, "@") {
			dir = dir[:len(dir)-1]
			fdir := fmt.Sprintf("/mnt/sda1/var/lib/docker/vfs/dir/%s", dir)
			mp := newmpath(dir)
			if mp == nil {
				fmt.Printf("Invalid marker detected: '%s'\n", dir)
				mustcmd("sudo rm " + fdir)
			} else {
				dirlink, err := cmd("sudo readlink " + fdir)
				fmt.Printf("---\ndir: '%s'\ndlk: '%s'\nerr='%v'\n", dir, dirlink, err)
				if err != nil {
					fmt.Printf("Invalid marker (no readlink) detected: '%s'\n", dir)
					mustcmd("sudo rm " + fdir)
				} else {
					_, err := cmd("sudo ls /mnt/sda1/var/lib/docker/vfs/dir/" + dirlink)
					if err != nil {
						fmt.Printf("Invalid marker (readlink no ls) detected: '%s'\n", dir)
						mustcmd("sudo rm " + fdir)
					} else {
						vd := newvdir(dirlink)
						if vd == "" {
							fmt.Printf("Invalid marker (readlink no vdir) detected: '%s'\n", dir)
							mustcmd("sudo rm " + fdir)
						} else {
							allmarkers = append(allmarkers, &marker{mp, vd})
						}
					}
				}
			}
		} else if strings.HasSuffix(dir, "/") {

			dir = dir[:len(dir)-1]
			fdir := fmt.Sprintf("/mnt/sda1/var/lib/docker/vfs/dir/%s", dir)
			vd := newvdir(dir)
			if vd == "" {
				fmt.Printf("Invalid volume folder detected: '%s'\n", dir)
				mustcmd("sudo rm " + fdir)
			} else {
				allvolumes = append(allvolumes, &volume{dir: vd})
			}
		} else {
			fdir := fmt.Sprintf("/mnt/sda1/var/lib/docker/vfs/dir/%s", dir)
			fmt.Printf("Invalid file detected: '%s'\n", dir)
			mustcmd("sudo rm " + fdir)
		}
	}
}

func readContainer() {

	out := mustcmd("docker ps -aq --no-trunc")
	contlines := strings.Split(out, "\n")
	// fmt.Println(contlines)
	for _, contline := range contlines {
		id := contline
		res := mustcmd("docker inspect -f '{{ .Name }},{{ range $key, $value := .Volumes }}{{ $key }},{{ $value }}##~#{{ end }}' " + id)
		// fmt.Println("res1: '" + res + "'")
		name := res[1:strings.Index(res, ",")]
		cont := &container{name: name, id: id}
		res = res[strings.Index(res, ",")+1:]
		// fmt.Println("res2: '" + res + "'")
		vols := strings.Split(res, "##~#")
		// fmt.Println(vols)
		for _, vol := range vols {
			elts := strings.Split(vol, ",")
			if len(elts) == 2 {
				// fmt.Printf("elts: '%v'\n", elts)
				path := elts[0]
				vfs := elts[1]
				if strings.Contains(vfs, "/var/lib/docker/vfs/dir/") {
					vd := newvdir(filepath.Base(vfs))
					if vd == "" {
						fmt.Printf("Invalid volume folder detected: '%s'\n", vfs)
						break
					}
					newvol := allvolumes.getVolume(vd, path, name)
					cont.volumes = append(cont.volumes, newvol)
				}
			}
		}
		containers = append(containers, cont)
		if len(cont.volumes) == 0 {
			fmt.Printf("Orphan container detected: '%s'\n", cont)
		}
	}
}

// docker run --rm -i -t -v `pwd`:`pwd` -w `pwd` --entrypoint="/bin/bash" go -c 'go build gcl.go'
func main() {
	readVolumes()
	readContainer()
}
<|endoftext|>


<commit_before>package wuxia

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"

	"github.com/robertkrimen/otto"
	"github.com/spf13/afero"
)

const (
	scriptsDir = "scripts"
	initDir    = "init"
	planDir    = "plan"
	configFile = "config.json"
)

type buildStage int

const (
	stageInit buildStage = iota
	stageConfig
	stagePlan
	stageExec
)

func (s buildStage) String() string {
	var rst string
	switch s {
	case stageInit:
		rst = "init"
	case stageConfig:
		rst = "config"
	case stagePlan:
		rst = "plan"
	case stageExec:
		rst = "exec"
	default:
		rst = "unkown stage"
	}
	return rst
}

//buildError error returned when building the static website. The error string
//returned is a json string that encodes the build stage and the message.
type buildError struct {
	Stage   string `json:"stage"`
	Message string `json:"msg"`
}

func buildErr(stage buildStage, msg string) error {
	return &buildError{Stage: stage.String(), Message: msg}
}

func (b *buildError) Error() string {
	o, err := json.Marshal(b)
	if err != nil {
		return err.Error()
	}
	return string(o)
}

//Generator provides the static website generation capabilities.This is heavily
//integrated with the otto javascript runtime.
type Generator struct {
	vm  *otto.Otto
	sys *System
	fs  afero.Fs

	// This is the absolute path to the root of the project from which the
	// Generator will be operating.
	workDir string
}

//NewGenerator retrunes a new  Generator.
func NewGenerator(vm *otto.Otto, sys *System, fs afero.Fs) *Generator {
	return &Generator{
		vm:  vm,
		sys: sys,
		fs:  fs,
	}
}

//Build builds a project.
func (g *Generator) Build() error {
	return evaluate(g.init, g.config, g.plan, g.exec, g.down)
}

//initializes the build process. Any stages after this will have the generator
//already bootstraped.
//
// It is possible to bootstrap the generator from the project( User's side) by
// providing an entry javascript file in the default path of
// scripts/init/index.js which will be executed and you can overide the default
// entry script which is evaluated internally
//
// Initialzation is offloaded to the javascript runtine of the generator..Any
// error returned is a build error.
func (g *Generator) init() error {
	if g.sys == nil {
		g.sys = defaultSystem()
	}
	if g.vm == nil {
		g.vm = defaultVM(g.sys)
	}
	_ = g.vm.Set("sys", func(call otto.FunctionCall) otto.Value {
		data, err := json.Marshal(g.sys)
		if err != nil {
			Panic(err)
		}
		val, err := call.Otto.Call("JSON.parse", nil, string(data))
		if err != nil {
			Panic(err)
		}
		return val
	})
	_, err := g.vm.Eval(entryScript())
	if err != nil {
		return buildErr(stageInit, err.Error())
	}

	// evaluate project provided entry script if provided. We ignore if the file
	// is not provided but any errors arsing from evaluating a provided script is
	// a built error.
	entryFile := filepath.Join(g.workDir, scriptsDir, initDir, "index.js")
	err = g.evaluateFile(entryFile)
	if err != nil {
		if !os.IsNotExist(err) {
			return buildErr(stageInit, err.Error())
		}
	}
	return nil
}

func defaultSystem() *System {
	pwd, err := os.Getwd()
	if err != nil {
		panic(err)
	}
	return &System{
		Boot: &Boot{
			ConfigiFile: configFile,
			PlanFile:    "index.js",
		},
		WorkDir: pwd,
	}
}

// opens the file in the specified path and evaluates it withing the context of
// the javascript runtine.
//
// The evaluated javascript code can mutate the global state. Use execFile to
// execute the javascript without mutating the state of the generato'r
// javascript runtime.
//
// TODO: (gernest) implement callFile if necessary
func (g *Generator) evaluateFile(path string) error {
	f, err := g.fs.Open(path)
	if err != nil {
		return err
	}
	defer func() { _ = f.Close() }()
	data, err := ioutil.ReadAll(f)
	if err != nil {
		return err
	}
	_, err = g.vm.Eval(data)
	if err != nil {
		return err
	}
	return nil
}

func defaultVM(sys *System) *otto.Otto {
	return otto.New()
}

func (g *Generator) config() error {
	v, err := g.vm.Call("getCurrentSys", nil)
	if err != nil {
		return buildErr(stageConfig, err.Error())
	}
	cSys := &System{}
	str, _ := v.ToString()
	err = json.Unmarshal([]byte(str), cSys)
	if err != nil {
		return buildErr(stageConfig, err.Error())
	}
	cfgFile := cSys.Boot.ConfigiFile
	cf, err := g.fs.Open(cfgFile)
	if err != nil {
		return buildErr(stageConfig, err.Error())
	}
	defer func() { _ = cf.Close() }()
	data, err := ioutil.ReadAll(cf)
	if err != nil {
		return buildErr(stageConfig, err.Error())
	}
	c := &Config{}
	err = json.Unmarshal(data, c)
	if err != nil {
		return buildErr(stageConfig, err.Error())
	}
	if cSys.Config == nil {
		cSys.Config = c
	} else {
		updateConfig(cSys.Config, c)
	}
	g.sys = cSys
	return nil
}

func updateConfig(old, new *Config) {
}

func (g *Generator) plan() error {
	return nil
}
func (g *Generator) exec() error {
	return nil
}
func (g *Generator) down() error {
	return nil
}

func evaluate(fn ...func() error) error {
	var err error
	for i := 0; i < len(fn); i++ {
		err = fn[i]()
		if err != nil {
			return err
		}
	}
	return err
}
<commit_msg>Refactoring<commit_after>package wuxia

import (
	"encoding/json"
	"io/ioutil"
	"os"
	"path/filepath"

	"github.com/robertkrimen/otto"
	"github.com/spf13/afero"
)

const (
	scriptsDir = "scripts"
	initDir    = "init"
	planDir    = "plan"
	configFile = "config.json"
)

type buildStage int

const (
	stageInit buildStage = iota
	stageConfig
	stagePlan
	stageExec
)

func (s buildStage) String() string {
	var rst string
	switch s {
	case stageInit:
		rst = "init"
	case stageConfig:
		rst = "config"
	case stagePlan:
		rst = "plan"
	case stageExec:
		rst = "exec"
	default:
		rst = "unkown stage"
	}
	return rst
}

//buildError error returned when building the static website. The error string
//returned is a json string that encodes the build stage and the message.
type buildError struct {
	Stage   string `json:"stage"`
	Message string `json:"msg"`
}

func buildErr(stage buildStage, msg string) error {
	return &buildError{Stage: stage.String(), Message: msg}
}

func (b *buildError) Error() string {
	o, err := json.Marshal(b)
	if err != nil {
		return err.Error()
	}
	return string(o)
}

//Generator provides the static website generation capabilities.This is heavily
//integrated with the otto javascript runtime.
type Generator struct {
	vm  *otto.Otto
	sys *System
	fs  afero.Fs

	// This is the absolute path to the root of the project from which the
	// Generator will be operating.
	workDir string
}

//NewGenerator retrunes a new  Generator.
func NewGenerator(vm *otto.Otto, sys *System, fs afero.Fs) *Generator {
	return &Generator{
		vm:  vm,
		sys: sys,
		fs:  fs,
	}
}

//Build builds a project.
func (g *Generator) Build() error {
	return evaluate(g.init, g.config, g.plan, g.exec, g.down)
}

//initializes the build process. Any stages after this will have the generator
//already bootstraped.
//
// It is possible to bootstrap the generator from the project( User's side) by
// providing an entry javascript file in the default path of
// scripts/init/index.js which will be executed and you can overide the default
// entry script which is evaluated internally
//
// Initialzation is offloaded to the javascript runtine of the generator..Any
// error returned is a build error.
func (g *Generator) init() error {
	if g.sys == nil {
		g.sys = defaultSystem()
	}
	if g.vm == nil {
		g.vm = defaultVM(g.sys)
	}
	_ = g.vm.Set("sys", func(call otto.FunctionCall) otto.Value {
		data, err := json.Marshal(g.sys)
		if err != nil {
			Panic(err)
		}
		val, err := call.Otto.Call("JSON.parse", nil, string(data))
		if err != nil {
			Panic(err)
		}
		return val
	})
	_, err := g.vm.Eval(entryScript())
	if err != nil {
		return buildErr(stageInit, err.Error())
	}

	// evaluate project provided entry script if provided. We ignore if the file
	// is not provided but any errors arsing from evaluating a provided script is
	// a built error.
	entryFile := filepath.Join(g.workDir, scriptsDir, initDir, "index.js")
	err = g.evaluateFile(entryFile)
	if err != nil {
		if !os.IsNotExist(err) {
			return buildErr(stageInit, err.Error())
		}
	}
	return nil
}

func defaultSystem() *System {
	pwd, err := os.Getwd()
	if err != nil {
		panic(err)
	}
	return &System{
		Boot: &Boot{
			ConfigiFile: configFile,
			PlanFile:    "index.js",
		},
		WorkDir: pwd,
	}
}

// opens the file in the specified path and evaluates it withing the context of
// the javascript runtine.
//
// The evaluated javascript code can mutate the global state. Use execFile to
// execute the javascript without mutating the state of the generato'r
// javascript runtime.
//
// TODO: (gernest) implement callFile if necessary
func (g *Generator) evaluateFile(path string) error {
	f, err := g.fs.Open(path)
	if err != nil {
		return err
	}
	defer func() { _ = f.Close() }()
	data, err := ioutil.ReadAll(f)
	if err != nil {
		return err
	}
	_, err = g.vm.Eval(data)
	if err != nil {
		return err
	}
	return nil
}

func defaultVM(sys *System) *otto.Otto {
	return otto.New()
}

func (g *Generator) config() error {
	v, err := g.vm.Call("getCurrentSys", nil)
	if err != nil {
		return buildErr(stageConfig, err.Error())
	}
	cSys := &System{}
	str, _ := v.ToString()
	err = json.Unmarshal([]byte(str), cSys)
	if err != nil {
		return buildErr(stageConfig, err.Error())
	}
	cfgFile := filepath.Join(g.workDir, cSys.Boot.ConfigiFile)
	cf, err := g.fs.Open(cfgFile)
	if err != nil {
		return buildErr(stageConfig, err.Error())
	}
	defer func() { _ = cf.Close() }()
	data, err := ioutil.ReadAll(cf)
	if err != nil {
		return buildErr(stageConfig, err.Error())
	}
	c := &Config{}
	err = json.Unmarshal(data, c)
	if err != nil {
		return buildErr(stageConfig, err.Error())
	}
	if cSys.Config == nil {
		cSys.Config = c
	} else {
		updateConfig(cSys.Config, c)
	}
	g.sys = cSys
	return nil
}

func updateConfig(old, new *Config) {
}

func (g *Generator) plan() error {
	return nil
}
func (g *Generator) exec() error {
	return nil
}
func (g *Generator) down() error {
	return nil
}

func evaluate(fn ...func() error) error {
	var err error
	for i := 0; i < len(fn); i++ {
		err = fn[i]()
		if err != nil {
			return err
		}
	}
	return err
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os/exec"
	"strings"
)

// use git to get the latest tag for the current directory/project
func getLatestVersionFromGit() (Version, error) {
	var version Version

	// run the git command to get the latest tag
	outputBytes, err := exec.Command("sh", "-c", "git describe --tags --abbrev=0").Output()

	// if the command failed to execute, exit with an error
	if err != nil {
		return version, fmt.Errorf("Failed to get latest version tag from git.")
	}

	// convert to a string and trim new lines
	versionString := strings.Trim(string(outputBytes), "\n")

	// get a Version struct from the tag string
	version, err = NewVersionFromString(versionString)

	// the tag wasn't a valid semver version
	if (err != nil) {
		return version, err
	}

	return version, nil
}

// use git to add a tag with a version
func setVersion(version Version) error {
	return exec.Command("sh", "-c", "git tag " + version.toString(false)).Run()
}<commit_msg>use annotated tags so that the last one is returned when retrieving the latest on a commit that has multiple tags<commit_after>package main

import (
	"fmt"
	"os/exec"
	"strings"
)

// use git to get the latest tag for the current directory/project
func getLatestVersionFromGit() (Version, error) {
	var version Version

	// run the git command to get the latest tag
	outputBytes, err := exec.Command("sh", "-c", "git describe --tags --abbrev=0").Output()

	// if the command failed to execute, exit with an error
	if err != nil {
		return version, fmt.Errorf("Failed to get latest version tag from git.")
	}

	// convert to a string and trim new lines
	versionString := strings.Trim(string(outputBytes), "\n")

	// get a Version struct from the tag string
	version, err = NewVersionFromString(versionString)

	// the tag wasn't a valid semver version
	if (err != nil) {
		return version, err
	}

	return version, nil
}

// use git to add a tag with a version
func setVersion(version Version) error {
	v := version.toString(false)
	return exec.Command("sh", "-c", "git tag -a " + v + " -m '" + v + "'").Run()
}<|endoftext|>


<commit_before>/*
 * Copyright (c) 2015, Shinya Yagyu
 * All rights reserved.
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 3. Neither the name of the copyright holder nor the names of its
 *    contributors may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

package main

import (
	"flag"
	"log"
	"net/http"
	_ "net/http/pprof"

	"github.com/shinGETsu-gou/shingetsu-gou/gou"
)

//init initialize all variables and logger by arguments
func init() {
	gou.InitVariables()

	var printLog, isSilent bool
	flag.BoolVar(&printLog, "verbose", false, "print logs")
	flag.BoolVar(&printLog, "v", false, "print logs")
	flag.BoolVar(&isSilent, "silent", false, "suppress logs")
	flag.Parse()

	gou.SetLogger(printLog, isSilent)
}

func main() {
	gou.SetupDaemon()
	gou.StartDaemon()
}
<commit_msg>trivial<commit_after>/*
 * Copyright (c) 2015, Shinya Yagyu
 * All rights reserved.
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 3. Neither the name of the copyright holder nor the names of its
 *    contributors may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

package main

import (
	"flag"
	_ "net/http/pprof"

	"github.com/shinGETsu-gou/shingetsu-gou/gou"
)

//init initialize all variables and logger by arguments
func init() {
	gou.InitVariables()

	var printLog, isSilent bool
	flag.BoolVar(&printLog, "verbose", false, "print logs")
	flag.BoolVar(&printLog, "v", false, "print logs")
	flag.BoolVar(&isSilent, "silent", false, "suppress logs")
	flag.Parse()

	gou.SetLogger(printLog, isSilent)
}

func main() {
	gou.SetupDaemon()
	gou.StartDaemon()
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"strings"

	"path/filepath"

	"path"

	"github.com/codegangsta/cli"
)

func remove(c *cli.Context) {
	importPath := c.Args().First()
	if importPath == "" {
		cli.ShowCommandHelp(c, "remove")
		fatalErrorf("No import path given")
	}

	err := removeImport(getAbsoluteCurrentDirOrExit(), importPath, c.Bool("y"))
	if err != nil {
		fatalErrorf("Error removing import : %s", err.Error())
	}
}

func vendor(c *cli.Context) {
	paths := c.Args().Tail()
	if len(paths) == 0 {
		cli.ShowCommandHelp(c, "vendor")
		fatalErrorf("No paths given")
	}

	currentDir := getAbsoluteCurrentDirOrExit()

	files, err := listFiles(paths, c.Bool("r"))
	if err != nil {
		fatalErrorf("Error listing files to scan for imports : %s", err.Error())
	}

	imports, err := extractImports(files)
	if err != nil {
		fatalErrorf("Error scanning imports from files : %s", err.Error())
	}

	for _, importPath := range imports {

		fmt.Print(importPath, " : ")
		err, ok := vendorImport(currentDir, importPath)
		if err != nil {
			fmt.Print("Failed (", err.Error(), ")")
		} else if !ok {
			fmt.Print("Skipped")
		} else {
			fmt.Print("OK")
		}
		fmt.Print("\n")
	}
}

func listFiles(fileNames []string, recursive bool) ([]string, error) {
	files := make([]string, 0, len(fileNames))
	var err error

	for _, fileName := range fileNames {
		err = listFile(fileName, &files, recursive, true)
		if err != nil {
			return nil, err
		}
	}
	return files, nil
}

func listFile(filename string, list *[]string, recursiveScanning, firstLevel bool) error {
	fileInfo, err := os.Stat(filename)
	if err != nil {
		err = fmt.Errorf("Error with file %q : %q\n", filename, err.Error())
		return err
	}
	if fileInfo.IsDir() {
		if recursiveScanning || firstLevel {
			fileInfos, err := ioutil.ReadDir(filename)
			if err != nil {
				return err
			}
			for _, fileInfo = range fileInfos {
				if strings.HasSuffix(fileInfo.Name(), ".go") {
					err = listFile(fileInfo.Name(), list, recursiveScanning, false)
					if err != nil {
						return err
					}
				}
			}
		}
	} else {
		*list = append(*list, filename)
	}
	return nil
}

func getAbsoluteCurrentDirOrExit() string {
	currentDir, err := filepath.Abs(path.Dir(os.Args[0]))
	if err != nil {
		fatalErrorf("Error getting current absolute path : %s", err.Error())
	}
	return currentDir
}
<commit_msg>Fix recursive scanning<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"strings"

	"path/filepath"

	"path"

	"github.com/codegangsta/cli"
)

func remove(c *cli.Context) {
	importPath := c.Args().First()
	if importPath == "" {
		cli.ShowCommandHelp(c, "remove")
		fatalErrorf("No import path given")
	}

	err := removeImport(getAbsoluteCurrentDirOrExit(), importPath, c.Bool("y"))
	if err != nil {
		fatalErrorf("Error removing import : %s", err.Error())
	}
}

func vendor(c *cli.Context) {
	paths := c.Args().Tail()
	if len(paths) == 0 {
		cli.ShowCommandHelp(c, "vendor")
		fatalErrorf("No paths given")
	}

	currentDir := getAbsoluteCurrentDirOrExit()

	files, err := listFiles(paths, c.Bool("r"))
	if err != nil {
		fatalErrorf("Error listing files to scan for imports : %s", err.Error())
	}

	imports, err := extractImports(files)
	if err != nil {
		fatalErrorf("Error scanning imports from files : %s", err.Error())
	}

	for _, importPath := range imports {

		fmt.Print(importPath, " : ")
		err, ok := vendorImport(currentDir, importPath)
		if err != nil {
			fmt.Print("Failed (", err.Error(), ")")
		} else if !ok {
			fmt.Print("Skipped")
		} else {
			fmt.Print("OK")
		}
		fmt.Print("\n")
	}
}

func listFiles(fileNames []string, recursive bool) ([]string, error) {
	files := make([]string, 0, len(fileNames))
	var err error

	for _, fileName := range fileNames {
		err = listFile(fileName, &files, recursive, "")
		if err != nil {
			return nil, err
		}
	}
	return files, nil
}

func listFile(filename string, list *[]string, recursiveScanning bool, currentPath string) error {
	fullPath := path.Join(currentPath, filename)
	fileInfo, err := os.Stat(fullPath)
	if err != nil {
		err = fmt.Errorf("Error with file %q : %q\n", filename, err.Error())
		return err
	}
	if fileInfo.IsDir() {
		if recursiveScanning || currentPath == "" {
			fileInfos, err := ioutil.ReadDir(filename)
			if err != nil {
				return err
			}
			for _, fileInfo = range fileInfos {
				if strings.HasSuffix(fileInfo.Name(), ".go") {
					err = listFile(fileInfo.Name(), list, recursiveScanning, fullPath)
					if err != nil {
						return err
					}
				}
			}
		}
	} else {
		*list = append(*list, filename)
	}
	return nil
}

func getAbsoluteCurrentDirOrExit() string {
	currentDir, err := filepath.Abs(path.Dir(os.Args[0]))
	if err != nil {
		fatalErrorf("Error getting current absolute path : %s", err.Error())
	}
	return currentDir
}
<|endoftext|>


<commit_before>package chain

import (
	"math/big"

	"github.com/ethereum/go-ethereum/crypto"
	"github.com/ethereum/go-ethereum/ethutil"
)

/*
 * This is the special genesis block.
 */

var ZeroHash256 = make([]byte, 32)
var ZeroHash160 = make([]byte, 20)
var ZeroHash512 = make([]byte, 64)
var EmptyShaList = crypto.Sha3(ethutil.Encode([]interface{}{}))
var EmptyListRoot = crypto.Sha3(ethutil.Encode(""))

var GenesisHeader = []interface{}{
	// Previous hash (none)
	ZeroHash256,
	// Empty uncles
	EmptyShaList,
	// Coinbase
	ZeroHash160,
	// Root state
	EmptyShaList,
	// tx root
	EmptyListRoot,
	// receipt root
	EmptyListRoot,
	// bloom
	ZeroHash512,
	// Difficulty
	//ethutil.BigPow(2, 22),
	big.NewInt(131072),
	// Number
	ethutil.Big0,
	// Block minimum gas price
	ethutil.Big0,
	// Block upper gas bound
	big.NewInt(1000000),
	// Block gas used
	ethutil.Big0,
	// Time
	ethutil.Big0,
	// Extra
	nil,
	// Nonce
	crypto.Sha3(big.NewInt(42).Bytes()),
}

var Genesis = []interface{}{GenesisHeader, []interface{}{}, []interface{}{}}
<commit_msg>Removed min gas price from genesis<commit_after>package chain

import (
	"math/big"

	"github.com/ethereum/go-ethereum/crypto"
	"github.com/ethereum/go-ethereum/ethutil"
)

/*
 * This is the special genesis block.
 */

var ZeroHash256 = make([]byte, 32)
var ZeroHash160 = make([]byte, 20)
var ZeroHash512 = make([]byte, 64)
var EmptyShaList = crypto.Sha3(ethutil.Encode([]interface{}{}))
var EmptyListRoot = crypto.Sha3(ethutil.Encode(""))

var GenesisHeader = []interface{}{
	// Previous hash (none)
	ZeroHash256,
	// Empty uncles
	EmptyShaList,
	// Coinbase
	ZeroHash160,
	// Root state
	EmptyShaList,
	// tx root
	EmptyListRoot,
	// receipt root
	EmptyListRoot,
	// bloom
	ZeroHash512,
	// Difficulty
	//ethutil.BigPow(2, 22),
	big.NewInt(131072),
	// Number
	ethutil.Big0,
	// Block upper gas bound
	big.NewInt(1000000),
	// Block gas used
	ethutil.Big0,
	// Time
	ethutil.Big0,
	// Extra
	nil,
	// Nonce
	crypto.Sha3(big.NewInt(42).Bytes()),
}

var Genesis = []interface{}{GenesisHeader, []interface{}{}, []interface{}{}}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"strings"

	"github.com/codegangsta/cli"
	"github.com/fatih/color"
	"github.com/google/go-github/github"
	"github.com/hoisie/mustache"
	git "github.com/libgit2/git2go"
	"gopkg.in/yaml.v2"
)

var (
	version        = "0.1"
	suffix         = "-gut-template"
	templateFile   = "gut.template"
	templateConfig configuration
	cwd            string
	name           string
	fullPath       string
)

var (
	boldCyan  *color.Color
	boldWhite *color.Color
)

type configuration struct {
	Variables map[string]string `yaml:"variables"`
	Options   map[string]string `yaml:"options"`
	Commands  [][]string        `yaml:"commands"`
}

func main() {
	boldCyan = color.New(color.FgCyan).Add(color.Bold)
	boldWhite = color.New(color.FgWhite).Add(color.Bold)

	cwd, _ = filepath.Abs(filepath.Dir(os.Args[0]))

	app := cli.NewApp()
	app.Name = "gut"
	app.Usage = "make an explosive entrance"

	app.Commands = []cli.Command{
		{
			Name:    "search",
			Aliases: []string{"s"},
			Usage:   "search templates",
			Action: func(c *cli.Context) {
				filter := c.Args().First()
				search(filter)
			},
		},
		{
			Name:    "new",
			Aliases: []string{"n"},
			Usage:   "new",
			Action: func(c *cli.Context) {
				if len(c.Args()) < 2 {
					fmt.Print("Not enough arguments")
				}
				templateName := c.Args().First()
				name = c.Args()[1]
				new(templateName)
			},
		},
		{
			Name:    "version",
			Aliases: []string{"v"},
			Usage:   "version",
			Action: func(c *cli.Context) {
				fmt.Printf("gut version %s\n", version)
			},
		},
	}

	app.Run(os.Args)
}

func search(filter string) {
	search := filter + suffix
	client := github.NewClient(nil)
	opt := &github.SearchOptions{
		Sort: "stars",
	}

	results, _, error := client.Search.Repositories(search, opt)

	if error != nil {
		log.Fatal(error)
	}

	for _, repository := range results.Repositories {
		repoName := *repository.Name
		repoUsername := *(*repository.Owner).Login
		repoDescription := *repository.Description
		repoStars := *repository.StargazersCount

		print := strings.HasSuffix(repoName, suffix)

		if print {
			repoName = strings.TrimSuffix(repoName, suffix)

			boldCyan.Printf("%s/", repoUsername)
			boldWhite.Printf("%s", repoName)
			fmt.Printf(" (%d)\n", repoStars)
			fmt.Printf("    %s\n", repoDescription)
		}
	}
}

func new(templateName string) {
	repoName := templateName + suffix
	repoURL := "https://github.com/" + repoName + ".git"

	fullPath = path.Join(cwd, name)
	gitopts := &git.CloneOptions{}

	boldWhite.Printf("Retrieving %s via %s\n", templateName, repoURL)
	_, err := git.Clone(repoURL, fullPath, gitopts)

	if err != nil {
		log.Fatal(err)
	} else {
		println()
	}

	config(name, path.Join(fullPath, templateFile))
	askForVariables()
	clean()
	compile()
	commands()
	fmt.Printf("Your %s project was created successfully.\n", templateName)
}

func config(name string, path string) {
	file, _ := ioutil.ReadFile(path)
	err := yaml.Unmarshal(file, &templateConfig) //TODO check for erros
	if err != nil {
		log.Fatal(err)
	}

	templateConfig.Variables["name"] = name
}

func askForVariables() {
	boldWhite.Println("Assign values to variables [default value]")
	for key, defaultValue := range templateConfig.Variables {
		if key != "name" {
			fmt.Printf("%s [%s]: ", key, defaultValue)

			input := ""
			fmt.Scanln(&input)

			if input != "" {
				templateConfig.Variables[key] = input
			} else {
				templateConfig.Variables[key] = defaultValue
			}
		}
	}
	println()
}

func clean() {
	os.Remove(path.Join(fullPath, templateFile))
	os.RemoveAll(path.Join(fullPath, ".git/"))
	os.Remove(path.Join(fullPath, ".gitignore"))
}

func compile() {
	boldWhite.Printf("Generating fresh 'gut new' %s project:\n", templateConfig.Variables["name"])
	filepath.Walk(fullPath, compileDirs)
	filepath.Walk(fullPath, compileFiles)
	println()
}

func compileDirs(fullPath string, f os.FileInfo, err error) error {
	if f.IsDir() {
		newPath := mustache.Render(fullPath, templateConfig.Variables)
		os.Remove(fullPath)
		os.Mkdir(newPath, f.Mode())
		printCreating(newPath)
	}

	return nil
}

func printCreating(path string) {
	relativePath, err := filepath.Rel(cwd, path)

	if err != nil {
		log.Fatal(err)
	}

	color.New(color.FgGreen).Print("* creating")
	fmt.Printf(" %s\n", relativePath)
}

func compileFiles(fullPath string, f os.FileInfo, err error) error {
	if !f.IsDir() {
		newPath := mustache.Render(fullPath, templateConfig.Variables)
		rendered := mustache.RenderFile(fullPath, templateConfig.Variables)

		os.Remove(fullPath)
		ioutil.WriteFile(newPath, []byte(rendered), f.Mode())

		printCreating(newPath)
	}

	return nil
}

func commands() {
	boldWhite.Println("Commands:")

	for n, v := range templateConfig.Commands {
		command := v[0]
		arguments := v[1:len(v)]

		fmt.Printf("%d. ", n+1)
		printCommand(command, arguments)
		println()
	}

	println()
	boldWhite.Printf("Do you want to run this commands? [N/y] ")
	input := ""
	fmt.Scanln(&input)

	if input == "y" || input == "Y" {
		for _, v := range templateConfig.Commands {
			cmdString := v[0]
			arguments := v[1:len(v)]

			color.New(color.FgGreen).Print("* running ")
			printCommand(cmdString, arguments)
			println()

			command := exec.Command(cmdString, arguments...)
			command.Dir = fullPath

			out, err := command.Output()
			if err != nil {
				log.Fatal(err)
			} else if string(out) != "" {
				fmt.Printf("> %s", out)
			}
		}
	}
	println()
}

func printCommand(command string, arguments []string) {
	fmt.Printf("%s", command)
	for _, argument := range arguments {
		fmt.Printf(" %s", argument)
	}
}

// inmediate tasks:
// add curl command in readme like docker compose has. generate gox builds
// work on temporary directory? if yes, then use os tempdir function. think if this is useful
// check that gut.template is present
// support templates that remove the cloned folder using the delete folder option
// commands not be inside of an array in gut.template
// name in the string should not have a / slash. if it has, we should only use the first
// add describe template subcommand
// clone templates with depth one
// option to specify tag or commit id of generator
// add homebrew formulas
// add documentation in the readme
// add version in gut help
// store templates in /home/.gut/templates/. only fetch if template not found in that path
// update stored templates
// paginate to get all answers
// add subcommand to compile current working dir. useful for developing templates
// add option to fill variables from a file
<commit_msg>Add new checks<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"strings"

	"github.com/codegangsta/cli"
	"github.com/fatih/color"
	"github.com/google/go-github/github"
	"github.com/hoisie/mustache"
	git "github.com/libgit2/git2go"
	"gopkg.in/yaml.v2"
)

var (
	version        = "0.1"
	suffix         = "-gut-template"
	templateFile   = "gut.template"
	templateConfig configuration
	cwd            string
	name           string
	fullPath       string
)

var (
	boldCyan  *color.Color
	boldWhite *color.Color
)

type configuration struct {
	Variables map[string]string `yaml:"variables"`
	Options   map[string]string `yaml:"options"`
	Commands  [][]string        `yaml:"commands"`
}

func main() {
	boldCyan = color.New(color.FgCyan).Add(color.Bold)
	boldWhite = color.New(color.FgWhite).Add(color.Bold)

	cwd, _ = filepath.Abs(filepath.Dir(os.Args[0]))

	app := cli.NewApp()
	app.Name = "gut"
	app.Usage = "tool that retrieves templates and compile them to scaffold projects and create standalone files"
	app.Version = version
	app.Author = "Federico Carrone"
	app.Email = "federico.carrone@gmail.com"

	app.Commands = []cli.Command{
		{
			Name:    "search",
			Aliases: []string{"s"},
			Usage:   "search templates",
			Action: func(c *cli.Context) {
				filter := c.Args().First()
				search(filter)
			},
		},
		{
			Name:    "new",
			Aliases: []string{"n"},
			Usage:   "new",
			Action: func(c *cli.Context) {
				if len(c.Args()) < 2 {
					fmt.Print("Not enough arguments")
				}
				templateName := c.Args().First()
				name = c.Args()[1]
				new(templateName)
			},
		},
		{
			Name:    "version",
			Aliases: []string{"v"},
			Usage:   "version",
			Action: func(c *cli.Context) {
				fmt.Printf("gut version %s\n", version)
			},
		},
	}

	app.Run(os.Args)
}

func search(filter string) {
	search := filter + suffix
	client := github.NewClient(nil)
	opt := &github.SearchOptions{
		Sort: "stars",
	}

	results, _, error := client.Search.Repositories(search, opt)

	if error != nil {
		log.Fatal(error)
	}

	for _, repository := range results.Repositories {
		repoName := *repository.Name
		repoUsername := *(*repository.Owner).Login
		repoDescription := *repository.Description
		repoStars := *repository.StargazersCount

		print := strings.HasSuffix(repoName, suffix)

		if print {
			repoName = strings.TrimSuffix(repoName, suffix)

			boldCyan.Printf("%s/", repoUsername)
			boldWhite.Printf("%s", repoName)
			fmt.Printf(" (%d)\n", repoStars)
			fmt.Printf("    %s\n", repoDescription)
		}
	}
}

func new(templateName string) {
	repoName := templateName + suffix
	repoURL := "https://github.com/" + repoName + ".git"

	fullPath = path.Join(cwd, name)
	gitopts := &git.CloneOptions{}

	boldWhite.Printf("Retrieving %s via %s\n", templateName, repoURL)
	_, err := git.Clone(repoURL, fullPath, gitopts)

	if err != nil {
		log.Fatal(err)
	} else {
		println()
	}

	config(name, path.Join(fullPath, templateFile))
	askForVariables()
	clean()
	compile()
	commands()
	fmt.Printf("Your %s project was created successfully.\n", templateName)
}

func config(name string, configPath string) {
	configFile, errFile := ioutil.ReadFile(configPath)

	if errFile != nil {
		log.Fatal("Configuration file not present inside template\nError: ", errFile)
	}

	errYaml := yaml.Unmarshal(configFile, &templateConfig)
	if errYaml != nil {
		log.Fatal(errYaml)
	}

	templateConfig.Variables["name"] = name
}

func askForVariables() {
	boldWhite.Println("Assign values to variables [default value]")
	for key, defaultValue := range templateConfig.Variables {
		if key != "name" {
			fmt.Printf("%s [%s]: ", key, defaultValue)

			input := ""
			fmt.Scanln(&input)

			if input != "" {
				templateConfig.Variables[key] = input
			} else {
				templateConfig.Variables[key] = defaultValue
			}
		}
	}
	println()
}

func clean() {
	os.Remove(path.Join(fullPath, templateFile))
	os.RemoveAll(path.Join(fullPath, ".git/"))
	os.Remove(path.Join(fullPath, ".gitignore"))
}

func compile() {
	boldWhite.Printf("Generating fresh 'gut new' %s project:\n", templateConfig.Variables["name"])
	filepath.Walk(fullPath, compileDirs)
	filepath.Walk(fullPath, compileFiles)
	println()
}

func compileDirs(fullPath string, f os.FileInfo, err error) error {
	if f.IsDir() {
		newPath := mustache.Render(fullPath, templateConfig.Variables)
		os.Remove(fullPath)
		os.Mkdir(newPath, f.Mode())
		printCreating(newPath)
	}

	return nil
}

func printCreating(path string) {
	relativePath, err := filepath.Rel(cwd, path)

	if err != nil {
		log.Fatal(err)
	}

	color.New(color.FgGreen).Print("* creating")
	fmt.Printf(" %s\n", relativePath)
}

func compileFiles(fullPath string, f os.FileInfo, err error) error {
	if !f.IsDir() {
		newPath := mustache.Render(fullPath, templateConfig.Variables)
		rendered := mustache.RenderFile(fullPath, templateConfig.Variables)

		os.Remove(fullPath)
		ioutil.WriteFile(newPath, []byte(rendered), f.Mode())

		printCreating(newPath)
	}

	return nil
}

func commands() {
	boldWhite.Printf("Template wants to run the following commands with path=%s:\n", fullPath)

	for n, v := range templateConfig.Commands {
		command := v[0]
		arguments := v[1:len(v)]

		fmt.Printf("%d. ", n+1)
		printCommand(command, arguments)
		println()
	}

	println()
	boldWhite.Printf("Do you want to run this commands? [N/y] ")
	input := ""
	fmt.Scanln(&input)

	if input == "y" || input == "Y" {
		for _, v := range templateConfig.Commands {
			cmdString := v[0]
			arguments := v[1:len(v)]

			color.New(color.FgGreen).Print("* running ")
			printCommand(cmdString, arguments)
			println()

			command := exec.Command(cmdString, arguments...)
			command.Dir = fullPath

			out, err := command.Output()
			if err != nil {
				log.Fatal(err)
			} else if string(out) != "" {
				fmt.Printf("> %s", out)
			}
		}
	}
	println()
}

func printCommand(command string, arguments []string) {
	fmt.Printf("%s", command)
	for _, argument := range arguments {
		fmt.Printf(" %s", argument)
	}
}

// inmediate tasks:
// commands can be optional
// compile commands with variables
// name in the string should not have a / slash. if it has, we should only use the first
// add describe template subcommand

// commands should not be inside of an array in gut.template
// add curl command in readme like docker compose has. generate gox builds

// support templates that remove the cloned folder using the delete folder option
// work on temporary directory? if yes, then use os tempdir function. think if this is useful

// clone templates with depth one
// option to specify tag or commit id of generator
// add homebrew formulas
// add documentation in the readme
// store templates in /home/.gut/templates/. only fetch if template not found in that path
// update stored templates
// paginate to get all answers
// add subcommand to compile current working dir. useful for developing templates
// add option to fill variables from a file
<|endoftext|>


<commit_before>package main

import (
	"crypto/tls"
	"flag"
	"fmt"
	"io"
	"log"
	"net"
	"os"
)

const VERSION = "v1.0.0"

var logger = log.New(os.Stderr, "", 0)

type OriginConfig struct {
	Addr   string
	Direct bool
}

func main() {
	port := flag.String("p", "443", "")
	ip := flag.String("i", "127.0.0.1", "")
	originPort := flag.String("P", "", "")
	originHost := flag.String("H", "", "")
	originDirect := flag.Bool("D", false, "")
	certPath := flag.String("c", "", "")
	keyPath := flag.String("k", "", "")
	outputLogFormat := flag.String("o", "default", "")
	version := flag.Bool("version", false, "")

	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %s [OPTIONS]\n\n", os.Args[0])
		fmt.Println("Options:")
		fmt.Println("  -p:        Port (Default: 443)")
		fmt.Println("  -i:        IP Address (Default: 127.0.0.1)")
		fmt.Println("  -P:        Origin port")
		fmt.Println("  -H:        Origin host")
		fmt.Println("  -D:        Use HTTP/2 direct mode to connect origin")
		fmt.Println("  -c:        Certificate file")
		fmt.Println("  -k:        Certificate key file")
		fmt.Println("  -o:        Output log format (default or json, Default: default)")
		fmt.Println("  --version: Display version information and exit.")
		fmt.Println("  --help:    Display this help and exit.")
		os.Exit(1)
	}

	flag.Parse()

	if *version {
		logger.Printf("h2a %s\n", VERSION)
		os.Exit(0)
	}

	addr := net.JoinHostPort(*ip, *port)

	if *originPort == "" {
		logger.Fatalln("Origin port is not specified")
	}
	if *originHost == "" {
		logger.Fatalln("Origin host is not specified")
	}
	originConfig := OriginConfig{
		Addr:   net.JoinHostPort(*originHost, *originPort),
		Direct: *originDirect,
	}

	var formatter Formatter
	if *outputLogFormat == "json" {
		formatter = JSONFormatter
	} else {
		formatter = DefaultFormatter
	}

	cert, err := tls.LoadX509KeyPair(*certPath, *keyPath)
	if err != nil {
		logger.Fatalln("Invalid certificate file")
	}

	config := &tls.Config{}
	config.Certificates = []tls.Certificate{cert}
	config.NextProtos = append(config.NextProtos, "h2", "h2-16", "h2-15", "h2-14", "http/1.1")

	server, err := tls.Listen("tcp", addr, config)
	if err != nil {
		logger.Fatalf("Could not bind address - %s\n", addr)
	}

	defer server.Close()

	for {
		remoteConn, err := server.Accept()
		if err != nil {
			logger.Printf("Unable to accept: %s", err)
			continue
		}

		go handlePeer(remoteConn, originConfig, formatter)
	}
}

func handlePeer(remoteConn net.Conn, originConfig OriginConfig, formatter Formatter) {
	var originConn net.Conn
	var err error
	h2 := true

	defer remoteConn.Close()

	dumper := NewFrameDumper(remoteConn.RemoteAddr(), formatter)
	defer dumper.Close()

	remoteCh, remoteErrCh := handleConnection(remoteConn)

	select {
	case chunk := <-remoteCh:
		connState := remoteConn.(*tls.Conn).ConnectionState()

		if connState.NegotiatedProtocol == "" {
			connState.NegotiatedProtocol = "http/1.1"
		}
		if connState.NegotiatedProtocol == "http/1.1" {
			h2 = true
		}

		dumper.DumpConnectionState(connState)

		config := &tls.Config{}
		config.CipherSuites = []uint16{connState.CipherSuite}
		config.ServerName = connState.ServerName
		config.InsecureSkipVerify = true
		config.NextProtos = append(config.NextProtos, connState.NegotiatedProtocol)

		if originConfig.Direct {
			originConn, err = net.Dial("tcp", originConfig.Addr)
		} else {
			originConn, err = tls.Dial("tcp", originConfig.Addr, config)
		}
		if err != nil {
			logger.Printf("Unable to connect to the origin: %s", err)
			return
		}

		defer originConn.Close()

		_, err = originConn.Write(chunk)
		if err != nil {
			logger.Printf("Unable to write data to the origin: %s", err)
			return
		}

		if h2 {
			dumper.DumpFrame(chunk, true)
		}

	case err := <-remoteErrCh:
		if err != io.EOF {
			logger.Printf("Connection error: %s", err)
		}
		return
	}

	originCh, originErrCh := handleConnection(originConn)

	for {
		select {
		case chunk := <-remoteCh:
			_, err := originConn.Write(chunk)
			if err != nil {
				logger.Printf("Unable to write data to the origin: %s", err)
				return
			}

			if h2 {
				dumper.DumpFrame(chunk, true)
			}

		case err := <-remoteErrCh:
			if err != io.EOF {
				logger.Printf("Connection error: %s", err)
			}
			return

		case chunk := <-originCh:
			_, err := remoteConn.Write(chunk)
			if err != nil {
				logger.Printf("Unable to write data to the connection: %s", err)
				return
			}

			if h2 {
				dumper.DumpFrame(chunk, false)
			}

		case err := <-originErrCh:
			if err != io.EOF {
				logger.Printf("Origin error: %s", err)
			}
			return
		}
	}
}

func handleConnection(conn net.Conn) (<-chan []byte, <-chan error) {
	dataCh := make(chan []byte)
	errCh := make(chan error, 1)

	go func() {
		for {
			buf := make([]byte, 16384)

			n, err := conn.Read(buf)
			if err != nil {
				errCh <- err
				break
			}

			dataCh <- buf[:n]
		}
	}()

	return dataCh, errCh
}
<commit_msg>Add -d option to support HTTP/2 direct mode<commit_after>package main

import (
	"crypto/tls"
	"flag"
	"fmt"
	"io"
	"log"
	"net"
	"os"
)

const VERSION = "v1.0.0"

var logger = log.New(os.Stderr, "", 0)

type OriginConfig struct {
	Addr   string
	Direct bool
}

func main() {
	port := flag.String("p", "443", "")
	ip := flag.String("i", "127.0.0.1", "")
	direct := flag.Bool("d", false, "")
	originPort := flag.String("P", "", "")
	originHost := flag.String("H", "", "")
	originDirect := flag.Bool("D", false, "")
	certPath := flag.String("c", "", "")
	keyPath := flag.String("k", "", "")
	outputLogFormat := flag.String("o", "default", "")
	version := flag.Bool("version", false, "")

	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %s [OPTIONS]\n\n", os.Args[0])
		fmt.Println("Options:")
		fmt.Println("  -p:        Port (Default: 443)")
		fmt.Println("  -i:        IP Address (Default: 127.0.0.1)")
		fmt.Println("  -d:        Use HTTP/2 direct mode")
		fmt.Println("  -P:        Origin port")
		fmt.Println("  -H:        Origin host")
		fmt.Println("  -D:        Use HTTP/2 direct mode to connect origin")
		fmt.Println("  -c:        Certificate file")
		fmt.Println("  -k:        Certificate key file")
		fmt.Println("  -o:        Output log format (default or json, Default: default)")
		fmt.Println("  --version: Display version information and exit.")
		fmt.Println("  --help:    Display this help and exit.")
		os.Exit(1)
	}

	flag.Parse()

	if *version {
		logger.Printf("h2a %s\n", VERSION)
		os.Exit(0)
	}

	addr := net.JoinHostPort(*ip, *port)

	if *originPort == "" {
		logger.Fatalln("Origin port is not specified")
	}
	if *originHost == "" {
		logger.Fatalln("Origin host is not specified")
	}
	originConfig := OriginConfig{
		Addr:   net.JoinHostPort(*originHost, *originPort),
		Direct: *originDirect,
	}

	var formatter Formatter
	if *outputLogFormat == "json" {
		formatter = JSONFormatter
	} else {
		formatter = DefaultFormatter
	}

	var server net.Listener
	var err error
	if *direct {
		server, err = net.Listen("tcp", addr)
	} else {
		cert, err := tls.LoadX509KeyPair(*certPath, *keyPath)
		if err != nil {
			logger.Fatalln("Invalid certificate file")
		}

		config := &tls.Config{}
		config.Certificates = []tls.Certificate{cert}
		config.NextProtos = append(config.NextProtos, "h2", "h2-16", "h2-15", "h2-14", "http/1.1")

		server, err = tls.Listen("tcp", addr, config)
	}

	if err != nil {
		logger.Fatalf("Could not bind address - %s\n", addr)
	}

	defer server.Close()

	for {
		remoteConn, err := server.Accept()
		if err != nil {
			logger.Printf("Unable to accept: %s", err)
			continue
		}

		go handlePeer(remoteConn, originConfig, formatter)
	}
}

func handlePeer(remoteConn net.Conn, originConfig OriginConfig, formatter Formatter) {
	var originConn net.Conn
	var err error
	h2 := true
	_, useTls := remoteConn.(*tls.Conn)

	defer remoteConn.Close()

	dumper := NewFrameDumper(remoteConn.RemoteAddr(), formatter)
	defer dumper.Close()

	remoteCh, remoteErrCh := handleConnection(remoteConn)

	select {
	case chunk := <-remoteCh:
		var connState tls.ConnectionState

		if useTls {
			connState = remoteConn.(*tls.Conn).ConnectionState()

			if connState.NegotiatedProtocol == "" {
				connState.NegotiatedProtocol = "http/1.1"
			}
			if connState.NegotiatedProtocol == "http/1.1" {
				h2 = true
			}

			dumper.DumpConnectionState(connState)
		}

		if originConfig.Direct {
			originConn, err = net.Dial("tcp", originConfig.Addr)
		} else {
			config := &tls.Config{}
			if useTls {
				config.CipherSuites = []uint16{connState.CipherSuite}
				config.ServerName = connState.ServerName
			}
			config.InsecureSkipVerify = true
			config.NextProtos = append(config.NextProtos, connState.NegotiatedProtocol)

			originConn, err = tls.Dial("tcp", originConfig.Addr, config)
		}
		if err != nil {
			logger.Printf("Unable to connect to the origin: %s", err)
			return
		}

		defer originConn.Close()

		_, err = originConn.Write(chunk)
		if err != nil {
			logger.Printf("Unable to write data to the origin: %s", err)
			return
		}

		if h2 {
			dumper.DumpFrame(chunk, true)
		}

	case err := <-remoteErrCh:
		if err != io.EOF {
			logger.Printf("Connection error: %s", err)
		}
		return
	}

	originCh, originErrCh := handleConnection(originConn)

	for {
		select {
		case chunk := <-remoteCh:
			_, err := originConn.Write(chunk)
			if err != nil {
				logger.Printf("Unable to write data to the origin: %s", err)
				return
			}

			if h2 {
				dumper.DumpFrame(chunk, true)
			}

		case err := <-remoteErrCh:
			if err != io.EOF {
				logger.Printf("Connection error: %s", err)
			}
			return

		case chunk := <-originCh:
			_, err := remoteConn.Write(chunk)
			if err != nil {
				logger.Printf("Unable to write data to the connection: %s", err)
				return
			}

			if h2 {
				dumper.DumpFrame(chunk, false)
			}

		case err := <-originErrCh:
			if err != io.EOF {
				logger.Printf("Origin error: %s", err)
			}
			return
		}
	}
}

func handleConnection(conn net.Conn) (<-chan []byte, <-chan error) {
	dataCh := make(chan []byte)
	errCh := make(chan error, 1)

	go func() {
		for {
			buf := make([]byte, 16384)

			n, err := conn.Read(buf)
			if err != nil {
				errCh <- err
				break
			}

			dataCh <- buf[:n]
		}
	}()

	return dataCh, errCh
}
<|endoftext|>


<commit_before>// Copyright 2017 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 main

import (
	"flag"

	"github.com/golang/dep"
)

const pruneShortHelp = `Prune was merged into ensure. Use ensure instead.`
const pruneLongHelp = `
Prune was merged into the ensure command.
Set prune options in the manifest and it will be applied after every ensure.
`

type pruneCommand struct{}

func (cmd *pruneCommand) Name() string      { return "prune" }
func (cmd *pruneCommand) Args() string      { return "" }
func (cmd *pruneCommand) ShortHelp() string { return pruneShortHelp }
func (cmd *pruneCommand) LongHelp() string  { return pruneLongHelp }
func (cmd *pruneCommand) Hidden() bool      { return true }

func (cmd *pruneCommand) Register(fs *flag.FlagSet) {}

func (cmd *pruneCommand) Run(ctx *dep.Ctx, args []string) error {
	ctx.Out.Printf("Prune was merged into ensure.\n")
	ctx.Out.Printf("Set prune settings in %s and it it will be applied when running ensure.\n", dep.ManifestName)

	return nil
}
<commit_msg>prune: Tweak help and output wording a bit<commit_after>// Copyright 2017 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 main

import (
	"flag"

	"github.com/golang/dep"
)

const pruneShortHelp = `Pruning is now performed automatically by dep ensure.`
const pruneLongHelp = `
Prune was merged into the ensure command.
Set prune options in the manifest and it will be applied after every ensure.
dep prune will be removed in a future version of dep, causing this command to exit non-0.
`

type pruneCommand struct{}

func (cmd *pruneCommand) Name() string      { return "prune" }
func (cmd *pruneCommand) Args() string      { return "" }
func (cmd *pruneCommand) ShortHelp() string { return pruneShortHelp }
func (cmd *pruneCommand) LongHelp() string  { return pruneLongHelp }
func (cmd *pruneCommand) Hidden() bool      { return true }

func (cmd *pruneCommand) Register(fs *flag.FlagSet) {}

func (cmd *pruneCommand) Run(ctx *dep.Ctx, args []string) error {
	ctx.Out.Printf("Pruning is now performed automatically by dep ensure.\n")
	ctx.Out.Printf("Set prune settings in %s and it it will be applied when running ensure.\n", dep.ManifestName)
	ctx.Out.Printf("\ndep prune will be removed in a future version, and this command will exit non-0.\nPlease update your scripts.\n")

	return nil
}
<|endoftext|>