<commit_before>/*
The MIT License (MIT)

transfer.sh was originally written by and
Copyright (c) 2014 DutchCoders [https://github.com/dutchcoders/]

Some modifications
Copyright (c) 2015 John Ko

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

package main

import (
	"flag"
	"fmt"
	"github.com/PuerkitoBio/ghost/handlers"
	"github.com/gorilla/mux"
	"log"
	"math/rand"
	"net/http"
	"os"
	"time"
)

const SERVER_INFO = "dtfc"
const SERVER_VERSION = "0.0.1"

// we use these commands to reduce the amount of garbage collection golang needs to do
const cmdSHASUMFreeBSD = "/usr/local/bin/shasum"

// or on Apple using Macports
const cmdSHASUMApple = "/opt/local/bin/shasum"
const cmdSHA512 = "/sbin/sha512"
const cmdTAIL = "/usr/bin/tail"

const timeLayout = "2006-01-02 15:04:05 MST"
const timeHTTPLayout = "Mon, 2 Jan 2006 15:04:05 MST"

// parse request with maximum memory of _24Kilobits
const _24K = (1 << 20) * 24

var config struct {
	ALLOWDELETE string
	ALLOWGET    string
	ALLOWPUT    string
	Temp        string
	ME          string
	PEERS       []string
}

var storage Storage

var cmdSHASUM string

func init() {
	config.Temp = os.TempDir()
}

func main() {
	rand.Seed(time.Now().UTC().UnixNano())

	var err error
	if _, err = os.Lstat(cmdSHASUMFreeBSD); err == nil {
		cmdSHASUM = cmdSHASUMFreeBSD
	}
	if _, err = os.Lstat(cmdSHASUMApple); err == nil {
		cmdSHASUM = cmdSHASUMApple
	}
	if _, err = os.Lstat(cmdSHASUM); err != nil {
		log.Panic("Error while looking for shasum executable.")
	}
	if _, err = os.Lstat(cmdTAIL); err != nil {
		log.Panic("Error while looking for tail executable.")
	}

	port := flag.String("port", "8080", "port number, default: 8080")
	temp := flag.String("temp", config.Temp, "")
	basedir := flag.String("basedir", "", "")
	logpath := flag.String("log", "", "")
	provider := flag.String("provider", "local", "")
	allowdelete := flag.String("allowdelete", "true", "true or false, default: true")
	allowget := flag.String("allowget", "true", "true or false, default: true")
	allowput := flag.String("allowput", "true", "true or false, default: true")
	me := flag.String("me", "", "example http://127.0.0.1:8080/")
	melist := flag.String("melist", "", "text file with first line as me")
	peerlist := flag.String("peerlist", "", "text file with one peer per line")

	flag.Parse()

	if *logpath != "" {
		f, err := os.OpenFile(*logpath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
		if err != nil {
			log.Fatalf("Error opening file: %v", err)
		}
		defer f.Close()
		log.SetOutput(f)
	}

	config.Temp = *temp
	config.ALLOWDELETE = *allowdelete
	config.ALLOWGET = *allowget
	config.ALLOWPUT = *allowput
	// usually string empty test is == ""
	// the following test can be nil because *string can be nil
	if me != nil {
		config.ME = *me
	}
	if (config.ME == "") && (melist != nil) {
		var arraystring []string
		arraystring, err = readLines(*melist)
		if err != nil {
			log.Panic("Error while reading melist.", err)
		} else {
			config.ME = arraystring[0]
		}
	}
	if config.ME == "" {
		log.Panic("Error while trying to figure out me.")
	}
	log.Printf("config.ME: %s", config.ME)
	config.PEERS, err = readLines(*peerlist)
	if err != nil {
		log.Panic("Error while reading peerlist.", err)
	}

	r := mux.NewRouter()

	r.HandleFunc("/health.html", healthHandler).Methods("GET")
	r.HandleFunc("/{hash}", getHandler).Methods("GET")

	//r.HandleFunc("/{hash}", headHandler).Methods("HEAD")

	r.HandleFunc("/{filename}", putHandler).Methods("PUT")

	r.NotFoundHandler = http.HandlerFunc(notFoundHandler)

	switch *provider {
	case "local":
		if *basedir == "" {
			log.Panic("Error basedir not set.")
		}
		storage, err = NewLocalStorage(*basedir)
	}
	if err != nil {
		log.Panic("Error while creating storage.", err)
	}

	log.Printf("%s/%s server started. listening on port: %v",
		SERVER_INFO, SERVER_VERSION, *port)
	log.Printf("using temp folder: %s, using storage provider: %s",
		config.Temp, *provider)
	log.Printf("allow delete: %s, allow get: %s, allow put: %s",
		config.ALLOWDELETE, config.ALLOWGET, config.ALLOWPUT)
	log.Printf("---------------------------")

	s := &http.Server{
		Addr:    fmt.Sprintf(":%s", *port),
		Handler: handlers.PanicHandler(RedirectHandler(handlers.LogHandler(r, handlers.NewLogOptions(log.Printf, "_default_"))), nil),
	}

	log.Panic(s.ListenAndServe())
	log.Printf("Server stopped.")
}
<commit_msg>trim config.ME and test if empty<commit_after>/*
The MIT License (MIT)

transfer.sh was originally written by and
Copyright (c) 2014 DutchCoders [https://github.com/dutchcoders/]

Some modifications
Copyright (c) 2015 John Ko

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

package main

import (
	"flag"
	"fmt"
	"github.com/PuerkitoBio/ghost/handlers"
	"github.com/gorilla/mux"
	"log"
	"math/rand"
	"net/http"
	"os"
	"time"
)

const SERVER_INFO = "dtfc"
const SERVER_VERSION = "0.0.1"

// we use these commands to reduce the amount of garbage collection golang needs to do
const cmdSHASUMFreeBSD = "/usr/local/bin/shasum"

// or on Apple using Macports
const cmdSHASUMApple = "/opt/local/bin/shasum"
const cmdSHA512 = "/sbin/sha512"
const cmdTAIL = "/usr/bin/tail"

const timeLayout = "2006-01-02 15:04:05 MST"
const timeHTTPLayout = "Mon, 2 Jan 2006 15:04:05 MST"

// parse request with maximum memory of _24Kilobits
const _24K = (1 << 20) * 24

var config struct {
	ALLOWDELETE string
	ALLOWGET    string
	ALLOWPUT    string
	Temp        string
	ME          string
	PEERS       []string
}

var storage Storage

var cmdSHASUM string

func init() {
	config.Temp = os.TempDir()
}

func main() {
	rand.Seed(time.Now().UTC().UnixNano())

	var err error
	if _, err = os.Lstat(cmdSHASUMFreeBSD); err == nil {
		cmdSHASUM = cmdSHASUMFreeBSD
	}
	if _, err = os.Lstat(cmdSHASUMApple); err == nil {
		cmdSHASUM = cmdSHASUMApple
	}
	if _, err = os.Lstat(cmdSHASUM); err != nil {
		log.Panic("Error while looking for shasum executable.")
	}
	if _, err = os.Lstat(cmdTAIL); err != nil {
		log.Panic("Error while looking for tail executable.")
	}

	port := flag.String("port", "8080", "port number, default: 8080")
	temp := flag.String("temp", config.Temp, "")
	basedir := flag.String("basedir", "", "")
	logpath := flag.String("log", "", "")
	provider := flag.String("provider", "local", "")
	allowdelete := flag.String("allowdelete", "true", "true or false, default: true")
	allowget := flag.String("allowget", "true", "true or false, default: true")
	allowput := flag.String("allowput", "true", "true or false, default: true")
	me := flag.String("me", "", "example http://127.0.0.1:8080/")
	melist := flag.String("melist", "", "text file with first line as me")
	peerlist := flag.String("peerlist", "", "text file with one peer per line")

	flag.Parse()

	if *logpath != "" {
		f, err := os.OpenFile(*logpath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
		if err != nil {
			log.Fatalf("Error opening file: %v", err)
		}
		defer f.Close()
		log.SetOutput(f)
	}

	config.Temp = *temp
	config.ALLOWDELETE = *allowdelete
	config.ALLOWGET = *allowget
	config.ALLOWPUT = *allowput
	// usually string empty test is == ""
	// the following test can be nil because *string can be nil
	if me != nil {
		config.ME = *me
	}
	if (config.ME == "") && (melist != nil) {
		var arraystring []string
		arraystring, err = readLines(*melist)
		if err != nil {
			log.Panic("Error while reading melist.", err)
		} else {
			config.ME = arraystring[0]
		}
	}
	if strings.Trim(config.ME, " ") == "" {
		log.Panic("Error while trying to figure out me.")
	}
	log.Printf("config.ME: %s", config.ME)
	config.PEERS, err = readLines(*peerlist)
	if err != nil {
		log.Panic("Error while reading peerlist.", err)
	}

	r := mux.NewRouter()

	r.HandleFunc("/health.html", healthHandler).Methods("GET")
	r.HandleFunc("/{hash}", getHandler).Methods("GET")

	//r.HandleFunc("/{hash}", headHandler).Methods("HEAD")

	r.HandleFunc("/{filename}", putHandler).Methods("PUT")

	r.NotFoundHandler = http.HandlerFunc(notFoundHandler)

	switch *provider {
	case "local":
		if *basedir == "" {
			log.Panic("Error basedir not set.")
		}
		storage, err = NewLocalStorage(*basedir)
	}
	if err != nil {
		log.Panic("Error while creating storage.", err)
	}

	log.Printf("%s/%s server started. listening on port: %v",
		SERVER_INFO, SERVER_VERSION, *port)
	log.Printf("using temp folder: %s, using storage provider: %s",
		config.Temp, *provider)
	log.Printf("allow delete: %s, allow get: %s, allow put: %s",
		config.ALLOWDELETE, config.ALLOWGET, config.ALLOWPUT)
	log.Printf("---------------------------")

	s := &http.Server{
		Addr:    fmt.Sprintf(":%s", *port),
		Handler: handlers.PanicHandler(RedirectHandler(handlers.LogHandler(r, handlers.NewLogOptions(log.Printf, "_default_"))), nil),
	}

	log.Panic(s.ListenAndServe())
	log.Printf("Server stopped.")
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"strings"
	"net/http"
	"gopkg.in/alecthomas/kingpin.v2"
	"github.com/dghubble/sling"
)

var (
	captureFlag = kingpin.Command("capture", "Set hoverfly to capture mode")
)

func main() {
	switch kingpin.Parse() {
		case "capture":
			captureHandler()
	}
}

func captureHandler() {
	request, _ := sling.New().Post("http://localhost:8888/api/state").Body(strings.NewReader(`{"mode":"capture"}`)).Request()
	response, _ := http.DefaultClient.Do(request)
	defer response.Body.Close()
	fmt.Println(response.Status)
	fmt.Println("I am capturing")
}
<commit_msg>Refactored a little bit ready for more modes.<commit_after>package main

import (
	"fmt"
	"strings"
	"net/http"
	"gopkg.in/alecthomas/kingpin.v2"
	"github.com/dghubble/sling"
)

var (
	captureFlag = kingpin.Command("capture", "Set hoverfly to capture mode")
)

func main() {
	switch kingpin.Parse() {
		case "capture":
			captureHandler()
	}
}

func captureHandler() {
	response := setHoverflyMode("capture")
	defer response.Body.Close()
	fmt.Println("Hoverfly set to capture mode")
}

func setHoverflyMode(mode string) (*http.Response) {
	request, _ := sling.New().Post("http://localhost:8888/api/state").Body(strings.NewReader(`{"mode":"` + mode + `"}`)).Request()
	response, _ := http.DefaultClient.Do(request)
	return response
}
<|endoftext|>


<commit_before>package main

import (
    "log"
    "net/http"
)

func pingServer(w http.ResponseWriter, req *http.Request) {
    w.Write([]byte("ping Drone!"))
}

func main() {
    http.HandleFunc("/", pingServer)
    err := http.ListenAndServe(":8080", nil)
    if err != nil {
        log.Fatal("ListenAndServe: ", err)
    }
}
<commit_msg>trigger<commit_after>package main

import (
    "log"
    "net/http"
)

func pingServer(w http.ResponseWriter, req *http.Request) {
    w.Write([]byte("Hello Drone!"))
}

func main() {
    http.HandleFunc("/", pingServer)
    err := http.ListenAndServe(":8080", nil)
    if err != nil {
        log.Fatal("ListenAndServe: ", err)
    }
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"os"
	"sort"
	"strings"
)

const VERSION = "0.0.1"

var fset *token.FileSet

func main() {
	if len(os.Args) != 2 {
		printUsage()
		os.Exit(1)
	}

	filename := os.Args[1]

	fset = token.NewFileSet()
	tags := make(sort.StringSlice, 0)

	f, err := parser.ParseFile(fset, filename, nil, 0)
	if err != nil {
		// TODO: fix error handling; it should still result in a valid ctags file
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}

	// header
	tags = append(tags, "!_TAG_FILE_FORMAT\t2\t")
	tags = append(tags, "!_TAG_FILE_SORTED\t1\t")

	// package
	if f.Name != nil {
		tags = append(tags, createTag(f.Name.Name, f.Name.Pos(), "p").String())
	}

	// imports
	for _, im := range f.Imports {
		if im.Path != nil {
			name := strings.Trim(im.Path.Value, "\"")
			tags = append(tags, createTag(name, im.Path.Pos(), "i").String())
		}
	}

	// declarations
	for _, d := range f.Decls {
		switch decl := d.(type) {
		case *ast.FuncDecl:
			tags = append(tags, createFuncTag(decl))
		case *ast.GenDecl:
			for _, s := range decl.Specs {
				if ts, ok := s.(*ast.TypeSpec); ok {
					tags = append(tags, createTag(ts.Name.Name, ts.Pos(), "s").String())
				}
			}
		}
	}

	// sort and print tags
	sort.Sort(tags)
	for _, tag := range tags {
		fmt.Println(tag)
	}
}

func printUsage() {
	fmt.Printf("gotags version %s\n\n", VERSION)
	fmt.Printf("Usage: %s file\n", os.Args[0])
}

func createTag(name string, pos token.Pos, tagtype string) *Tag {
	return NewTag(name, fset.File(pos).Name(), fset.Position(pos).Line, tagtype)
}

func createFuncTag(f *ast.FuncDecl) string {
	if f == nil || f.Name == nil {
		return ""
	}

	tag := createTag(f.Name.Name, f.Pos(), "f")

	// access
	if ast.IsExported(tag.Name) {
		tag.Fields["access"] = "public"
	} else {
		tag.Fields["access"] = "private"
	}

	// signature
	var sig bytes.Buffer
	sig.WriteByte('(')
	for i, param := range f.Type.Params.List {
		// parameter names
		for j, n := range param.Names {
			sig.WriteString(n.Name)
			if j < len(param.Names)-1 {
				sig.WriteString(", ")
			}
		}

		// parameter type
		if t, ok := param.Type.(*ast.Ident); ok {
			sig.WriteByte(' ')
			sig.WriteString(t.Name)
		}

		if i < len(f.Type.Params.List)-1 {
			sig.WriteString(", ")
		}
	}
	sig.WriteByte(')')
	tag.Fields["signature"] = sig.String()

	// TODO: receiver

	return tag.String()
}
<commit_msg>Correctly generate function signatures<commit_after>package main

import (
	"bytes"
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"os"
	"sort"
	"strings"
)

const VERSION = "0.0.1"

var fset *token.FileSet

func main() {
	if len(os.Args) != 2 {
		printUsage()
		os.Exit(1)
	}

	filename := os.Args[1]

	fset = token.NewFileSet()
	tags := make(sort.StringSlice, 0)

	f, err := parser.ParseFile(fset, filename, nil, 0)
	if err != nil {
		// TODO: fix error handling; it should still result in a valid ctags file
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}

	// header
	tags = append(tags, "!_TAG_FILE_FORMAT\t2\t")
	tags = append(tags, "!_TAG_FILE_SORTED\t1\t")

	// package
	if f.Name != nil {
		tags = append(tags, createTag(f.Name.Name, f.Name.Pos(), "p").String())
	}

	// imports
	for _, im := range f.Imports {
		if im.Path != nil {
			name := strings.Trim(im.Path.Value, "\"")
			tags = append(tags, createTag(name, im.Path.Pos(), "i").String())
		}
	}

	// declarations
	for _, d := range f.Decls {
		switch decl := d.(type) {
		case *ast.FuncDecl:
			tags = append(tags, createFuncTag(decl))
		case *ast.GenDecl:
			for _, s := range decl.Specs {
				if ts, ok := s.(*ast.TypeSpec); ok {
					tags = append(tags, createTag(ts.Name.Name, ts.Pos(), "s").String())
				}
			}
		}
	}

	// sort and print tags
	sort.Sort(tags)
	for _, tag := range tags {
		fmt.Println(tag)
	}
}

func printUsage() {
	fmt.Printf("gotags version %s\n\n", VERSION)
	fmt.Printf("Usage: %s file\n", os.Args[0])
}

func createTag(name string, pos token.Pos, tagtype string) *Tag {
	return NewTag(name, fset.File(pos).Name(), fset.Position(pos).Line, tagtype)
}

func createFuncTag(f *ast.FuncDecl) string {
	if f == nil || f.Name == nil {
		return ""
	}

	tag := createTag(f.Name.Name, f.Pos(), "f")

	// access
	if ast.IsExported(tag.Name) {
		tag.Fields["access"] = "public"
	} else {
		tag.Fields["access"] = "private"
	}

	// signature
	var sig bytes.Buffer
	sig.WriteByte('(')
	for i, param := range f.Type.Params.List {
		// parameter names
		for j, n := range param.Names {
			sig.WriteString(n.Name)
			if j < len(param.Names)-1 {
				sig.WriteString(", ")
			}
		}

		// parameter type
		sig.WriteByte(' ')
		sig.WriteString(getParamType(param.Type))

		if i < len(f.Type.Params.List)-1 {
			sig.WriteString(", ")
		}
	}
	sig.WriteByte(')')
	tag.Fields["signature"] = sig.String()

	// TODO: receiver

	return tag.String()
}

func getParamType(node ast.Node) (paramType string) {
	switch t := node.(type) {
	case *ast.Ident:
		paramType = t.Name
	case *ast.StarExpr:
		paramType = "*" + getParamType(t.X)
	case *ast.SelectorExpr:
		paramType = getParamType(t.X) + "." + getParamType(t.Sel)
	}
	return
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/hawx/img/utils"
	"github.com/hawx/hadfield"
	"bytes"
	"path/filepath"
	"os/exec"
	"os"
	"strings"
	"flag"
)

type External struct {
	Path, Usage, Short, Long  string
}

func (e External) String() string {
	return "External{" + e.Path + "}"
}

func (e *External) Name() string {
	return filepath.Base(e.Path)[4:]
}

func (e *External) Data() interface{} {
	return map[string]interface{}{
		"Callable": e.Callable(),
		"Category": e.Category(),
		"Usage":    e.Usage,
		"Short":    e.Short,
		"Long":     e.Long,
		"Name":     e.Name(),
	}
}

func (e *External) Category() string {
	return "External"
}

func (e *External) Callable() bool {
	return true
}

func (e *External) Call(cmd hadfield.Interface, templates hadfield.Templates, args []string) {
	// args[0] is set to the executable's name, so we can safely replace it with
	// the output type. This is always going to be something, so needs to be
	// checked for, removed, and respected!
	args[0] = string(utils.Output)

	ex := exec.Command(e.Path, args...)
	ex.Stdin  = os.Stdin
	ex.Stdout = os.Stdout
	ex.Stderr = os.Stderr
	err := ex.Run()
	if err != nil {
		os.Exit(2)
	}
	return
}

func findExternalsIn(dir string) ([]string, error) {
	found := []string{}

	dirs, _ := filepath.Glob(dir + "/" + "*")
	for _, possible := range dirs {
		if strings.HasPrefix(filepath.Base(possible), "img-") {
			found = append(found, possible)
		}
	}

	return found, nil
}

func runExternal(ext string, flags... string) string {
	cmd := exec.Command(ext, flags...)
	var out bytes.Buffer
	cmd.Stdout = &out
	err := cmd.Run()
	if err != nil {
		// handle
	}
	return out.String()
}

func lookupExternals() hadfield.Commands {
	found := hadfield.Commands{}
	pathenv := os.Getenv("PATH")
	output := string(utils.Output)

	for _, dir := range strings.Split(pathenv, ":") {
		if dir == "" {
			dir = "."
		}

		if exts, err := findExternalsIn(dir); err == nil {
			for _, ext := range exts {
				usage := runExternal(ext, output, "--usage")
				short := runExternal(ext, output, "--short")
				long  := runExternal(ext, output, "--long")

				found = append(found, &External{ext, usage, short, long})
			}
		}
	}

	return found
}

// Commands list the available commands and help topics. The order here is the
// order in which they are printed by 'img help'.
var commands = hadfield.Commands{
	cmdBlend,
	cmdBlur,
	cmdChannel,
	cmdContrast,
	cmdCrop,
	cmdGamma,
	cmdGreyscale,
	cmdHxl,
	cmdLevels,
	cmdPixelate,
	cmdPxl,
	cmdSharpen,
	cmdShuffle,
	cmdTint,
	cmdVxl,
}

var templates = hadfield.Templates{
Usage: `Usage: img [command] [arguments]

	Img is a set of image manipulation tools. They each take an image from STDIN
	and print the result to STDOUT (in some cases they may also require a second
	image, consult the help for the particular command).

	An example usage,

		$ img greyscale < input.png > output.png

	As standard input and output are used throughout, commands can be easily
	chained together using pipes (and parentheses for clarity),

		$ (img greyscale | img pxl | img contrast --by 0.05) < input.png > output.png

	Commands: {{range .}}{{if .Callable}}{{if category . "Command"}}
		{{.Name | printf "%-15s"}} # {{.Short | trim}}{{end}}{{end}}{{end}}

	External Commands: {{range .}}{{if .Callable}}{{if category . "External"}}
		{{.Name | printf "%-15s"}} # {{.Short | trim}}{{end}}{{end}}{{end}}

Use "img help [command]" for more information about a command.
`,
Help: `{{if .Callable}}Usage: img {{.Usage}}
{{end}}{{.Long}}
`,
}

var builtIn = []string{
	"blend", "blur", "channel", "contrast", "crop", "gamma", "greyscale", "hxl",
	"levels", "pixelate", "pxl", "sharpen", "shuffle", "tint", "vxl",
}

func isRunningBuiltin(args []string) bool {
	for _, v := range builtIn {
		if args[0] == v { return true }
	}

	return false
}

func main() {
	var jpeg, png, tiff bool
	flag.BoolVar(&jpeg, "jpg",  false, "")
	flag.BoolVar(&jpeg, "jpeg", false, "")
	flag.BoolVar(&png,  "png",  false, "")
	flag.BoolVar(&tiff, "tiff", false, "")
	flag.BoolVar(&tiff, "tif",  false, "")

	flag.Parse()
	if jpeg { utils.Output = utils.JPEG }
	if png  { utils.Output = utils.PNG }
	if tiff { utils.Output = utils.TIFF }

	if !isRunningBuiltin(flag.Args()) {
		externals := lookupExternals()
		commands = append(commands, externals...)
	}

	hadfield.Run(commands, templates)
}
<commit_msg>Fixed indentation of img help<commit_after>package main

import (
	"github.com/hawx/img/utils"
	"github.com/hawx/hadfield"
	"bytes"
	"path/filepath"
	"os/exec"
	"os"
	"strings"
	"flag"
)

type External struct {
	Path, Usage, Short, Long  string
}

func (e External) String() string {
	return "External{" + e.Path + "}"
}

func (e *External) Name() string {
	return filepath.Base(e.Path)[4:]
}

func (e *External) Data() interface{} {
	return map[string]interface{}{
		"Callable": e.Callable(),
		"Category": e.Category(),
		"Usage":    e.Usage,
		"Short":    e.Short,
		"Long":     e.Long,
		"Name":     e.Name(),
	}
}

func (e *External) Category() string {
	return "External"
}

func (e *External) Callable() bool {
	return true
}

func (e *External) Call(cmd hadfield.Interface, templates hadfield.Templates, args []string) {
	// args[0] is set to the executable's name, so we can safely replace it with
	// the output type. This is always going to be something, so needs to be
	// checked for, removed, and respected!
	args[0] = string(utils.Output)

	ex := exec.Command(e.Path, args...)
	ex.Stdin  = os.Stdin
	ex.Stdout = os.Stdout
	ex.Stderr = os.Stderr
	err := ex.Run()
	if err != nil {
		os.Exit(2)
	}
	return
}

func findExternalsIn(dir string) ([]string, error) {
	found := []string{}

	dirs, _ := filepath.Glob(dir + "/" + "*")
	for _, possible := range dirs {
		if strings.HasPrefix(filepath.Base(possible), "img-") {
			found = append(found, possible)
		}
	}

	return found, nil
}

func runExternal(ext string, flags... string) string {
	cmd := exec.Command(ext, flags...)
	var out bytes.Buffer
	cmd.Stdout = &out
	err := cmd.Run()
	if err != nil {
		// handle
	}
	return out.String()
}

func lookupExternals() hadfield.Commands {
	found := hadfield.Commands{}
	pathenv := os.Getenv("PATH")
	output := string(utils.Output)

	for _, dir := range strings.Split(pathenv, ":") {
		if dir == "" {
			dir = "."
		}

		if exts, err := findExternalsIn(dir); err == nil {
			for _, ext := range exts {
				usage := runExternal(ext, output, "--usage")
				short := runExternal(ext, output, "--short")
				long  := runExternal(ext, output, "--long")

				found = append(found, &External{ext, usage, short, long})
			}
		}
	}

	return found
}

// Commands list the available commands and help topics. The order here is the
// order in which they are printed by 'img help'.
var commands = hadfield.Commands{
	cmdBlend,
	cmdBlur,
	cmdChannel,
	cmdContrast,
	cmdCrop,
	cmdGamma,
	cmdGreyscale,
	cmdHxl,
	cmdLevels,
	cmdPixelate,
	cmdPxl,
	cmdSharpen,
	cmdShuffle,
	cmdTint,
	cmdVxl,
}

var templates = hadfield.Templates{
Usage: `Usage: img [command] [arguments]

  Img is a set of image manipulation tools. They each take an image from STDIN
  and print the result to STDOUT (in some cases they may also require a second
  image, consult the help for the particular command).

  An example usage,

    $ img greyscale < input.png > output.png

  As standard input and output are used throughout, commands can be easily
  chained together using pipes (and parentheses for clarity),

    $ (img greyscale | img pxl | img contrast --by 0.05) < input.png > output.png

  Commands: {{range .}}{{if .Callable}}{{if category . "Command"}}
    {{.Name | printf "%-15s"}} # {{.Short | trim}}{{end}}{{end}}{{end}}

  External Commands: {{range .}}{{if .Callable}}{{if category . "External"}}
    {{.Name | printf "%-15s"}} # {{.Short | trim}}{{end}}{{end}}{{end}}

Use "img help [command]" for more information about a command.
`,
Help: `{{if .Callable}}Usage: img {{.Usage}}
{{end}}{{.Long}}
`,
}

var builtIn = []string{
	"blend", "blur", "channel", "contrast", "crop", "gamma", "greyscale", "hxl",
	"levels", "pixelate", "pxl", "sharpen", "shuffle", "tint", "vxl",
}

func isRunningBuiltin(args []string) bool {
	for _, v := range builtIn {
		if args[0] == v { return true }
	}

	return false
}

func main() {
	var jpeg, png, tiff bool
	flag.BoolVar(&jpeg, "jpg",  false, "")
	flag.BoolVar(&jpeg, "jpeg", false, "")
	flag.BoolVar(&png,  "png",  false, "")
	flag.BoolVar(&tiff, "tiff", false, "")
	flag.BoolVar(&tiff, "tif",  false, "")

	flag.Parse()
	if jpeg { utils.Output = utils.JPEG }
	if png  { utils.Output = utils.PNG }
	if tiff { utils.Output = utils.TIFF }

	if !isRunningBuiltin(flag.Args()) {
		externals := lookupExternals()
		commands = append(commands, externals...)
	}

	hadfield.Run(commands, templates)
}
<|endoftext|>


<commit_before>package main

import (
	"io/ioutil"
	"os"

	"github.com/codegangsta/cli"
	"github.com/juju/loggo"
	"github.com/naoina/toml"
)

var logger = loggo.GetLogger("main")

func main() {
	setupLogging()
	setupCLI()
}

func setupLogging() {
	config := os.Getenv("LEMONCRYPT_LOGGING")
	if config == "" {
		config = "<root>=DEBUG"
	}
	loggo.ConfigureLoggers(config)
	logger.Tracef("logging set up")
}

func setupCLI() {
	app := cli.NewApp()
	app.Name = "lemoncrypt"
	app.Usage = "archive and encrypt the messages in your mailbox"
	app.Version = "0.1"
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:   "config",
			Usage:  "path to your config file",
			EnvVar: "LIMECRYPT_CONFIG",
		},
	}
	ea := &EncryptAction{}
	app.Action = ea.Run
	app.Run(os.Args)
}

// EncryptAction provides the context for the default encrypt action.
type EncryptAction struct {
	ctx  *cli.Context
	cfg  *Config
	conn *IMAPWalker
}

// Config defines the structure of the TOML config file and represents the
// stored values.
type Config struct {
	Server struct {
		Address  string
		Username string
		Password string
	}
}

// Run starts the EncryptAction.
func (a *EncryptAction) Run(ctx *cli.Context) {
	a.ctx = ctx
	err := a.loadConfig()
	if err != nil {
		os.Exit(1)
	}
	err = a.setupServer()
	if err != nil {
		os.Exit(1)
	}

	err = a.process()
	if err != nil {
		os.Exit(1)
	}
	defer a.closeServer()
}

func (a *EncryptAction) loadConfig() error {
	path := a.ctx.String("config")
	if path == "" {
		path = "lemoncrypt.cfg"
	}
	logger.Debugf("trying to load config file %s", path)
	content, err := ioutil.ReadFile(path)
	if err != nil {
		logger.Errorf("failed to read config file: %s", err)
		return err
	}
	a.cfg = &Config{}
	err = toml.Unmarshal(content, a.cfg)
	if err != nil {
		logger.Errorf("unable to parse config file: %s", err)
		return err
	}
	logger.Debugf("config loaded successfully")
	return nil
}

func (a *EncryptAction) setupServer() error {
	a.conn = NewIMAPWalker()
	err := a.conn.Dial(a.cfg.Server.Address)
	if err != nil {
		return err
	}
	return a.conn.Login(a.cfg.Server.Username, a.cfg.Server.Password)
}

func (a *EncryptAction) closeServer() error {
	return a.conn.Close()
}

func (a *EncryptAction) callback(mail []byte) error {
	logger.Infof("callback: %d bytes", len(mail))
	return nil
}

func (a *EncryptAction) process() error {
	return a.conn.Walk("INBOX", a.callback)
}
<commit_msg>main: make source mailbox configurable<commit_after>package main

import (
	"io/ioutil"
	"os"

	"github.com/codegangsta/cli"
	"github.com/juju/loggo"
	"github.com/naoina/toml"
)

var logger = loggo.GetLogger("main")

func main() {
	setupLogging()
	setupCLI()
}

func setupLogging() {
	config := os.Getenv("LEMONCRYPT_LOGGING")
	if config == "" {
		config = "<root>=DEBUG"
	}
	loggo.ConfigureLoggers(config)
	logger.Tracef("logging set up")
}

func setupCLI() {
	app := cli.NewApp()
	app.Name = "lemoncrypt"
	app.Usage = "archive and encrypt the messages in your mailbox"
	app.Version = "0.1"
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:   "config",
			Usage:  "path to your config file",
			EnvVar: "LIMECRYPT_CONFIG",
		},
	}
	ea := &EncryptAction{}
	app.Action = ea.Run
	app.Run(os.Args)
}

// EncryptAction provides the context for the default encrypt action.
type EncryptAction struct {
	ctx  *cli.Context
	cfg  *Config
	conn *IMAPWalker
}

// Config defines the structure of the TOML config file and represents the
// stored values.
type Config struct {
	Server struct {
		Address  string
		Username string
		Password string
	}
	Mailbox struct {
		Source string
		Target string
	}
}

// Run starts the EncryptAction.
func (a *EncryptAction) Run(ctx *cli.Context) {
	a.ctx = ctx
	err := a.loadConfig()
	if err != nil {
		os.Exit(1)
	}
	err = a.setupServer()
	if err != nil {
		os.Exit(1)
	}

	err = a.process()
	if err != nil {
		os.Exit(1)
	}
	defer a.closeServer()
}

func (a *EncryptAction) loadConfig() error {
	path := a.ctx.String("config")
	if path == "" {
		path = "lemoncrypt.cfg"
	}
	logger.Debugf("trying to load config file %s", path)
	content, err := ioutil.ReadFile(path)
	if err != nil {
		logger.Errorf("failed to read config file: %s", err)
		return err
	}
	a.cfg = &Config{}
	err = toml.Unmarshal(content, a.cfg)
	if err != nil {
		logger.Errorf("unable to parse config file: %s", err)
		return err
	}
	logger.Debugf("config loaded successfully")
	return nil
}

func (a *EncryptAction) setupServer() error {
	a.conn = NewIMAPWalker()
	err := a.conn.Dial(a.cfg.Server.Address)
	if err != nil {
		return err
	}
	return a.conn.Login(a.cfg.Server.Username, a.cfg.Server.Password)
}

func (a *EncryptAction) closeServer() error {
	return a.conn.Close()
}

func (a *EncryptAction) callback(mail []byte) error {
	logger.Infof("callback: %d bytes", len(mail))
	return nil
}

func (a *EncryptAction) process() error {
	return a.conn.Walk(a.cfg.Mailbox.Source, a.callback)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"

	"./lexer"
	"./parser"
	"./print"
	"./query"
)

func main() {
	dat, err := ioutil.ReadFile("sample.dtodo")
	if err != nil {
		panic(err)
	}

	todo(string(dat))
}

func todo(src string) {
	tokenChan := make(chan lexer.Token)
	treeChan := make(chan parser.Todo)
	go lexer.Run(tokenChan, &src)
	go parser.Run(treeChan, tokenChan)
	root := <-treeChan
	fmt.Printf("%s\n", print.Stringify(root))

	query.New(root)
	return
}
<commit_msg>Can query todo list on main application.<commit_after>package main

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

	"./lexer"
	"./parser"
	"./print"
	"./query"
)

func main() {
	dat, err := ioutil.ReadFile("sample.dtodo")
	if err != nil {
		panic(err)
	}

	todo(string(dat))
}

func todo(src string) {
	tokenChan := make(chan lexer.Token)
	treeChan := make(chan parser.Todo)
	go lexer.Run(tokenChan, &src)
	go parser.Run(treeChan, tokenChan)
	root := <-treeChan
	fmt.Printf("Input:\n%s\n", print.Stringify(root))

	fmt.Println()

	q := query.New(root)

	in := bufio.NewReader(os.Stdin)
	for {
		fmt.Printf("To do .. (type something): ")
		line, _ := in.ReadString('\n')
		line = strings.Trim(line, "\n")
		if line == "" {
			continue
		}

		todos := q.GetTodo(line)
		if len(todos) == 1 {
			fmt.Printf("Do \"%s\"!\n", todos[0])
		} else {
			fmt.Println("Here are your todo list")
			for _, todo := range todos {
				fmt.Printf(" - %s\n", todo)
			}
		}
	}
	return
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"os/exec"
	"strings"

	"github.com/UniversityRadioYork/bifrost-go"
	"github.com/UniversityRadioYork/bifrost-server/request"
	"github.com/UniversityRadioYork/bifrost-server/tcpserver"
	//"github.com/docopt/docopt-go"
	_ "github.com/lib/pq"
)

var hostport = flag.String("hostport", "localhost:8123", "The host and port on which trackd should listen (host:port).")
var resolver = flag.String("resolver", "resolve", "The two-argument command to which trackids will be sent on stdin.")

func resolve(recordid, trackid string) (out string, err error) {
	cmd := exec.Command(*resolver, recordid, trackid)

	var outb []byte
	outb, err = cmd.Output()
	out = string(outb)

	return
}

func main() {
	flag.Parse()

	sample, serr := resolve("recordid", "trackid")
	if serr != nil {
		log.Fatal(serr)
	}

	log.Printf("example resolve: %s recordid trackid -> %s", *resolver, sample)

	db, err := getDB()
	if err != nil {
		log.Fatal(err)
	}
	defer func() {
		if err := db.Close(); err != nil {
			log.Fatal(err)
		}
	}()

	t := NewTrackDB(db, resolve)

	// TODO(CaptainHayashi): factor this out?
	rtree := bifrost.NewDirectoryResourceNode(
		map[string]bifrost.ResourceNoder{
			"control": bifrost.NewDirectoryResourceNode(
				// TODO: put state here
				map[string]bifrost.ResourceNoder{},
			),
			"tracks": &TrackResourceNode{
				trackdb: t,
			},
		},
	)

	log.Printf("listening on %s", *hostport)
	tcpserver.Serve(request.Map{
		bifrost.RqRead:  handleRead,
		bifrost.RqWrite: handleWrite,
	}, rtree, "trackd", *hostport)
}

type TrackResourceNode struct {
	bifrost.ResourceNode

	trackdb *TrackDB
}

func (r *TrackResourceNode) NRead(prefix, relpath []string) ([]bifrost.Resource, error) {
	// Is this about us, or one of our children?
	if len(relpath) == 0 {
		// TODO(CaptainHayashi): This should be something else.
		// Like, maybe, a Query?
		return bifrost.ToResource(prefix, struct{}{}), nil
	}
	// We're expecting relpath to contain the trackID and nothing else.
	// Bail out if this isn't the case.
	if len(relpath) != 1 {
		return []bifrost.Resource{}, fmt.Errorf("expected only one child, got %q", relpath)
	}
	return r.trackdb.LookupTrack(prefix, relpath[0])
}

func (r *TrackResourceNode) NWrite(_, _ []string, _ bifrost.BifrostType) error {
	// TODO(CaptainHayashi): correct error
	return fmt.Errorf("can't write to trackdb")
}

func (r *TrackResourceNode) NDelete(_, _ []string) error {
	// TODO(CaptainHayashi): correct error
	return fmt.Errorf("can't delete trackdb")
}

func (r *TrackResourceNode) NAdd(_, _ []string, _ bifrost.ResourceNoder) error {
	// TODO(CaptainHayashi): correct error
	return fmt.Errorf("can't add to trackdb")
}

func handleRead(_ chan<- *bifrost.Message, response chan<- *bifrost.Message, args []string, it interface{}) (bool, error) {
	t := it.(bifrost.ResourceNoder)

	// read TAG PATH
	if 2 == len(args) {
		// Reading can never quit the server (we hope).
		res := bifrost.Read(t, args[1])
		// TODO(CaptainHayashi): don't unpack this?
		if res.Status.Code != bifrost.StatusOk {
			return false, fmt.Errorf("fixme: %q", res.Status.String())
		}
		for _, r := range res.Resources {
			response <- r.Message(args[0])
		}

		return false, nil
	}

	return false, fmt.Errorf("FIXME: bad read %q", args)
}

func handleWrite(_ chan<- *bifrost.Message, response chan<- *bifrost.Message, args []string, _ interface{}) (bool, error) {
	// write TAG(ignored) PATH VALUE
	if 3 == len(args) {
		resources := strings.Split(strings.Trim(args[1], "/"), "/")
		if len(resources) == 2 && resources[0] == "control" && resources[1] == "state" {
			if strings.EqualFold(args[2], "Quitting") {
				return true, nil
			}
			return false, fmt.Errorf("FIXME: unknown state %q", args[2])
		}
		return false, fmt.Errorf("FIXME: unknown write %q", resources)
	}

	return false, fmt.Errorf("FIXME: bad write %q", args)
}
<commit_msg>Implement basic, initial state resource node.<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"os/exec"
	"strings"

	"github.com/UniversityRadioYork/bifrost-go"
	"github.com/UniversityRadioYork/bifrost-server/request"
	"github.com/UniversityRadioYork/bifrost-server/tcpserver"
	//"github.com/docopt/docopt-go"
	_ "github.com/lib/pq"
)

var hostport = flag.String("hostport", "localhost:8123", "The host and port on which trackd should listen (host:port).")
var resolver = flag.String("resolver", "resolve", "The two-argument command to which trackids will be sent on stdin.")

func resolve(recordid, trackid string) (out string, err error) {
	cmd := exec.Command(*resolver, recordid, trackid)

	var outb []byte
	outb, err = cmd.Output()
	out = string(outb)

	return
}

func main() {
	flag.Parse()

	sample, serr := resolve("recordid", "trackid")
	if serr != nil {
		log.Fatal(serr)
	}

	log.Printf("example resolve: %s recordid trackid -> %s", *resolver, sample)

	db, err := getDB()
	if err != nil {
		log.Fatal(err)
	}
	defer func() {
		if err := db.Close(); err != nil {
			log.Fatal(err)
		}
	}()

	t := NewTrackDB(db, resolve)

	// TODO(CaptainHayashi): factor this out?
	rtree := bifrost.NewDirectoryResourceNode(
		map[string]bifrost.ResourceNoder{
			"control": bifrost.NewDirectoryResourceNode(
				// TODO: put state here
				map[string]bifrost.ResourceNoder{
					"state": &StateResourceNode{
						state: "running",
						stateChangeFn: func(x string) (string, error) { return "", fmt.Errorf("cannot change state to %q", x) },
					},
				},
			),
			"tracks": &TrackResourceNode{
				trackdb: t,
			},
		},
	)

	log.Printf("listening on %s", *hostport)
	tcpserver.Serve(request.Map{
		bifrost.RqRead:  handleRead,
		bifrost.RqWrite: handleWrite,
	}, rtree, "trackd", *hostport)
}

type StateResourceNode struct {
	bifrost.ResourceNode

	// TODO(CaptainHayashi): tighten this up?
	state string

	// Called when the state is changed to something other than quitting.
	// Passed the new state verbatim -- please use strings.EqualFold etc. to compare.
	// Return (new state, nil) if the state change is allowed; (_, error) otherwise.
	stateChangeFn func(string) (string, error)
}

func (r *StateResourceNode) NRead(prefix, relpath []string) ([]bifrost.Resource, error) {
	// We don't have any children (though eventually enums will be a thing?)
	if len(relpath) != 0 {
		return []bifrost.Resource{}, fmt.Errorf("state has no children, got %q", relpath)
	}

	return bifrost.ToResource(prefix, r.state), nil
}
func (r *StateResourceNode) NWrite(prefix, relpath []string, val bifrost.BifrostType) error {
	log.Printf("trying to set state to %s", val)

	if len(relpath) != 0 {
		return fmt.Errorf("state has no children, got %q", relpath)
	}

	// TODO(CaptainHayashi): support more than strings here?
	st, ok := val.(bifrost.BifrostTypeString)
	if !ok {
		return fmt.Errorf("state must be a string, got %q", val)
	}
	_, s := st.ResourceBody()

	// Quitting is monotonic: once you've quit, you can't unquit.
	if strings.EqualFold(r.state, "quitting") {
		return fmt.Errorf("cannot change state, server is quitting")
	}

	// Don't allow changes from one state to itself.
	if strings.EqualFold(r.state, s) {
		return nil
	}

	// We handle quitting on our own.
	news := "quitting"
	var err error
	if !strings.EqualFold(s, "quitting") {
		news, err = r.stateChangeFn(s)
		if err != nil {
			return err
		}
	}

	r.state = news
	return nil
}

func (r *StateResourceNode) NDelete(prefix, relpath []string) error {
	// Deleting = writing "quitting" by design.
	// Since we can't write to children of a state node, this is sound.
	return r.NWrite(prefix, relpath, bifrost.BifrostTypeString("quitting"))
}

func (r *StateResourceNode) NAdd(_, _ []string, _ bifrost.ResourceNoder) error {
	// TODO(CaptainHayashi): correct error
	return fmt.Errorf("can't add to state")
}

type TrackResourceNode struct {
	bifrost.ResourceNode

	trackdb *TrackDB
}

func (r *TrackResourceNode) NRead(prefix, relpath []string) ([]bifrost.Resource, error) {
	// Is this about us, or one of our children?
	if len(relpath) == 0 {
		// TODO(CaptainHayashi): This should be something else.
		// Like, maybe, a Query?
		return bifrost.ToResource(prefix, struct{}{}), nil
	}
	// We're expecting relpath to contain the trackID and nothing else.
	// Bail out if this isn't the case.
	if len(relpath) != 1 {
		return []bifrost.Resource{}, fmt.Errorf("expected only one child, got %q", relpath)
	}
	return r.trackdb.LookupTrack(prefix, relpath[0])
}

func (r *TrackResourceNode) NWrite(_, _ []string, _ bifrost.BifrostType) error {
	// TODO(CaptainHayashi): correct error
	return fmt.Errorf("can't write to trackdb")
}

func (r *TrackResourceNode) NDelete(_, _ []string) error {
	// TODO(CaptainHayashi): correct error
	return fmt.Errorf("can't delete trackdb")
}

func (r *TrackResourceNode) NAdd(_, _ []string, _ bifrost.ResourceNoder) error {
	// TODO(CaptainHayashi): correct error
	return fmt.Errorf("can't add to trackdb")
}

func handleRead(_ chan<- *bifrost.Message, response chan<- *bifrost.Message, args []string, it interface{}) (bool, error) {
	t := it.(bifrost.ResourceNoder)

	// read TAG PATH
	if 2 == len(args) {
		// Reading can never quit the server (we hope).
		res := bifrost.Read(t, args[1])
		// TODO(CaptainHayashi): don't unpack this?
		if res.Status.Code != bifrost.StatusOk {
			return false, fmt.Errorf("fixme: %q", res.Status.String())
		}
		for _, r := range res.Resources {
			response <- r.Message(args[0])
		}

		return false, nil
	}

	return false, fmt.Errorf("FIXME: bad read %q", args)
}

func handleWrite(_ chan<- *bifrost.Message, response chan<- *bifrost.Message, args []string, it interface{}) (bool, error) {
	t := it.(bifrost.ResourceNoder)

	// write TAG(ignored) PATH VALUE
	if 3 == len(args) {
		// TODO(CaptainHayashi): figuring out if the server has quit is very convoluted at the moment

		res := bifrost.Write(t, args[1], args[2])
		// TODO(CaptainHayashi): don't unpack this (as above)?
		if res.Status.Code != bifrost.StatusOk {
			return false, fmt.Errorf("fixme: %q", res.Status.String())
		}

		// Ugh... please fix this.
		return args[1] == "/control/state" && strings.EqualFold(args[2], "quitting"), nil
	}

	return false, fmt.Errorf("FIXME: bad write %q", args)
}
<|endoftext|>


<commit_before>package main

import (
	"os"

	log "github.com/Sirupsen/logrus"
	"github.com/codegangsta/cli"
)

const version = "0.0.1"

var commands []cli.Command

func init() {
	commands = []cli.Command{}
}

func main() {
	app := cli.NewApp()
	app.Name = "zodiac"
	app.Version = version
	app.Usage = "Simple Docker deployment utility."
	app.Authors = []cli.Author{{"CenturyLink Labs", "clt-labs-futuretech@centurylink.com"}}
	app.Commands = commands
	app.Before = initializeCLI
	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:  "debug",
			Usage: "Enable verbose logging",
		},
	}

	app.Run(os.Args)
}

func initializeCLI(c *cli.Context) error {
	if c.GlobalBool("debug") {
		log.SetLevel(log.DebugLevel)
	}

	return nil
}
<commit_msg>Actually set the initial loglevel.<commit_after>package main

import (
	"os"

	log "github.com/Sirupsen/logrus"
	"github.com/codegangsta/cli"
)

const version = "0.0.1"

var commands []cli.Command

func init() {
	log.SetLevel(log.WarnLevel)
	commands = []cli.Command{}
}

func main() {
	app := cli.NewApp()
	app.Name = "zodiac"
	app.Version = version
	app.Usage = "Simple Docker deployment utility."
	app.Authors = []cli.Author{{"CenturyLink Labs", "clt-labs-futuretech@centurylink.com"}}
	app.Commands = commands
	app.Before = initializeCLI
	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:  "debug",
			Usage: "Enable verbose logging",
		},
	}

	app.Run(os.Args)
}

func initializeCLI(c *cli.Context) error {
	if c.GlobalBool("debug") {
		log.SetLevel(log.DebugLevel)
	}

	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2013 Mathieu Lonjaret.
*/

// Package scgiclient implements the client side of the
// Simple Common Gateway Interface protocol, as described
// at http://python.ca/scgi/protocol.txt
package scgiclient

import (
	"bufio"
	"bytes"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"strconv"
	"strings"
)

// Send sends and scgi request to addr, with
// all the data read from r as the body of the request.
// The received response is returned and the connection
// to addr is closed.
func Send(addr string, r io.Reader) (*Response, error) {
	conn, err := net.Dial("tcp", addr)
	if err != nil {
		return nil, err
	}
	defer conn.Close()
	body, err := ioutil.ReadAll(r)
	if err != nil {
		return nil, err
	}
	req := NewRequest(addr, body)
	req.conn = conn
	if _, err = req.Send(); err != nil {
		return nil, err
	}
	return req.Receive()
}

type Request struct {
	Addr   string
	Header []byte
	Body   []byte
	conn   net.Conn
}

// NewRequest returns a Request ready to be sent with
// Request.Send().
func NewRequest(addr string, body []byte) *Request {
	return &Request{
		Addr:   addr,
		Header: defaultHeader(len(body)),
		Body:   body,
	}
}

// Close closes the connection to r.Addr.
func (r *Request) Close() error {
	return r.conn.Close()
}

// Send sends an scgi message built with
// r.Header and r.Body, to r.Addr. It returns the
// number of bytes sent and an error, if any.
func (r *Request) Send() (int64, error) {
	var err error
	if r.conn == nil {
		r.conn, err = net.Dial("tcp", r.Addr)
		if err != nil {
			return 0, err
		}
	}
	msg := append(netstring(r.Header), r.Body...)
	return io.Copy(r.conn, bytes.NewReader(msg))
}

// Receive reads the response from r.Addr and returns
// it in a Response. The connection to r.Addr must already
// be established.
func (r *Request) Receive() (*Response, error) {
	if r.conn == nil {
		return nil, errors.New("Can not receive on a closed connection")
	}
	return receive(r.conn)
}

type Response struct {
	Header map[string]string
	Body   []byte
	conn   net.Conn
}

// Close closes the connection to r.Addr.
func (r *Response) Close() error {
	return r.conn.Close()
}

func receive(conn net.Conn) (*Response, error) {
	r := bufio.NewReader(conn)
	header := make(map[string]string)
	terminator := string([]byte{13, 10})
	for {
		line, err := r.ReadString('\n')
		if err != nil {
			return nil, err
		}
		line = strings.TrimRight(line, terminator)
		if line == "" {
			break
		}
		keyValue := strings.SplitN(line, ": ", 2)
		if len(keyValue) != 2 {
			return nil, fmt.Errorf("Bogus header line in response: %q", line)
		}
		header[keyValue[0]] = keyValue[1]
	}

	resp := &Response{
		Header: header,
		conn:   conn,
	}
	status, ok := header["Status"]
	if !ok {
		return nil, errors.New("Did not get a status line in response header")
	}
	if status != "200 OK" {
		return resp, fmt.Errorf("Got %v as response status", status)
	}
	var body bytes.Buffer
	if _, err := io.Copy(&body, r); err != nil {
		return nil, fmt.Errorf("Could not read response: %v", err)
	}
	resp.Body = body.Bytes()
	return resp, nil
}

func defaultHeader(bodyLen int) []byte {
	var dh []byte
	defaultHeaderFields["CONTENT_LENGTH"] = strconv.Itoa(bodyLen)
	for k, v := range defaultHeaderFields {
		dh = append(dh, header(k, v)...)
	}
	return dh
}

func header(name, value string) []byte {
	h := append([]byte(name), 0)
	h = append(h, []byte(value)...)
	return append(h, 0)
}

var defaultHeaderFields = map[string]string{
	"CONTENT_LENGTH":  "",
	"SCGI":            "1",
	"REQUEST_METHOD":  "POST",
	"SERVER_PROTOCOL": "HTTP/1.1",
}

const (
	comma = byte(',')
	colon = byte(':')
)

func netstring(s []byte) []byte {
	le := []byte(strconv.Itoa(len(s)))
	ns := append(le, colon)
	ns = append(ns, s...)
	ns = append(ns, comma)
	return ns
}
<commit_msg>allow unix domain sockets<commit_after>/*
Copyright 2013 Mathieu Lonjaret.
*/

// Package scgiclient implements the client side of the
// Simple Common Gateway Interface protocol, as described
// at http://python.ca/scgi/protocol.txt
package scgiclient

import (
	"bufio"
	"bytes"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"os"
	"strconv"
	"strings"
)

// Send sends and scgi request to addr, with
// all the data read from r as the body of the request.
// The received response is returned and the connection
// to addr is closed.
func Send(addr string, r io.Reader) (*Response, error) {
	var conn net.Conn

	fi, err := os.Stat(addr)

	if err == nil && fi.Mode()&os.ModeSocket != 0 {
		conn, err = net.Dial("unix", addr)
	} else {
		conn, err = net.Dial("tcp", addr)
	}
	if err != nil {
		return nil, err
	}
	defer conn.Close()
	body, err := ioutil.ReadAll(r)
	if err != nil {
		return nil, err
	}
	req := NewRequest(addr, body)
	req.conn = conn
	if _, err = req.Send(); err != nil {
		return nil, err
	}
	return req.Receive()
}

type Request struct {
	Addr   string
	Header []byte
	Body   []byte
	conn   net.Conn
}

// NewRequest returns a Request ready to be sent with
// Request.Send().
func NewRequest(addr string, body []byte) *Request {
	return &Request{
		Addr:   addr,
		Header: defaultHeader(len(body)),
		Body:   body,
	}
}

// Close closes the connection to r.Addr.
func (r *Request) Close() error {
	return r.conn.Close()
}

// Send sends an scgi message built with
// r.Header and r.Body, to r.Addr. It returns the
// number of bytes sent and an error, if any.
func (r *Request) Send() (int64, error) {
	var err error
	if r.conn == nil {
		r.conn, err = net.Dial("tcp", r.Addr)
		if err != nil {
			return 0, err
		}
	}
	msg := append(netstring(r.Header), r.Body...)
	return io.Copy(r.conn, bytes.NewReader(msg))
}

// Receive reads the response from r.Addr and returns
// it in a Response. The connection to r.Addr must already
// be established.
func (r *Request) Receive() (*Response, error) {
	if r.conn == nil {
		return nil, errors.New("Can not receive on a closed connection")
	}
	return receive(r.conn)
}

type Response struct {
	Header map[string]string
	Body   []byte
	conn   net.Conn
}

// Close closes the connection to r.Addr.
func (r *Response) Close() error {
	return r.conn.Close()
}

func receive(conn net.Conn) (*Response, error) {
	r := bufio.NewReader(conn)
	header := make(map[string]string)
	terminator := string([]byte{13, 10})
	for {
		line, err := r.ReadString('\n')
		if err != nil {
			return nil, err
		}
		line = strings.TrimRight(line, terminator)
		if line == "" {
			break
		}
		keyValue := strings.SplitN(line, ": ", 2)
		if len(keyValue) != 2 {
			return nil, fmt.Errorf("Bogus header line in response: %q", line)
		}
		header[keyValue[0]] = keyValue[1]
	}

	resp := &Response{
		Header: header,
		conn:   conn,
	}
	status, ok := header["Status"]
	if !ok {
		return nil, errors.New("Did not get a status line in response header")
	}
	if status != "200 OK" {
		return resp, fmt.Errorf("Got %v as response status", status)
	}
	var body bytes.Buffer
	if _, err := io.Copy(&body, r); err != nil {
		return nil, fmt.Errorf("Could not read response: %v", err)
	}
	resp.Body = body.Bytes()
	return resp, nil
}

func defaultHeader(bodyLen int) []byte {
	var dh []byte
	defaultHeaderFields["CONTENT_LENGTH"] = strconv.Itoa(bodyLen)
	for k, v := range defaultHeaderFields {
		dh = append(dh, header(k, v)...)
	}
	return dh
}

func header(name, value string) []byte {
	h := append([]byte(name), 0)
	h = append(h, []byte(value)...)
	return append(h, 0)
}

var defaultHeaderFields = map[string]string{
	"CONTENT_LENGTH":  "",
	"SCGI":            "1",
	"REQUEST_METHOD":  "POST",
	"SERVER_PROTOCOL": "HTTP/1.1",
}

const (
	comma = byte(',')
	colon = byte(':')
)

func netstring(s []byte) []byte {
	le := []byte(strconv.Itoa(len(s)))
	ns := append(le, colon)
	ns = append(ns, s...)
	ns = append(ns, comma)
	return ns
}
<|endoftext|>


<commit_before>package main

import (
	"time"

	"github.com/hybridgroup/gobot"
	"github.com/hybridgroup/gobot/platforms/gpio"
	"github.com/hybridgroup/gobot/platforms/intel-iot/edison"
)

func main() {
	gbot := gobot.NewGobot()

	e := edison.NewEdisonAdaptor("edison")
	led := gpio.NewLedDriver(e, "led", "13")

	work := func() {
		gobot.Every(1*time.Second, func() {
			led.Toggle()
		})
	}

	robot := gobot.NewRobot("blinkBot",
		[]gobot.Connection{e},
		[]gobot.Device{led},
		work,
	)

	gbot.AddRobot(robot)

	gbot.Start()
}
<commit_msg>ble stuff<commit_after>package main

import (
	"fmt"
	"log"
	"time"

	"github.com/acmacalister/gatt"
)

func main() {

	srv := gatt.NewServer(gatt.Name("gophergatt"))
	svc := srv.AddService(gatt.MustParseUUID("09fc95c0-c111-11e3-9904-0002a5d5c51b"))

	// Add a read characteristic that prints how many times it has been read
	n := 0
	rchar := svc.AddCharacteristic(gatt.MustParseUUID("11fac9e0-c111-11e3-9246-0002a5d5c51b"))
	rchar.HandleRead(
		gatt.ReadHandlerFunc(
			func(resp gatt.ReadResponseWriter, req *gatt.ReadRequest) {
				fmt.Fprintf(resp, "count: %d", n)
				n++
			}),
	)

	// Add a write characteristic that logs when written to
	wchar := svc.AddCharacteristic(gatt.MustParseUUID("16fe0d80-c111-11e3-b8c8-0002a5d5c51b"))
	wchar.HandleWriteFunc(
		func(r gatt.Request, data []byte) (status byte) {
			log.Println("Wrote:", string(data))
			return gatt.StatusSuccess
		})

	// Add a notify characteristic that updates once a second
	nchar := svc.AddCharacteristic(gatt.MustParseUUID("1c927b50-c116-11e3-8a33-0800200c9a66"))
	nchar.HandleNotifyFunc(
		func(r gatt.Request, n gatt.Notifier) {
			go func() {
				count := 0
				for !n.Done() {
					fmt.Fprintf(n, "Count: %d", count)
					count++
					time.Sleep(time.Second)
				}
			}()
		})

	fmt.Println("advertising...")
	// Start the server
	log.Fatal(srv.AdvertiseAndServe())
}

// c := &serial.Config{Name: "/dev/ttyMFD1", Baud: 9600}
// s, err := serial.OpenPort(c)
// if err != nil {
// 	log.Fatal(err)
// }

// go func() {
// 	for {
// 		reader := bufio.NewReader(os.Stdin)
// 		fmt.Print("Enter text: ")
// 		text, _ := reader.ReadString('\n')
// 		_, err := s.Write([]byte(text))
// 		if err != nil {
// 			log.Fatal(err)
// 		}
// 	}
// }()

// for {
// 	buf := make([]byte, 128)
// 	n, err := s.Read(buf)
// 	if err != nil {
// 		log.Fatal(err)
// 	}
// 	log.Println("stuff:", string(buf[:n]))
// }
<|endoftext|>


<commit_before>package main

import (
	"log"
	"flag"
	"os"
	"time"

	"github.com/hanwen/gitfs/fs"
	"github.com/hanwen/go-fuse/fuse/nodefs"

	git "github.com/libgit2/git2go"
)

func main() {
	tree := flag.String("tree", "master", "tree to mount")
	flag.Parse()

	if len(flag.Args()) < 2 {
		log.Fatalf("usage: %s REPO MOUNT", os.Args[0])
	}

	repoDir := flag.Args()[0]
	mntDir := flag.Args()[1]

	repo, err := git.OpenRepository(repoDir)
	if err != nil {
		log.Fatalf("OpenRepository(%q): %v", repoDir, err)
	}

	fs, err := fs.NewTreeFS(repo, *tree)
	if err != nil {
		log.Fatalf("NewTreeFS(%q): %v", *tree, err)
	}

	server, _, err := nodefs.MountFileSystem(mntDir, fs, &nodefs.Options{
		EntryTimeout: time.Hour,
		NegativeTimeout: time.Hour,
		AttrTimeout: time.Hour,
		PortableInodes: true,
	})
	log.Printf("Started gitfs FUSE on %s", mntDir)
	server.Serve()
}
<commit_msg>Make main driver use multifs.<commit_after>package main

import (
	"log"
	"flag"
	"os"
	"time"

	"github.com/hanwen/gitfs/fs"
	"github.com/hanwen/go-fuse/fuse/nodefs"
)

func main() {
	flag.Parse()
	if len(flag.Args()) < 1 {
		log.Fatalf("usage: %s MOUNT", os.Args[0])
	}

	mntDir := flag.Args()[0]

	fs := fs.NewMultiGitFS()
	server, _, err := nodefs.MountFileSystem(mntDir, fs, &nodefs.Options{
		EntryTimeout: time.Hour,
		NegativeTimeout: time.Hour,
		AttrTimeout: time.Hour,
		PortableInodes: true,
	})
	if err != nil {
		log.Fatalf("MountFileSystem: %v", err)
	}
	log.Printf("Started git multi fs FUSE on %s", mntDir)
	server.Serve()
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"errors"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"os/user"
	"path"
	"path/filepath"
	"sort"
	"strings"
	"syscall"

	"github.com/codegangsta/cli"
	"github.com/hpcloud/tail"
	"github.com/yext/errgo"
)

type EdwardConfiguration struct {
	Dir       string
	LogDir    string
	PidDir    string
	ScriptDir string
}

var EdwardConfig EdwardConfiguration = EdwardConfiguration{}

func createDirIfNeeded(path string) {
	if _, err := os.Stat(path); os.IsNotExist(err) {
		os.MkdirAll(path, 0777)
	}
}

func (e *EdwardConfiguration) initialize() error {
	user, err := user.Current()
	if err != nil {
		return err
	}
	e.Dir = path.Join(user.HomeDir, ".edward")
	e.LogDir = path.Join(e.Dir, "logs")
	e.PidDir = path.Join(e.Dir, "pidFiles")
	e.ScriptDir = path.Join(e.Dir, "scriptFiles")
	createDirIfNeeded(e.Dir)
	createDirIfNeeded(e.LogDir)
	createDirIfNeeded(e.PidDir)
	createDirIfNeeded(e.ScriptDir)
	return nil
}

var groups map[string]*ServiceGroupConfig
var services map[string]*ServiceConfig

func thirdPartyService(name string, startCommand string, stopCommand string, started string) *ServiceConfig {
	pathStr := "$ALPHA"
	return &ServiceConfig{
		Name: name,
		Path: &pathStr,
		Env:  []string{"YEXT_RABBITMQ=localhost"},
		Commands: ServiceConfigCommands{
			Launch: startCommand,
			Stop:   stopCommand,
		},
		Properties: ServiceConfigProperties{
			Started: started,
		},
	}
}

func getAlpha() string {
	for _, env := range os.Environ() {
		pair := strings.Split(env, "=")
		if pair[0] == "ALPHA" {
			return pair[1]
		}
	}
	return ""
}

func addFoundServices() {
	foundServices, _, err := generateServices(getAlpha())
	if err != nil {
		log.Fatal(err)
	}

	for _, s := range foundServices {
		if _, found := services[s.Name]; !found {
			services[s.Name] = s
		}
	}
}

func getConfigPath() string {
	wd, _ := os.Getwd()
	return filepath.Join(wd, "edward.json")
}

func loadConfig() {
	groups = make(map[string]*ServiceGroupConfig)
	services = make(map[string]*ServiceConfig)

	configPath := getConfigPath()

	if _, err := os.Stat(configPath); err == nil {
		println("Loading configuration from", configPath)
		r, err := os.Open(configPath)
		if err != nil {
			log.Fatal(err)
		}
		config, err := LoadConfig(r)
		if err != nil {
			log.Fatal(err)
		}

		services = config.ServiceMap
		groups = config.GroupMap
		return
	} else {
		addFoundServices()
		applyHardCodedServicesAndGroups()
	}

}

func getServicesOrGroups(names []string) ([]ServiceOrGroup, error) {
	var outSG []ServiceOrGroup
	for _, name := range names {
		sg, err := getServiceOrGroup(name)
		if err != nil {
			return nil, err
		}
		outSG = append(outSG, sg)
	}
	return outSG, nil
}

func getServiceOrGroup(name string) (ServiceOrGroup, error) {
	if group, ok := groups[name]; ok {
		return group, nil
	}
	if service, ok := services[name]; ok {
		return service, nil
	}
	return nil, errors.New("Service or group not found")
}

func list(c *cli.Context) error {

	var groupNames []string
	var serviceNames []string
	for name, _ := range groups {
		groupNames = append(groupNames, name)
	}
	for name, _ := range services {
		serviceNames = append(serviceNames, name)
	}

	sort.Strings(groupNames)
	sort.Strings(serviceNames)

	println("Services and groups")
	println("Groups:")
	for _, name := range groupNames {
		println("\t", name)
	}
	println("Services:")
	for _, name := range serviceNames {
		println("\t", name)
	}

	return nil
}

func generate(c *cli.Context) error {

	// Add any new services to the config as appropriate
	addFoundServices()

	configPath := getConfigPath()

	if err := generateConfigFile(configPath); err != nil {
		return err
	}
	println("Wrote to", configPath)

	return nil
}

func allStatus() {
	var statuses []ServiceStatus
	for _, service := range services {
		statuses = append(statuses, service.GetStatus()...)
	}
	for _, status := range statuses {
		if status.Status != "STOPPED" {
			println(status.Service.Name, ":", status.Status)
		}
	}
}

func status(c *cli.Context) error {

	if len(c.Args()) == 0 {
		allStatus()
		return nil
	}

	sgs, err := getServicesOrGroups(c.Args())
	if err != nil {
		return err
	}
	for _, s := range sgs {
		statuses := s.GetStatus()
		for _, status := range statuses {
			println(status.Service.Name, ":", status.Status)
		}
	}
	return nil
}

func messages(c *cli.Context) error {
	return errors.New("Unimplemented")
}

func start(c *cli.Context) error {
	sgs, err := getServicesOrGroups(c.Args())
	if err != nil {
		return err
	}
	for _, s := range sgs {
		println("==== Build Phase ====")
		err = s.Build()
		if err != nil {
			return errors.New("Error building " + s.GetName() + ": " + err.Error())
		}
		println("==== Launch Phase ====")
		err = s.Start()
		if err != nil {
			return errors.New("Error launching " + s.GetName() + ": " + err.Error())
		}
	}
	return nil
}

func allServices() []ServiceOrGroup {
	var as []ServiceOrGroup
	for _, service := range services {
		as = append(as, service)
	}
	return as
}

func stop(c *cli.Context) error {
	var sgs []ServiceOrGroup
	var err error
	if len(c.Args()) == 0 {
		sgs = allServices()
	} else {
		sgs, err = getServicesOrGroups(c.Args())
		if err != nil {
			return err
		}
	}
	for _, s := range sgs {
		_ = s.Stop()
	}
	return nil
}

func restart(c *cli.Context) error {
	sgs, err := getServicesOrGroups(c.Args())
	if err != nil {
		return err
	}
	for _, s := range sgs {
		_ = s.Stop()
		err = s.Build()
		if err != nil {
			return err
		}
		err = s.Start()
		if err != nil {
			return err
		}
	}
	return nil
}

func doLog(c *cli.Context) error {
	if len(c.Args()) > 1 {
		return errors.New("Cannot output multiple service logs")
	}
	name := c.Args()[0]
	if _, ok := groups[name]; ok {
		return errors.New("Cannot output group logs")
	}
	if service, ok := services[name]; ok {
		command := service.GetCommand()
		runLog := command.Logs.Run
		t, err := tail.TailFile(runLog, tail.Config{Follow: true})
		if err != nil {
			return nil
		}
		for line := range t.Lines {
			println(line.Text)
		}
		return nil
	}
	return errors.New("Service not found: " + name)
}

func checkNotSudo() {
	user, err := user.Current()
	if err != nil {
		log.Fatal(err)
	}
	if user.Uid == "0" {
		log.Fatal("edward should not be run with sudo")
	}
}

func createScriptFile(suffix string, content string) (*os.File, error) {
	file, err := ioutil.TempFile(os.TempDir(), suffix)
	if err != nil {
		return nil, err
	}
	file.WriteString(content)
	file.Close()

	err = os.Chmod(file.Name(), 0777)
	if err != nil {
		return nil, err
	}

	return file, nil
}

func ensureSudoAble() {
	var buffer bytes.Buffer

	buffer.WriteString("#!/bin/bash\n")
	buffer.WriteString("sudo echo Test > /dev/null\n")
	buffer.WriteString("ISCHILD=YES ")
	buffer.WriteString(strings.Join(os.Args, " "))
	buffer.WriteString("\n")

	file, err := createScriptFile("sudoAbility", buffer.String())
	if err != nil {
		log.Fatal(err)
	}

	err = syscall.Exec(file.Name(), []string{file.Name()}, os.Environ())
	if err != nil {
		log.Fatal(err)
	}
}

func prepareForSudo() {
	checkNotSudo()

	isChild := os.Getenv("ISCHILD")
	if isChild == "" {
		ensureSudoAble()
		return
	}
}

func RemoveContents(dir string) error {
	d, err := os.Open(dir)
	if err != nil {
		return err
	}
	defer d.Close()
	names, err := d.Readdirnames(-1)
	if err != nil {
		return err
	}
	for _, name := range names {
		err = os.RemoveAll(filepath.Join(dir, name))
		if err != nil {
			return err
		}
	}
	return nil
}

func refreshForReboot() error {
	rebootFile := path.Join(EdwardConfig.Dir, ".lastreboot")

	rebootMarker, _ := ioutil.ReadFile(rebootFile)

	command := exec.Command("last", "-1", "reboot")
	output, err := command.CombinedOutput()
	if err != nil {
		return errgo.Mask(err)
	}

	if string(output) != string(rebootMarker) {
		err = RemoveContents(EdwardConfig.PidDir)
		if err != nil {
			return errgo.Mask(err)
		}
		err = ioutil.WriteFile(rebootFile, output, os.ModePerm)
		if err != nil {
			return errgo.Mask(err)
		}
	}

	return nil
}

func main() {

	app := cli.NewApp()
	app.Name = "Edward"
	app.Usage = "Manage local microservices"
	app.Before = func(c *cli.Context) error {
		command := c.Args().First()
		if command == "start" || command == "stop" || command == "restart" {
			prepareForSudo()
		}

		err := EdwardConfig.initialize()
		if err != nil {
			return err
		}
		err = refreshForReboot()
		if err != nil {
			return err
		}
		loadConfig()
		return nil
	}
	app.Commands = []cli.Command{
		{
			Name:   "list",
			Usage:  "List available services",
			Action: list,
		},
		{
			Name:   "generate",
			Usage:  "Generate Edward config for a source tree",
			Action: generate,
		},
		{
			Name:   "status",
			Usage:  "Display service status",
			Action: status,
		},
		{
			Name:   "messages",
			Usage:  "Show messages from services",
			Action: messages,
		},
		{
			Name:   "start",
			Usage:  "Build and launch a service",
			Action: start,
		},
		{
			Name:   "stop",
			Usage:  "Stop a service",
			Action: stop,
		},
		{
			Name:   "restart",
			Usage:  "Rebuild and relaunch a service",
			Action: restart,
		},
		{
			Name:    "log",
			Aliases: []string{"tail"},
			Usage:   "Tail the log for a service",
			Action:  doLog,
		},
	}

	err := app.Run(os.Args)
	if err != nil {
		log.Fatal(err)
	}
}
<commit_msg>Search for a config file first in the current working directory, then the root of the current working dir's git repo, then the Edward home dir.<commit_after>package main

import (
	"bytes"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"os/user"
	"path"
	"path/filepath"
	"sort"
	"strings"
	"syscall"

	"github.com/codegangsta/cli"
	"github.com/hpcloud/tail"
	"github.com/yext/errgo"
)

type EdwardConfiguration struct {
	Dir       string
	LogDir    string
	PidDir    string
	ScriptDir string
}

var EdwardConfig EdwardConfiguration = EdwardConfiguration{}

func createDirIfNeeded(path string) {
	if _, err := os.Stat(path); os.IsNotExist(err) {
		os.MkdirAll(path, 0777)
	}
}

func (e *EdwardConfiguration) initialize() error {
	user, err := user.Current()
	if err != nil {
		return err
	}
	e.Dir = path.Join(user.HomeDir, ".edward")
	e.LogDir = path.Join(e.Dir, "logs")
	e.PidDir = path.Join(e.Dir, "pidFiles")
	e.ScriptDir = path.Join(e.Dir, "scriptFiles")
	createDirIfNeeded(e.Dir)
	createDirIfNeeded(e.LogDir)
	createDirIfNeeded(e.PidDir)
	createDirIfNeeded(e.ScriptDir)
	return nil
}

var groups map[string]*ServiceGroupConfig
var services map[string]*ServiceConfig

func thirdPartyService(name string, startCommand string, stopCommand string, started string) *ServiceConfig {
	pathStr := "$ALPHA"
	return &ServiceConfig{
		Name: name,
		Path: &pathStr,
		Env:  []string{"YEXT_RABBITMQ=localhost"},
		Commands: ServiceConfigCommands{
			Launch: startCommand,
			Stop:   stopCommand,
		},
		Properties: ServiceConfigProperties{
			Started: started,
		},
	}
}

func getAlpha() string {
	for _, env := range os.Environ() {
		pair := strings.Split(env, "=")
		if pair[0] == "ALPHA" {
			return pair[1]
		}
	}
	return ""
}

func addFoundServices() {
	foundServices, _, err := generateServices(getAlpha())
	if err != nil {
		log.Fatal(err)
	}

	for _, s := range foundServices {
		if _, found := services[s.Name]; !found {
			services[s.Name] = s
		}
	}
}

// getConfigPath identifies the location of edward.json, if any exists
func getConfigPath() string {
	var pathOptions []string

	// Config file in current working directory
	wd, err := os.Getwd()
	if err == nil {
		pathOptions = append(pathOptions, filepath.Join(wd, "edward.json"))
	}

	// Config file at root of working dir's git repo, if any
	gitRoot, err := gitRoot()
	if err == nil {
		pathOptions = append(pathOptions, filepath.Join(gitRoot, "edward.json"))

	}

	// Config file in Edward Config dir
	pathOptions = append(pathOptions, filepath.Join(EdwardConfig.Dir, "edward.json"))

	for _, path := range pathOptions {
		if _, err := os.Stat(path); err == nil {
			return path
		}
	}

	return ""
}

func gitRoot() (string, error) {
	output, err := exec.Command("git", "rev-parse", "--show-toplevel").CombinedOutput()
	if err != nil {
		return "", fmt.Errorf("%v\n%v", string(output), err)
	}
	return strings.TrimSpace(string(output)), nil
}

func loadConfig() {
	groups = make(map[string]*ServiceGroupConfig)
	services = make(map[string]*ServiceConfig)

	configPath := getConfigPath()

	if configPath != "" {
		println("Loading configuration from", configPath)
		r, err := os.Open(configPath)
		if err != nil {
			log.Fatal(err)
		}
		config, err := LoadConfig(r)
		if err != nil {
			log.Fatal(err)
		}

		services = config.ServiceMap
		groups = config.GroupMap
		return
	} else {
		addFoundServices()
		applyHardCodedServicesAndGroups()
	}

}

func getServicesOrGroups(names []string) ([]ServiceOrGroup, error) {
	var outSG []ServiceOrGroup
	for _, name := range names {
		sg, err := getServiceOrGroup(name)
		if err != nil {
			return nil, err
		}
		outSG = append(outSG, sg)
	}
	return outSG, nil
}

func getServiceOrGroup(name string) (ServiceOrGroup, error) {
	if group, ok := groups[name]; ok {
		return group, nil
	}
	if service, ok := services[name]; ok {
		return service, nil
	}
	return nil, errors.New("Service or group not found")
}

func list(c *cli.Context) error {

	var groupNames []string
	var serviceNames []string
	for name, _ := range groups {
		groupNames = append(groupNames, name)
	}
	for name, _ := range services {
		serviceNames = append(serviceNames, name)
	}

	sort.Strings(groupNames)
	sort.Strings(serviceNames)

	println("Services and groups")
	println("Groups:")
	for _, name := range groupNames {
		println("\t", name)
	}
	println("Services:")
	for _, name := range serviceNames {
		println("\t", name)
	}

	return nil
}

func generate(c *cli.Context) error {

	// Add any new services to the config as appropriate
	addFoundServices()

	configPath := getConfigPath()
	if configPath == "" {
		wd, err := os.Getwd()
		if err == nil {
			configPath = filepath.Join(wd, "edward.json")
		}
	}

	if err := generateConfigFile(configPath); err != nil {
		return err
	}
	println("Wrote to", configPath)

	return nil
}

func allStatus() {
	var statuses []ServiceStatus
	for _, service := range services {
		statuses = append(statuses, service.GetStatus()...)
	}
	for _, status := range statuses {
		if status.Status != "STOPPED" {
			println(status.Service.Name, ":", status.Status)
		}
	}
}

func status(c *cli.Context) error {

	if len(c.Args()) == 0 {
		allStatus()
		return nil
	}

	sgs, err := getServicesOrGroups(c.Args())
	if err != nil {
		return err
	}
	for _, s := range sgs {
		statuses := s.GetStatus()
		for _, status := range statuses {
			println(status.Service.Name, ":", status.Status)
		}
	}
	return nil
}

func messages(c *cli.Context) error {
	return errors.New("Unimplemented")
}

func start(c *cli.Context) error {
	sgs, err := getServicesOrGroups(c.Args())
	if err != nil {
		return err
	}
	for _, s := range sgs {
		println("==== Build Phase ====")
		err = s.Build()
		if err != nil {
			return errors.New("Error building " + s.GetName() + ": " + err.Error())
		}
		println("==== Launch Phase ====")
		err = s.Start()
		if err != nil {
			return errors.New("Error launching " + s.GetName() + ": " + err.Error())
		}
	}
	return nil
}

func allServices() []ServiceOrGroup {
	var as []ServiceOrGroup
	for _, service := range services {
		as = append(as, service)
	}
	return as
}

func stop(c *cli.Context) error {
	var sgs []ServiceOrGroup
	var err error
	if len(c.Args()) == 0 {
		sgs = allServices()
	} else {
		sgs, err = getServicesOrGroups(c.Args())
		if err != nil {
			return err
		}
	}
	for _, s := range sgs {
		_ = s.Stop()
	}
	return nil
}

func restart(c *cli.Context) error {
	sgs, err := getServicesOrGroups(c.Args())
	if err != nil {
		return err
	}
	for _, s := range sgs {
		_ = s.Stop()
		err = s.Build()
		if err != nil {
			return err
		}
		err = s.Start()
		if err != nil {
			return err
		}
	}
	return nil
}

func doLog(c *cli.Context) error {
	if len(c.Args()) > 1 {
		return errors.New("Cannot output multiple service logs")
	}
	name := c.Args()[0]
	if _, ok := groups[name]; ok {
		return errors.New("Cannot output group logs")
	}
	if service, ok := services[name]; ok {
		command := service.GetCommand()
		runLog := command.Logs.Run
		t, err := tail.TailFile(runLog, tail.Config{Follow: true})
		if err != nil {
			return nil
		}
		for line := range t.Lines {
			println(line.Text)
		}
		return nil
	}
	return errors.New("Service not found: " + name)
}

func checkNotSudo() {
	user, err := user.Current()
	if err != nil {
		log.Fatal(err)
	}
	if user.Uid == "0" {
		log.Fatal("edward should not be run with sudo")
	}
}

func createScriptFile(suffix string, content string) (*os.File, error) {
	file, err := ioutil.TempFile(os.TempDir(), suffix)
	if err != nil {
		return nil, err
	}
	file.WriteString(content)
	file.Close()

	err = os.Chmod(file.Name(), 0777)
	if err != nil {
		return nil, err
	}

	return file, nil
}

func ensureSudoAble() {
	var buffer bytes.Buffer

	buffer.WriteString("#!/bin/bash\n")
	buffer.WriteString("sudo echo Test > /dev/null\n")
	buffer.WriteString("ISCHILD=YES ")
	buffer.WriteString(strings.Join(os.Args, " "))
	buffer.WriteString("\n")

	file, err := createScriptFile("sudoAbility", buffer.String())
	if err != nil {
		log.Fatal(err)
	}

	err = syscall.Exec(file.Name(), []string{file.Name()}, os.Environ())
	if err != nil {
		log.Fatal(err)
	}
}

func prepareForSudo() {
	checkNotSudo()

	isChild := os.Getenv("ISCHILD")
	if isChild == "" {
		ensureSudoAble()
		return
	}
}

func RemoveContents(dir string) error {
	d, err := os.Open(dir)
	if err != nil {
		return err
	}
	defer d.Close()
	names, err := d.Readdirnames(-1)
	if err != nil {
		return err
	}
	for _, name := range names {
		err = os.RemoveAll(filepath.Join(dir, name))
		if err != nil {
			return err
		}
	}
	return nil
}

func refreshForReboot() error {
	rebootFile := path.Join(EdwardConfig.Dir, ".lastreboot")

	rebootMarker, _ := ioutil.ReadFile(rebootFile)

	command := exec.Command("last", "-1", "reboot")
	output, err := command.CombinedOutput()
	if err != nil {
		return errgo.Mask(err)
	}

	if string(output) != string(rebootMarker) {
		err = RemoveContents(EdwardConfig.PidDir)
		if err != nil {
			return errgo.Mask(err)
		}
		err = ioutil.WriteFile(rebootFile, output, os.ModePerm)
		if err != nil {
			return errgo.Mask(err)
		}
	}

	return nil
}

func main() {

	app := cli.NewApp()
	app.Name = "Edward"
	app.Usage = "Manage local microservices"
	app.Before = func(c *cli.Context) error {
		command := c.Args().First()
		if command == "start" || command == "stop" || command == "restart" {
			prepareForSudo()
		}

		err := EdwardConfig.initialize()
		if err != nil {
			return err
		}
		err = refreshForReboot()
		if err != nil {
			return err
		}
		loadConfig()
		return nil
	}
	app.Commands = []cli.Command{
		{
			Name:   "list",
			Usage:  "List available services",
			Action: list,
		},
		{
			Name:   "generate",
			Usage:  "Generate Edward config for a source tree",
			Action: generate,
		},
		{
			Name:   "status",
			Usage:  "Display service status",
			Action: status,
		},
		{
			Name:   "messages",
			Usage:  "Show messages from services",
			Action: messages,
		},
		{
			Name:   "start",
			Usage:  "Build and launch a service",
			Action: start,
		},
		{
			Name:   "stop",
			Usage:  "Stop a service",
			Action: stop,
		},
		{
			Name:   "restart",
			Usage:  "Rebuild and relaunch a service",
			Action: restart,
		},
		{
			Name:    "log",
			Aliases: []string{"tail"},
			Usage:   "Tail the log for a service",
			Action:  doLog,
		},
	}

	err := app.Run(os.Args)
	if err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"database/sql"
	"fmt"
	"io"
	"log"
	"mime"
	"net/mail"
	"net/smtp"
	"os"
	"strconv"

	message "github.com/matsuev/go-message"
	charset "github.com/matsuev/go-message/charset"

	_ "github.com/go-sql-driver/mysql"
)

func main() {
	// Перенаправление логов в файл
	// создать файл лога, установить права доступа
	// l, err := os.OpenFile("./klshmail.log", os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)
	// l, err := os.OpenFile("/var/log/klshmail.log", os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)
	// logFatal(err)
	// defer l.Close()

	// log.SetOutput(l)

	// Заголовки исходного сообщения,
	// которые нужно оставить
	hh := []string{
		"MIME-Version",
		"Message-Id",
		"Content-Type",
		"Content-Transfer-Encoding",
		"In-Reply-To",
		"References",
		// "Subject",
	}

	r, err := os.Open("./testmessage.eml")
	if err != nil {
		log.Fatal(err)
	}
	defer r.Close()

	// Читаем сообщение из стандартного ввода
	// msg, err := message.Read(os.Stdin)
	msg, err := message.Read(r)
	logFatal(err)
	log.Println("New message accepted...")

	// Разбор заголовков сообщения
	to, err := getMailHeader("To", msg.Header)
	logFatal(err)
	log.Printf("To: %s <%s>\n", to.Name, to.Address)

	from, err := getMailHeader("From", msg.Header)
	logFatal(err)
	log.Printf("From: %s <%s>\n", from.Name, from.Address)

	hSubject, err := charset.DecodeHeader(msg.Header.Get("Subject"))
	logFatal(err)

	subj := mime.BEncoding.Encode("utf-8", hSubject)

	if to.Address == "" || from.Address == "" {
		log.Fatalln("Empty address. Reject message.")
	}

	// Сокдинение с сервером БД
	db, err := sql.Open("mysql", "klshmail:euXoe8uSha1xu4sh@/klshmail?charset=utf8")
	logFatal(err)

	// Проверка соединения с сервером БД
	err = db.Ping()
	logFatal(err)

	// Запрос данных о списке рассылки
	var lid uint64
	var lprefix string

	err = db.QueryRow(`
		SELECT list.id, list.prefix
		FROM list
		WHERE LCASE(list.email)=TRIM(LCASE(?))
		AND list.active
		`, to.Address).Scan(&lid, &lprefix)
	if err != nil {
		log.Println("No list with address:", to.Address)
		os.Exit(0)
	}

	// Запрос на проверку прав пользователя на отправку сообщений в список
	var uid uint64
	err = db.QueryRow(`
		SELECT user.id
		FROM user
		INNER JOIN user_list
		ON (user_list.lid=?
			AND user.id=user_list.uid
			AND user_list.canwrite
		)
		WHERE LCASE(user.email)=TRIM(LCASE(?))
		AND user.active
		`, lid, from.Address).Scan(&uid)
	if err != nil {
		log.Println("User", from.Address, "can't send messages to", to.Address)
		os.Exit(0)
	}

	// Формирование заголовков нового сообщения
	newHeader := make(message.Header)
	for _, hk := range hh {
		if hv := msg.Header.Get(hk); hv != "" {
			newHeader.Set(hk, hv)
		}
	}

	sender := new(mail.Address)
	sender.Name = from.Name
	sender.Address = from.Address

	from.Name = fmt.Sprintf("%s", lprefix)
	from.Address = to.Address

	newHeader.Set("From", from.String())
	newHeader.Set("Reply-To", to.Address)
	newHeader.Set("Subject", subj)
	newHeader.Set("X-KLSH-Sender", strconv.FormatUint(uid, 10))

	var b bytes.Buffer
	w, err := message.CreateWriter(&b, newHeader)
	if err != nil {
		log.Fatal(err)
	}
	defer w.Close()

	if err := transform(w, msg, sender); err != nil {
		log.Fatal(err)
	}

	// Подключение к SMTP серверу
	c, err := smtp.Dial("127.0.0.1:25")
	if err != nil {
		log.Println("SMTP connection error")
		log.Fatal(err)
	}
	defer c.Close()

	// // Заголовки для отправки
	// c.Mail(to.Address)
	// c.Rcpt(fmt.Sprintf("%v@klshmail", lid))
	//
	// wc, err := c.Data()
	// logFatal(err)
	// defer wc.Close()
	//
	// // Отправка сообщения
	// br := bytes.NewReader(b.Bytes())
	// if _, err = io.Copy(wc, br); err != nil {
	// 	log.Println("SMTP send body error")
	// 	log.Fatalln(err)
	// }

	fmt.Println(b.String())

	// Завершение работы
	log.Println("Message processing done.")

}

func logFatal(e error) {
	if e != nil {
		log.Fatalln(e)
	}
}

const senderHtml string = `<p><b>Сообщение от:</b> %s <<a href="mailto:%s">%s</a>><p>`
const senderPlain string = "| Сообщение от:  %s <%s>\n——\n\n"

func transform(w *message.Writer, e *message.Entity, sender *mail.Address) error {
	if mr := e.MultipartReader(); mr != nil {
		// This is a multipart entity, transform each of its parts
		for {
			p, err := mr.NextPart()
			if err == io.EOF {
				break
			} else if err != nil {
				return err
			}

			pw, err := w.CreatePart(p.Header)
			if err != nil {
				return err
			}

			if err := transform(pw, p, sender); err != nil {
				return err
			}

			pw.Close()
		}
		return nil
	} else {
		body := e.Body
		// var newLine string
		// if strings.HasPrefix(e.Header.Get("Content-Type"), "text/plain") {
		// 	newLine = fmt.Sprintf(senderPlain, sender.Name, sender.Address)
		// }
		// if strings.HasPrefix(e.Header.Get("Content-Type"), "text/html") {
		// 	newLine = fmt.Sprintf(senderHtml, sender.Name, sender.Address, sender.Address)
		// }
		// body = io.MultiReader(strings.NewReader(newLine), body)
		_, err := io.Copy(w, body)
		return err
	}
}

func getMailHeader(k string, h message.Header) (*mail.Address, error) {
	dh, err := charset.DecodeHeader(h.Get(k))
	if err != nil {
		return nil, err
	}

	rh, err := mail.ParseAddress(dh)
	return rh, err
}
<commit_msg>Update main.go<commit_after>package main

import (
	"bytes"
	"database/sql"
	"fmt"
	"io"
	"log"
	"mime"
	"net/mail"
	"net/smtp"
	"os"
	"strconv"

	message "github.com/matsuev/go-message"
	charset "github.com/matsuev/go-message/charset"

	_ "github.com/go-sql-driver/mysql"
)

func main() {
	// Перенаправление логов в файл
	// создать файл лога, установить права доступа
	// l, err := os.OpenFile("./klshmail.log", os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)
	// l, err := os.OpenFile("/var/log/klshmail.log", os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)
	// logFatal(err)
	// defer l.Close()

	// log.SetOutput(l)

	// Заголовки исходного сообщения,
	// которые нужно оставить
	hh := []string{
		"MIME-Version",
		"Message-Id",
		"Content-Type",
		"Content-Transfer-Encoding",
		"In-Reply-To",
		"References",
		// "Subject",
	}

	r, err := os.Open("./testmessage.eml")
	if err != nil {
		log.Fatal(err)
	}
	defer r.Close()

	// Читаем сообщение из стандартного ввода
	// msg, err := message.Read(os.Stdin)
	msg, err := message.Read(r)
	logFatal(err)
	log.Println("New message accepted...")

	// Разбор заголовков сообщения
	to, err := getMailHeader("To", msg.Header)
	logFatal(err)
	log.Printf("To: %s <%s>\n", to.Name, to.Address)

	from, err := getMailHeader("From", msg.Header)
	logFatal(err)
	log.Printf("From: %s <%s>\n", from.Name, from.Address)

	hSubject, err := charset.DecodeHeader(msg.Header.Get("Subject"))
	logFatal(err)

	subj := mime.BEncoding.Encode("utf-8", hSubject)

	if to.Address == "" || from.Address == "" {
		log.Fatalln("Empty address. Reject message.")
	}

	// Сокдинение с сервером БД
	db, err := sql.Open("mysql", "klshmail:euXoe8uSha1xu4sh@/klshmail?charset=utf8")
	logFatal(err)

	// Проверка соединения с сервером БД
	err = db.Ping()
	logFatal(err)

	// Запрос данных о списке рассылки
	var lid uint64
	var lprefix string

	err = db.QueryRow(`
		SELECT list.id, list.prefix
		FROM list
		WHERE LCASE(list.email)=TRIM(LCASE(?))
		AND list.active
		`, to.Address).Scan(&lid, &lprefix)
	if err != nil {
		log.Println("No list with address:", to.Address)
		os.Exit(0)
	}

	// Запрос на проверку прав пользователя на отправку сообщений в список
	var uid uint64
	err = db.QueryRow(`
		SELECT user.id
		FROM user
		INNER JOIN user_list
		ON (user_list.lid=?
			AND user.id=user_list.uid
			AND user_list.canwrite
		)
		WHERE LCASE(user.email)=TRIM(LCASE(?))
		AND user.active
		`, lid, from.Address).Scan(&uid)
	if err != nil {
		log.Println("User", from.Address, "can't send messages to", to.Address)
		os.Exit(0)
	}

	// Формирование заголовков нового сообщения
	newHeader := make(message.Header)
	for _, hk := range hh {
		if hv := msg.Header.Get(hk); hv != "" {
			newHeader.Set(hk, hv)
		}
	}

	sender := new(mail.Address)
	sender.Name = from.Name
	sender.Address = from.Address

	from.Name = fmt.Sprintf("%s", lprefix)
	from.Address = to.Address

	newHeader.Set("From", from.String())
	newHeader.Set("Reply-To", to.Address)
	newHeader.Set("Subject", subj)
	newHeader.Set("X-KLSH-Sender", strconv.FormatUint(uid, 10))

	var b bytes.Buffer
	w, err := message.CreateWriter(&b, newHeader)
	if err != nil {
		log.Fatal(err)
	}
	defer w.Close()

	if err := transform(w, msg, sender); err != nil {
		log.Fatal(err)
	}

	// Подключение к SMTP серверу
	c, err := smtp.Dial("127.0.0.1:25")
	if err != nil {
		log.Println("SMTP connection error")
		log.Fatal(err)
	}
	defer c.Close()

	// // Заголовки для отправки
	// c.Mail(to.Address)
	// c.Rcpt(fmt.Sprintf("%v@klshmail", lid))
	//
	// wc, err := c.Data()
	// logFatal(err)
	// defer wc.Close()
	//
	// // Отправка сообщения
	// br := bytes.NewReader(b.Bytes())
	// if _, err = io.Copy(wc, br); err != nil {
	// 	log.Println("SMTP send body error")
	// 	log.Fatalln(err)
	// }

	fmt.Println(b.String())

	// Завершение работы
	log.Println("Message processing done.")

}

func logFatal(e error) {
	if e != nil {
		log.Fatalln(e)
	}
}

const senderHtml string = `<p><b>Сообщение от:</b> %s <<a href="mailto:%s">%s</a>><p>`
const senderPlain string = "| Сообщение от:  %s <%s>\n——\n\n"

func transform(w *message.Writer, e *message.Entity, sender *mail.Address) error {
	if mr := e.MultipartReader(); mr != nil {
		// This is a multipart entity, transform each of its parts
		for {
			p, err := mr.NextPart()
			if err == io.EOF {
				break
			} else if err != nil {
				return err
			}

			fmt.Println(p.Header)

			pw, err := w.CreatePart(p.Header)
			if err != nil {
				return err
			}

			if err := transform(pw, p, sender); err != nil {
				return err
			}

			pw.Close()
		}
		return nil
	} else {
		body := e.Body
		// var newLine string
		// if strings.HasPrefix(e.Header.Get("Content-Type"), "text/plain") {
		// 	newLine = fmt.Sprintf(senderPlain, sender.Name, sender.Address)
		// }
		// if strings.HasPrefix(e.Header.Get("Content-Type"), "text/html") {
		// 	newLine = fmt.Sprintf(senderHtml, sender.Name, sender.Address, sender.Address)
		// }
		// body = io.MultiReader(strings.NewReader(newLine), body)
		_, err := io.Copy(w, body)
		return err
	}
}

func getMailHeader(k string, h message.Header) (*mail.Address, error) {
	dh, err := charset.DecodeHeader(h.Get(k))
	if err != nil {
		return nil, err
	}

	rh, err := mail.ParseAddress(dh)
	return rh, err
}
<|endoftext|>