<commit_before>/*
This package is just a collection of test cases
*/
package main

import (
	"github.com/codegangsta/cli"
	"os"
	"sort"
	"strings"
)

var (
	// flags
	fWant4 bool
	fWant6 bool
	fAllProbes bool
	fAsn string
	fCountry string
	fFieldList string
	fFormat string
	fOptFields string
	fSortOrder string
	fVerbose bool
	fWantAnchor bool

	cliCommands []cli.Command
)

type ByAlphabet []cli.Command

func (a ByAlphabet) Len() int           { return len(a) }
func (a ByAlphabet) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a ByAlphabet) Less(i, j int) bool { return a[i].Name < a[j].Name }

// checkGlobalFlags is the place to check global parameters
func checkGlobalFlags(o map[string]string) (map[string]string) {
	opts := o
	if fSortOrder != "" {
		opts["sort"] = fSortOrder
	}

	if fFieldList != "" {
		opts["fields"] = fFieldList
	}

	if fOptFields != "" {
		opts["optional_fields"] = fOptFields
	}

	if fFormat != "" && validateFormat(fFormat) {
		opts["format"] = fFormat
	}
	return opts
}

// validateFormat allows only supported formats
func validateFormat(fmt string) bool {
	f := strings.ToLower(fmt)
	if f == "json" || f == "xml" || f == "api" || f == "txt" || f == "jsonp" {
		return true
	}
	return false
}

// main is the starting point (and everything)
func main() {
	app := cli.NewApp()
	app.Name = "atlas"
	app.Usage = "RIPE Atlas cli interface"
	app.Author = "Ollivier Robert <roberto@keltia.net>"
	app.Version = "0.0.1"
	app.HideVersion = true

	// General flags
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name: "format,f",
			Usage: "specify output format",
			Destination: &fFormat,
		},
		cli.BoolFlag{
			Name: "v",
			Usage: "verbose mode",
			Destination: &fVerbose,
		},
		cli.StringFlag{
			Name: "fields,F",
			Usage: "specify which fields are wanted",
			Destination: &fFieldList,
		},
		cli.StringFlag{
			Name: "opt-fields,O",
			Usage: "specify which optional fields are wanted",
			Destination: &fOptFields,
		},
		cli.StringFlag{
			Name:        "sort,S",
			Usage:       "sort results",
			Value:       "id",
			Destination: &fSortOrder,
		},
	}

	sort.Sort(ByAlphabet(cliCommands))
	app.Commands = cliCommands
	app.Run(os.Args)
}
<commit_msg>This is not really alpha.<commit_after>/*
This package is just a collection of test cases
*/
package main

import (
	"github.com/codegangsta/cli"
	"os"
	"sort"
	"strings"
)

var (
	// flags
	fWant4 bool
	fWant6 bool
	fAllProbes bool
	fAsn string
	fCountry string
	fFieldList string
	fFormat string
	fOptFields string
	fSortOrder string
	fVerbose bool
	fWantAnchor bool

	cliCommands []cli.Command
)

type ByAlphabet []cli.Command

func (a ByAlphabet) Len() int           { return len(a) }
func (a ByAlphabet) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a ByAlphabet) Less(i, j int) bool { return a[i].Name < a[j].Name }

// checkGlobalFlags is the place to check global parameters
func checkGlobalFlags(o map[string]string) (map[string]string) {
	opts := o
	if fSortOrder != "" {
		opts["sort"] = fSortOrder
	}

	if fFieldList != "" {
		opts["fields"] = fFieldList
	}

	if fOptFields != "" {
		opts["optional_fields"] = fOptFields
	}

	if fFormat != "" && validateFormat(fFormat) {
		opts["format"] = fFormat
	}
	return opts
}

// validateFormat allows only supported formats
func validateFormat(fmt string) bool {
	f := strings.ToLower(fmt)
	if f == "json" || f == "xml" || f == "api" || f == "txt" || f == "jsonp" {
		return true
	}
	return false
}

// main is the starting point (and everything)
func main() {
	app := cli.NewApp()
	app.Name = "atlas"
	app.Usage = "RIPE Atlas cli interface"
	app.Author = "Ollivier Robert <roberto@keltia.net>"
	app.Version = "0.1.0"
	app.HideVersion = true

	// General flags
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name: "format,f",
			Usage: "specify output format",
			Destination: &fFormat,
		},
		cli.BoolFlag{
			Name: "v",
			Usage: "verbose mode",
			Destination: &fVerbose,
		},
		cli.StringFlag{
			Name: "fields,F",
			Usage: "specify which fields are wanted",
			Destination: &fFieldList,
		},
		cli.StringFlag{
			Name: "opt-fields,O",
			Usage: "specify which optional fields are wanted",
			Destination: &fOptFields,
		},
		cli.StringFlag{
			Name:        "sort,S",
			Usage:       "sort results",
			Value:       "id",
			Destination: &fSortOrder,
		},
	}

	sort.Sort(ByAlphabet(cliCommands))
	app.Commands = cliCommands
	app.Run(os.Args)
}
<|endoftext|>


<commit_before>// Copyright 2014 Wandoujia Inc. All Rights Reserved.
// Licensed under the MIT (MIT-LICENSE.txt) license.

package main

import (
	"os"
	"strings"

	"github.com/c4pt0r/cfg"
	"github.com/juju/errors"
	"github.com/wandoulabs/codis/pkg/utils/log"
	"github.com/wandoulabs/zkhelper"
)

type Env interface {
	ProductName() string
	DashboardAddr() string
	NewZkConn() (zkhelper.Conn, error)
}

type CodisEnv struct {
	zkAddr        string
	dashboardAddr string
	productName   string
	provider      string
}

func LoadCodisEnv(cfg *cfg.Cfg) Env {
	if cfg == nil {
		log.Panicf("config is nil")
	}

	productName, err := cfg.ReadString("product", "test")
	if err != nil {
		log.PanicErrorf(err, "read product name failed")
	}

	zkAddr, err := cfg.ReadString("zk", "localhost:2181")
	if err != nil {
		log.PanicErrorf(err, "read zk address failed")
	}

	hostname, _ := os.Hostname()
	dashboardAddr, err := cfg.ReadString("dashboard_addr", hostname+":18087")
	if err != nil {
		log.PanicErrorf(err, "read dashboard address failed")
	}

	provider, err := cfg.ReadString("coordinator", "zookeeper")
	if err != nil {
		log.PanicErrorf(err, "read coordinator failed")
	}

	return &CodisEnv{
		zkAddr:        zkAddr,
		dashboardAddr: dashboardAddr,
		productName:   productName,
		provider:      provider,
	}
}

func (e *CodisEnv) ProductName() string {
	return e.productName
}

func (e *CodisEnv) DashboardAddr() string {
	return e.dashboardAddr
}

func (e *CodisEnv) NewZkConn() (zkhelper.Conn, error) {
	switch e.provider {
	case "zookeeper":
		return zkhelper.ConnectToZk(e.zkAddr)
	case "etcd":
		addr := strings.TrimSpace(e.zkAddr)
		if !strings.HasPrefix(addr, "http://") {
			addr = "http://" + addr
		}
		return zkhelper.NewEtcdConn(addr)
	}
	return nil, errors.Errorf("need coordinator in config file, %+v", e)
}
<commit_msg>fix import<commit_after>// Copyright 2014 Wandoujia Inc. All Rights Reserved.
// Licensed under the MIT (MIT-LICENSE.txt) license.

package main

import (
	"os"
	"strings"

	"github.com/c4pt0r/cfg"
	"github.com/juju/errors"
	log "github.com/ngaut/logging"

	"github.com/wandoulabs/zkhelper"
)

type Env interface {
	ProductName() string
	DashboardAddr() string
	NewZkConn() (zkhelper.Conn, error)
}

type CodisEnv struct {
	zkAddr        string
	dashboardAddr string
	productName   string
	provider      string
}

func LoadCodisEnv(cfg *cfg.Cfg) Env {
	if cfg == nil {
		log.Fatal("config is nil")
	}

	productName, err := cfg.ReadString("product", "test")
	if err != nil {
		log.Fatal(err)
	}

	zkAddr, err := cfg.ReadString("zk", "localhost:2181")
	if err != nil {
		log.Fatal(err)
	}

	hostname, _ := os.Hostname()
	dashboardAddr, err := cfg.ReadString("dashboard_addr", hostname+":18087")
	if err != nil {
		log.Fatal(err)
	}

	provider, err := cfg.ReadString("coordinator", "zookeeper")
	if err != nil {
		log.Fatal(err)
	}

	return &CodisEnv{
		zkAddr:        zkAddr,
		dashboardAddr: dashboardAddr,
		productName:   productName,
		provider:      provider,
	}
}

func (e *CodisEnv) ProductName() string {
	return e.productName
}

func (e *CodisEnv) DashboardAddr() string {
	return e.dashboardAddr
}

func (e *CodisEnv) NewZkConn() (zkhelper.Conn, error) {
	switch e.provider {
	case "zookeeper":
		return zkhelper.ConnectToZk(e.zkAddr)
	case "etcd":
		addr := strings.TrimSpace(e.zkAddr)
		if !strings.HasPrefix(addr, "http://") {
			addr = "http://" + addr
		}
		return zkhelper.NewEtcdConn(addr)
	}
	return nil, errors.Errorf("need coordinator in config file, %+v", e)
}
<|endoftext|>


<commit_before>package check

import (
	"context"
	"io"
	"os"
	"strings"

	"github.com/rclone/rclone/cmd"
	"github.com/rclone/rclone/fs"
	"github.com/rclone/rclone/fs/config/flags"
	"github.com/rclone/rclone/fs/operations"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
)

// Globals
var (
	download     = false
	oneway       = false
	combined     = ""
	missingOnSrc = ""
	missingOnDst = ""
	match        = ""
	differ       = ""
	errFile      = ""
)

func init() {
	cmd.Root.AddCommand(commandDefinition)
	cmdFlags := commandDefinition.Flags()
	AddFlags(cmdFlags)
}

// AddFlags adds the check flags to the cmdFlags command
func AddFlags(cmdFlags *pflag.FlagSet) {
	flags.BoolVarP(cmdFlags, &oneway, "one-way", "", oneway, "Check one way only, source files must exist on remote")
	flags.StringVarP(cmdFlags, &combined, "combined", "", combined, "Make a combined report of changes to this file")
	flags.StringVarP(cmdFlags, &missingOnSrc, "missing-on-src", "", missingOnSrc, "Report all files missing from the source to this file")
	flags.StringVarP(cmdFlags, &missingOnDst, "missing-on-dst", "", missingOnDst, "Report all files missing from the destination to this file")
	flags.StringVarP(cmdFlags, &match, "match", "", match, "Report all matching files to this file")
	flags.StringVarP(cmdFlags, &differ, "differ", "", differ, "Report all non-matching files to this file")
	flags.StringVarP(cmdFlags, &errFile, "error", "", errFile, "Report all files with errors (hashing or reading) to this file")
}

// FlagsHelp describes the flags for the help
var FlagsHelp = strings.Replace(`
If you supply the |--one-way| flag, it will only check that files in
the source match the files in the destination, not the other way
around. This means that extra files in the destination that are not in
the source will not be detected.

The |--differ|, |--missing-on-dst|, |--missing-on-src|, |--src-only|
and |--error| flags write paths, one per line, to the file name (or
stdout if it is |-|) supplied. What they write is described in the
help below. For example |--differ| will write all paths which are
present on both the source and destination but different.

The |--combined| flag will write a file (or stdout) which contains all
file paths with a symbol and then a space and then the path to tell
you what happened to it. These are reminiscent of diff files.

- |= path| means path was found in source and destination and was identical
- |- path| means path was missing on the source, so only in the destination
- |+ path| means path was missing on the destination, so only in the source
- |* path| means path was present in source and destination but different.
- |! path| means there was an error reading or hashing the source or dest.
`, "|", "`", -1)

// GetCheckOpt gets the options corresponding to the check flags
func GetCheckOpt(fsrc, fdst fs.Fs) (opt *operations.CheckOpt, close func(), err error) {
	closers := []io.Closer{}

	opt = &operations.CheckOpt{
		Fsrc:   fsrc,
		Fdst:   fdst,
		OneWay: oneway,
	}

	open := func(name string, pout *io.Writer) error {
		if name == "" {
			return nil
		}
		if name == "-" {
			*pout = os.Stdout
			return nil
		}
		out, err := os.Create(name)
		if err != nil {
			return err
		}
		*pout = out
		closers = append(closers, out)
		return nil
	}

	if err = open(combined, &opt.Combined); err != nil {
		return nil, nil, err
	}
	if err = open(missingOnSrc, &opt.MissingOnSrc); err != nil {
		return nil, nil, err
	}
	if err = open(missingOnDst, &opt.MissingOnDst); err != nil {
		return nil, nil, err
	}
	if err = open(match, &opt.Match); err != nil {
		return nil, nil, err
	}
	if err = open(differ, &opt.Differ); err != nil {
		return nil, nil, err
	}
	if err = open(errFile, &opt.Error); err != nil {
		return nil, nil, err
	}

	close = func() {
		for _, closer := range closers {
			err := closer.Close()
			if err != nil {
				fs.Errorf(nil, "Failed to close report output: %v", err)
			}
		}
	}

	return opt, close, nil

}

var commandDefinition = &cobra.Command{
	Use:   "check source:path dest:path",
	Short: `Checks the files in the source and destination match.`,
	Long: `
Checks the files in the source and destination match.  It compares
sizes and hashes (MD5 or SHA1) and logs a report of files which don't
match.  It doesn't alter the source or destination.

If you supply the --size-only flag, it will only compare the sizes not
the hashes as well.  Use this for a quick check.

If you supply the --download flag, it will download the data from
both remotes and check them against each other on the fly.  This can
be useful for remotes that don't support hashes or if you really want
to check all the data.
` + FlagsHelp,
	Run: func(command *cobra.Command, args []string) {
		cmd.CheckArgs(2, 2, command, args)
		fsrc, fdst := cmd.NewFsSrcDst(args)
		cmd.Run(false, true, command, func() error {
			opt, close, err := GetCheckOpt(fsrc, fdst)
			if err != nil {
				return err
			}
			defer close()
			if download {
				return operations.CheckDownload(context.Background(), opt)
			}
			return operations.Check(context.Background(), opt)
		})
	},
}
<commit_msg>check: add back missing --download flag - fixes #4565<commit_after>package check

import (
	"context"
	"io"
	"os"
	"strings"

	"github.com/rclone/rclone/cmd"
	"github.com/rclone/rclone/fs"
	"github.com/rclone/rclone/fs/config/flags"
	"github.com/rclone/rclone/fs/operations"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
)

// Globals
var (
	download     = false
	oneway       = false
	combined     = ""
	missingOnSrc = ""
	missingOnDst = ""
	match        = ""
	differ       = ""
	errFile      = ""
)

func init() {
	cmd.Root.AddCommand(commandDefinition)
	cmdFlags := commandDefinition.Flags()
	flags.BoolVarP(cmdFlags, &download, "download", "", download, "Check by downloading rather than with hash.")
	AddFlags(cmdFlags)
}

// AddFlags adds the check flags to the cmdFlags command
func AddFlags(cmdFlags *pflag.FlagSet) {
	flags.BoolVarP(cmdFlags, &oneway, "one-way", "", oneway, "Check one way only, source files must exist on remote")
	flags.StringVarP(cmdFlags, &combined, "combined", "", combined, "Make a combined report of changes to this file")
	flags.StringVarP(cmdFlags, &missingOnSrc, "missing-on-src", "", missingOnSrc, "Report all files missing from the source to this file")
	flags.StringVarP(cmdFlags, &missingOnDst, "missing-on-dst", "", missingOnDst, "Report all files missing from the destination to this file")
	flags.StringVarP(cmdFlags, &match, "match", "", match, "Report all matching files to this file")
	flags.StringVarP(cmdFlags, &differ, "differ", "", differ, "Report all non-matching files to this file")
	flags.StringVarP(cmdFlags, &errFile, "error", "", errFile, "Report all files with errors (hashing or reading) to this file")
}

// FlagsHelp describes the flags for the help
var FlagsHelp = strings.Replace(`
If you supply the |--one-way| flag, it will only check that files in
the source match the files in the destination, not the other way
around. This means that extra files in the destination that are not in
the source will not be detected.

The |--differ|, |--missing-on-dst|, |--missing-on-src|, |--src-only|
and |--error| flags write paths, one per line, to the file name (or
stdout if it is |-|) supplied. What they write is described in the
help below. For example |--differ| will write all paths which are
present on both the source and destination but different.

The |--combined| flag will write a file (or stdout) which contains all
file paths with a symbol and then a space and then the path to tell
you what happened to it. These are reminiscent of diff files.

- |= path| means path was found in source and destination and was identical
- |- path| means path was missing on the source, so only in the destination
- |+ path| means path was missing on the destination, so only in the source
- |* path| means path was present in source and destination but different.
- |! path| means there was an error reading or hashing the source or dest.
`, "|", "`", -1)

// GetCheckOpt gets the options corresponding to the check flags
func GetCheckOpt(fsrc, fdst fs.Fs) (opt *operations.CheckOpt, close func(), err error) {
	closers := []io.Closer{}

	opt = &operations.CheckOpt{
		Fsrc:   fsrc,
		Fdst:   fdst,
		OneWay: oneway,
	}

	open := func(name string, pout *io.Writer) error {
		if name == "" {
			return nil
		}
		if name == "-" {
			*pout = os.Stdout
			return nil
		}
		out, err := os.Create(name)
		if err != nil {
			return err
		}
		*pout = out
		closers = append(closers, out)
		return nil
	}

	if err = open(combined, &opt.Combined); err != nil {
		return nil, nil, err
	}
	if err = open(missingOnSrc, &opt.MissingOnSrc); err != nil {
		return nil, nil, err
	}
	if err = open(missingOnDst, &opt.MissingOnDst); err != nil {
		return nil, nil, err
	}
	if err = open(match, &opt.Match); err != nil {
		return nil, nil, err
	}
	if err = open(differ, &opt.Differ); err != nil {
		return nil, nil, err
	}
	if err = open(errFile, &opt.Error); err != nil {
		return nil, nil, err
	}

	close = func() {
		for _, closer := range closers {
			err := closer.Close()
			if err != nil {
				fs.Errorf(nil, "Failed to close report output: %v", err)
			}
		}
	}

	return opt, close, nil

}

var commandDefinition = &cobra.Command{
	Use:   "check source:path dest:path",
	Short: `Checks the files in the source and destination match.`,
	Long: `
Checks the files in the source and destination match.  It compares
sizes and hashes (MD5 or SHA1) and logs a report of files which don't
match.  It doesn't alter the source or destination.

If you supply the --size-only flag, it will only compare the sizes not
the hashes as well.  Use this for a quick check.

If you supply the --download flag, it will download the data from
both remotes and check them against each other on the fly.  This can
be useful for remotes that don't support hashes or if you really want
to check all the data.
` + FlagsHelp,
	Run: func(command *cobra.Command, args []string) {
		cmd.CheckArgs(2, 2, command, args)
		fsrc, fdst := cmd.NewFsSrcDst(args)
		cmd.Run(false, true, command, func() error {
			opt, close, err := GetCheckOpt(fsrc, fdst)
			if err != nil {
				return err
			}
			defer close()
			if download {
				return operations.CheckDownload(context.Background(), opt)
			}
			return operations.Check(context.Background(), opt)
		})
	},
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"database/sql"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"text/template"

	"code.google.com/p/go-uuid/uuid"
	"github.com/mxk/go-sqlite/sqlite3"
	"github.com/rwcarlsen/cyan/post"
	"github.com/rwcarlsen/cyan/query"
)

const MAX_MEMORY = 50 * 1024 * 1024

var resultTmpl = template.Must(template.New("results").Parse(results))

var addr = flag.String("addr", "127.0.0.1:4141", "network address of dispatch server")

func main() {
	flag.Parse()

	http.HandleFunc("/", serveHome)
	http.HandleFunc("/upload", upload)

	err := http.ListenAndServe(*addr, nil)
	if err != nil {
		log.Fatal(err)
	}
}

func serveHome(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte(home))
}

func upload(w http.ResponseWriter, r *http.Request) {
	// parse database from multi part form data
	if err := r.ParseMultipartForm(MAX_MEMORY); err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusForbidden)
		return
	}

	gotDb := false
	fname := uuid.NewRandom().String() + ".sqlite"
	for _, fileHeaders := range r.MultipartForm.File {
		for _, fileHeader := range fileHeaders {
			file, _ := fileHeader.Open()
			data, _ := ioutil.ReadAll(file)
			err := ioutil.WriteFile(fname, data, 0644)
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				log.Print(err)
				return
			}
			defer func() { os.Remove(fname) }()
			gotDb = true
			break
		}
		break
	}
	if !gotDb {
		http.Error(w, "No file provided", http.StatusBadRequest)
		log.Print("received request with no file")
		return
	}

	// post process the database
	conn, err := sqlite3.Open(fname)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Print(err)
		return
	}
	defer conn.Close()

	err = post.Prepare(conn)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Print(err)
		return
	}
	defer post.Finish(conn)

	simids, err := post.GetSimIds(conn)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Print(err)
		return
	}

	ctx := post.NewContext(conn, simids[0], nil)
	if err := ctx.WalkAll(); err != nil {
		log.Println(err)
	}

	// get simid
	db, err := sql.Open("sqlite3", fname)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Print(err)
		return
	}
	defer db.Close()

	ids, err := query.SimIds(db)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Print(err)
		return
	}
	simid := ids[0]
	rs := &Results{}

	// create flow graph
	combineProto := false
	arcs, err := query.FlowGraph(db, simid, 0, -1, combineProto)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Print(err)
		return
	}
	dotname := fname + ".dot"
	dotf, err := os.Create(dotname)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Print(err)
		return
	}
	defer func() { os.Remove(dotname) }()

	fmt.Fprintln(dotf, "digraph ResourceFlows {")
	fmt.Fprintln(dotf, "    overlap = false;")
	fmt.Fprintln(dotf, "    nodesep=1.0;")
	fmt.Fprintln(dotf, "    edge [fontsize=9];")
	for _, arc := range arcs {
		fmt.Fprintf(dotf, "    \"%v\" -> \"%v\" [label=\"%v\\n(%.3g kg)\"];\n", arc.Src, arc.Dst, arc.Commod, arc.Quantity)
	}
	fmt.Fprintln(dotf, "}")
	dotf.Close()

	var buf bytes.Buffer
	cmd := exec.Command("dot", "-Tsvg", dotname)
	cmd.Stdout = &buf
	err = cmd.Run()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Print(err)
		return
	}
	rs.Flowgraph = buf.String()

	// create agents table
	rs.Agents, err = query.AllAgents(db, simid, "")
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Print(err)
		return
	}

	// create Material transactions table
	sql := `
		SELECT TransactionId,Time,SenderId,ReceiverId,tr.ResourceId,Commodity,NucId,MassFrac*Quantity
		FROM Transactions AS tr
		INNER JOIN Resources AS res ON tr.ResourceId = res.ResourceId
		INNER JOIN Compositions AS cmp ON res.QualId = cmp.QualId
		WHERE tr.SimId = ? AND cmp.SimId = res.SimId AND res.SimId = tr.SimId
		AND res.Type = 'Material';
		`
	rows, err := db.Query(sql, simid)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Print(err)
		return
	}

	for rows.Next() {
		t := &Trans{}
		if err := rows.Scan(&t.Id, &t.Time, &t.Sender, &t.Receiver, &t.ResourceId, &t.Commod, &t.Nuc, &t.Qty); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			log.Print(err)
			return
		}
		rs.TransMats = append(rs.TransMats, t)
	}
	if err := rows.Err(); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Print(err)
		return
	}

	// create Material transactions table
	sql = `
		SELECT TransactionId,Time,SenderId,ReceiverId,tr.ResourceId,Commodity,Quality,Quantity
		FROM Transactions AS tr
		INNER JOIN Resources AS res ON tr.ResourceId = res.ResourceId
		INNER JOIN Products AS pd ON res.QualId = pd.QualId
		WHERE tr.SimId = ? AND pd.SimId = res.SimId AND res.SimId = tr.SimId
		AND res.Type = 'Product';
		`
	rows, err = db.Query(sql, simid)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Print(err)
		return
	}

	for rows.Next() {
		t := &ProdTrans{}
		if err := rows.Scan(&t.Id, &t.Time, &t.Sender, &t.Receiver, &t.ResourceId, &t.Commod, &t.Quality, &t.Qty); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			log.Print(err)
			return
		}
		rs.TransProds = append(rs.TransProds, t)
	}
	if err := rows.Err(); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Print(err)
		return
	}

	// render all rsults
	resultTmpl.Execute(w, rs)
}

type ProdTrans struct {
	Id         int
	Time       int
	Sender     int
	Receiver   int
	ResourceId int
	Commod     string
	Quality    string
	Qty        float64
}

type Trans struct {
	Id         int
	Time       int
	Sender     int
	Receiver   int
	ResourceId int
	Commod     string
	Nuc        int
	Qty        float64
}

type Results struct {
	Flowgraph  string
	Agents     []query.AgentInfo
	TransMats  []*Trans
	TransProds []*ProdTrans
}

//<input type="hidden" name="redirect" value="/analysis" />

const home = `

	<meta charset="UTF-8"/>

Cyclus Data Viewer

	<form action="/upload" method="POST" enctype="multipart/form-data">

		Cyclus Sqlite Database:
		<input name="file" type="file"></input>
		<input type="submit"></input>

	</form>

`

const results = `

	<title>Cyclus Database Viewer</title>
	<meta charset="UTF-8"/>

Resource Flow

	{{.Flowgraph}}

Agents Table

ID	Kind	Spec	Prototype	ParentId	Lifetime	EnterTime	ExitTime

		{{ range .Agents}}

			{{ .Id }}
			{{ .Kind }}
			{{ .Impl }}
			{{ .Proto }}
			{{ .Parent }}
			{{ .Lifetime }}
			{{ .Enter }}
			{{ .Exit }}

		{{ end }}

Material Transactions Table

ID	Time	Sender	Receiver	ResourceId	Commod	Nuclide	Quantity (kg)

		{{ range .TransMats}}

			{{ .Id }}
			{{ .Time }}
			{{ .Sender }}
			{{ .Receiver }}
			{{ .ResourceId }}
			{{ .Commod }}
			{{ .Nuc }}
			{{ .Qty }}

		{{ end }}

Product Transactions Table

ID	Time	Sender	Receiver	ResourceId	Commod	Quality	Quantity

		{{ range .TransProds}}

			{{ .Id }}
			{{ .Time }}
			{{ .Sender }}
			{{ .Receiver }}
			{{ .ResourceId }}
			{{ .Commod }}
			{{ .Quality }}
			{{ .Qty }}

		{{ end }}

`
<commit_msg>added ability to store html pages and retrieve them later<commit_after>package main

import (
	"bytes"
	"database/sql"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"text/template"

	"code.google.com/p/go-uuid/uuid"
	"github.com/mxk/go-sqlite/sqlite3"
	"github.com/rwcarlsen/cyan/post"
	"github.com/rwcarlsen/cyan/query"
)

const MAX_MEMORY = 50 * 1024 * 1024

var resultTmpl = template.Must(template.New("results").Parse(results))
var homeTmpl = template.Must(template.New("home").Parse(home))

var addr = flag.String("addr", "127.0.0.1:4141", "network address of dispatch server")

func main() {
	flag.Parse()

	http.HandleFunc("/", serveHome)
	http.HandleFunc("/upload/", upload)
	http.HandleFunc("/share/", share)

	err := http.ListenAndServe(*addr, nil)
	if err != nil {
		log.Fatal(err)
	}
}

func serveHome(w http.ResponseWriter, r *http.Request) {
	uid := uuid.NewRandom().String()
	homeTmpl.Execute(w, uid)
}

func share(w http.ResponseWriter, r *http.Request) {
	uid := r.URL.Path[len("/share/"):]
	fname := uid + ".html"
	data, err := ioutil.ReadFile(fname)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Print(err)
		return
	}
	w.Write(data)
}

func upload(w http.ResponseWriter, r *http.Request) {
	// parse database from multi part form data
	if err := r.ParseMultipartForm(MAX_MEMORY); err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusForbidden)
		return
	}

	gotDb := false
	uid := r.URL.Path[len("/upload/"):]
	fname := uid + ".sqlite"
	for _, fileHeaders := range r.MultipartForm.File {
		for _, fileHeader := range fileHeaders {
			file, _ := fileHeader.Open()
			data, _ := ioutil.ReadAll(file)
			err := ioutil.WriteFile(fname, data, 0644)
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				log.Print(err)
				return
			}
			defer func() { os.Remove(fname) }()
			gotDb = true
			break
		}
		break
	}
	if !gotDb {
		http.Error(w, "No file provided", http.StatusBadRequest)
		log.Print("received request with no file")
		return
	}

	// post process the database
	conn, err := sqlite3.Open(fname)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Print(err)
		return
	}
	defer conn.Close()

	err = post.Prepare(conn)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Print(err)
		return
	}
	defer post.Finish(conn)

	simids, err := post.GetSimIds(conn)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Print(err)
		return
	}

	ctx := post.NewContext(conn, simids[0], nil)
	if err := ctx.WalkAll(); err != nil {
		log.Println(err)
	}

	// get simid
	db, err := sql.Open("sqlite3", fname)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Print(err)
		return
	}
	defer db.Close()

	ids, err := query.SimIds(db)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Print(err)
		return
	}
	simid := ids[0]
	rs := &Results{}

	// create flow graph
	combineProto := false
	arcs, err := query.FlowGraph(db, simid, 0, -1, combineProto)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Print(err)
		return
	}
	dotname := fname + ".dot"
	dotf, err := os.Create(dotname)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Print(err)
		return
	}
	defer func() { os.Remove(dotname) }()

	fmt.Fprintln(dotf, "digraph ResourceFlows {")
	fmt.Fprintln(dotf, "    overlap = false;")
	fmt.Fprintln(dotf, "    nodesep=1.0;")
	fmt.Fprintln(dotf, "    edge [fontsize=9];")
	for _, arc := range arcs {
		fmt.Fprintf(dotf, "    \"%v\" -> \"%v\" [label=\"%v\\n(%.3g kg)\"];\n", arc.Src, arc.Dst, arc.Commod, arc.Quantity)
	}
	fmt.Fprintln(dotf, "}")
	dotf.Close()

	var buf bytes.Buffer
	cmd := exec.Command("dot", "-Tsvg", dotname)
	cmd.Stdout = &buf
	err = cmd.Run()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Print(err)
		return
	}
	rs.Flowgraph = buf.String()

	// create agents table
	rs.Agents, err = query.AllAgents(db, simid, "")
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Print(err)
		return
	}

	// create Material transactions table
	sql := `
		SELECT TransactionId,Time,SenderId,ReceiverId,tr.ResourceId,Commodity,NucId,MassFrac*Quantity
		FROM Transactions AS tr
		INNER JOIN Resources AS res ON tr.ResourceId = res.ResourceId
		INNER JOIN Compositions AS cmp ON res.QualId = cmp.QualId
		WHERE tr.SimId = ? AND cmp.SimId = res.SimId AND res.SimId = tr.SimId
		AND res.Type = 'Material';
		`
	rows, err := db.Query(sql, simid)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Print(err)
		return
	}

	for rows.Next() {
		t := &Trans{}
		if err := rows.Scan(&t.Id, &t.Time, &t.Sender, &t.Receiver, &t.ResourceId, &t.Commod, &t.Nuc, &t.Qty); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			log.Print(err)
			return
		}
		rs.TransMats = append(rs.TransMats, t)
	}
	if err := rows.Err(); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Print(err)
		return
	}

	// create Material transactions table
	sql = `
		SELECT TransactionId,Time,SenderId,ReceiverId,tr.ResourceId,Commodity,Quality,Quantity
		FROM Transactions AS tr
		INNER JOIN Resources AS res ON tr.ResourceId = res.ResourceId
		INNER JOIN Products AS pd ON res.QualId = pd.QualId
		WHERE tr.SimId = ? AND pd.SimId = res.SimId AND res.SimId = tr.SimId
		AND res.Type = 'Product';
		`
	rows, err = db.Query(sql, simid)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Print(err)
		return
	}

	for rows.Next() {
		t := &ProdTrans{}
		if err := rows.Scan(&t.Id, &t.Time, &t.Sender, &t.Receiver, &t.ResourceId, &t.Commod, &t.Quality, &t.Qty); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			log.Print(err)
			return
		}
		rs.TransProds = append(rs.TransProds, t)
	}
	if err := rows.Err(); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Print(err)
		return
	}

	// render all results and save page
	resultTmpl.Execute(w, rs)

	f, err := os.Create(uid + ".html")
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Print(err)
		return
	}
	defer f.Close()
	resultTmpl.Execute(f, rs)
}

type ProdTrans struct {
	Id         int
	Time       int
	Sender     int
	Receiver   int
	ResourceId int
	Commod     string
	Quality    string
	Qty        float64
}

type Trans struct {
	Id         int
	Time       int
	Sender     int
	Receiver   int
	ResourceId int
	Commod     string
	Nuc        int
	Qty        float64
}

type Results struct {
	Flowgraph  string
	Agents     []query.AgentInfo
	TransMats  []*Trans
	TransProds []*ProdTrans
}

//<input type="hidden" name="redirect" value="/analysis" />

const home = `

	<meta charset="UTF-8"/>

Cyclus Data Viewer

	<form action="/upload/{{.}}" method="POST" enctype="multipart/form-data">
		Cyclus Sqlite Database:
		<input name="file" type="file"></input>
		<input type="submit"></input>
	</form>

`

const results = `

	<title>Cyclus Database Viewer</title>
	<meta charset="UTF-8"/>

Resource Flow

	{{.Flowgraph}}

Agents Table

ID	Kind	Spec	Prototype	ParentId	Lifetime	EnterTime	ExitTime

		{{ range .Agents}}

			{{ .Id }}
			{{ .Kind }}
			{{ .Impl }}
			{{ .Proto }}
			{{ .Parent }}
			{{ .Lifetime }}
			{{ .Enter }}
			{{ .Exit }}

		{{ end }}

Material Transactions Table

ID	Time	Sender	Receiver	ResourceId	Commod	Nuclide	Quantity (kg)

		{{ range .TransMats}}

			{{ .Id }}
			{{ .Time }}
			{{ .Sender }}
			{{ .Receiver }}
			{{ .ResourceId }}
			{{ .Commod }}
			{{ .Nuc }}
			{{ .Qty }}

		{{ end }}

Product Transactions Table

ID	Time	Sender	Receiver	ResourceId	Commod	Quality	Quantity

		{{ range .TransProds}}

			{{ .Id }}
			{{ .Time }}
			{{ .Sender }}
			{{ .Receiver }}
			{{ .ResourceId }}
			{{ .Commod }}
			{{ .Quality }}
			{{ .Qty }}

		{{ end }}

`
<|endoftext|>


<commit_before>package main

import (
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/gomarkdown/markdown"
	"github.com/mkaz/hastie/pkg/utils"
)

/* ************************************************
 * Read and Parse File
 * ************************************************ */
func readParseFile(filename string) (page Page) {
	log.Debug("Parsing File:", filename)
	epoch, _ := time.Parse("20060102", "19700101")

	// setup default page struct
	page = Page{
		Date:      epoch,
		OutFile:   filename,
		Extension: ".html",
		Params:    make(map[string]string),
	}

	// read file
	var data, err = ioutil.ReadFile(filename)
	if err != nil {
		log.Warn("Error Reading: " + filename)
		return
	}

	// go through content parse frontmatter
	// params from --- to ---
	var lines = strings.Split(string(data), "\n")
	var found = 0
	for i, line := range lines {
		line = strings.TrimSpace(line)

		if found == 1 {
			// parse line for param
			colonIndex := strings.Index(line, ":")
			if colonIndex > 0 {
				key := strings.ToLower(strings.TrimSpace(line[:colonIndex]))
				value := strings.TrimSpace(line[colonIndex+1:])
				value = strings.Trim(value, "\"") //remove quotes
				switch key {
				case "title":
					page.Title = value
				case "category":
					page.Category = value
				case "layout":
					page.Layout = value
				case "extension":
					page.Extension = "." + value
				case "date":
					page.Date, _ = time.Parse("2006-01-02", value[0:10])
				default:
					page.Params[key] = value
				}
			}

		} else if found >= 2 {
			// frontmatter over
			// slurp up the rest
			lines = lines[i:]
			break
		}

		if line == "---" {
			found++
		}

	}

	// chop off first directory, since that is the template dir
	log.Debug("Filename", filename)
	page.OutFile = filename[strings.Index(filename, string(os.PathSeparator))+1:]
	page.OutFile = strings.Replace(page.OutFile, ".md", page.Extension, 1)
	log.Debug("page.Outfile", page.OutFile)

	// next directory(s) category, category includes sub-dir = solog/webdev
	if page.Category == "" {
		if strings.Contains(page.OutFile, string(os.PathSeparator)) {
			page.Category = page.OutFile[0:strings.LastIndex(page.OutFile, string(os.PathSeparator))]
			page.SimpleCategory = strings.Replace(page.Category, string(os.PathSeparator), "_", -1)
		}
	}
	log.Debug("page.Category", page.Category)
	// parse date from filename
	base := filepath.Base(page.OutFile)
	if base[0:2] == "20" || base[0:2] == "19" { //HACK: if file starts with 20 or 19 assume date
		page.Date, _ = time.Parse("2006-01-02", base[0:10])
		page.OutFile = strings.Replace(page.OutFile, base[0:11], "", 1) // remove date from final filename
	}

	// add url of page, which includes initial slash
	// this is needed to get correct links for multi
	// level directories

	page.Url = "/" + utils.RemoveIndexHTML(page.OutFile)

	// convert markdown content
	content := strings.Join(lines, "\n")
	if (config.UseMarkdown) && (page.Params["markdown"] != "no") {
		output := markdown.ToHTML([]byte(content), nil, nil)
		page.Content = string(output)
	} else {
		page.Content = content
	}

	return page
}
<commit_msg>Rebase<commit_after>package main

import (
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/gomarkdown/markdown"
	"github.com/mkaz/hastie/pkg/utils"
)

/* ************************************************
 * Read and Parse File
 * ************************************************ */
func readParseFile(filename string) (page Page) {
	log.Debug("Parsing File:", filename)
	epoch, _ := time.Parse("20060102", "19700101")

	// setup default page struct
	page = Page{
		Date:      epoch,
		OutFile:   filename,
		Extension: ".html",
		Params:    make(map[string]string),
	}

	// read file
	var data, err = ioutil.ReadFile(filename)
	if err != nil {
		log.Warn("Error Reading: " + filename)
		return
	}

	// go through content parse frontmatter
	// params from --- to ---
	var lines = strings.Split(string(data), "\n")
	var found = 0
	for i, line := range lines {
		line = strings.TrimSpace(line)

		if found == 1 {
			// parse line for param
			colonIndex := strings.Index(line, ":")
			if colonIndex > 0 {
				key := strings.ToLower(strings.TrimSpace(line[:colonIndex]))
				value := strings.TrimSpace(line[colonIndex+1:])
				value = strings.Trim(value, "\"") //remove quotes
				switch key {
				case "title":
					page.Title = value
				case "category":
					page.Category = value
				case "layout":
					page.Layout = value
				case "extension":
					page.Extension = "." + value
				case "date":
					page.Date, _ = time.Parse("2006-01-02", value[0:10])
				default:
					page.Params[key] = value
				}
			}

		} else if found >= 2 {
			// frontmatter over
			// slurp up the rest
			lines = lines[i:]
			break
		}

		if line == "---" {
			found++
		}

	}

	// generate the public-file's path based on the source-file's path
	log.Debug("Filename", filename)
	page.OutFile = filename[strings.Index(filename, config.SourceDir)+len(config.SourceDir):]
	page.OutFile = strings.Replace(page.OutFile, ".md", page.Extension, 1)
	log.Debug("page.Outfile", page.OutFile)

	// next directory(s) category, category includes sub-dir = solog/webdev
	if page.Category == "" {
		if strings.Contains(page.OutFile, string(os.PathSeparator)) {
			page.Category = page.OutFile[0:strings.LastIndex(page.OutFile, string(os.PathSeparator))]
			page.SimpleCategory = strings.Replace(page.Category, string(os.PathSeparator), "_", -1)
		}
	}
	log.Debug("page.Category", page.Category)
	// parse date from filename
	base := filepath.Base(page.OutFile)
	if base[0:2] == "20" || base[0:2] == "19" { //HACK: if file starts with 20 or 19 assume date
		page.Date, _ = time.Parse("2006-01-02", base[0:10])
		page.OutFile = strings.Replace(page.OutFile, base[0:11], "", 1) // remove date from final filename
	}

	// add url of page, which includes initial slash
	// this is needed to get correct links for multi
	// level directories

	page.Url = "/" + utils.RemoveIndexHTML(page.OutFile)

	// convert markdown content
	content := strings.Join(lines, "\n")
	if (config.UseMarkdown) && (page.Params["markdown"] != "no") {
		output := markdown.ToHTML([]byte(content), nil, nil)
		page.Content = string(output)
	} else {
		page.Content = content
	}

	return page
}
<|endoftext|>


<commit_before>// A "simple" program to display some text and let the
// user drag it around. It will get simpler...
package main

import (
	"rog-go.googlecode.com/hg/x11"
	"exp/draw"
	"log"
	"image"
	"io/ioutil"
	"os"
	"rog-go.googlecode.com/hg/canvas"
	"freetype-go.googlecode.com/hg/freetype/truetype"
)

var cvs *canvas.Canvas

func main() {
	ctxt, err := x11.NewWindow()
	if ctxt == nil {
		log.Exitf("no window: %v", err)
	}
	screen := ctxt.Screen()

	bg := canvas.NewBackground(screen.(*image.RGBA), draw.White, flushFunc(ctxt))
	cvs = canvas.NewCanvas(bg, nil, draw.Rect(0, 0, bg.Width(), bg.Height()))
	bg.SetItem(cvs)

	item := canvas.Draggable(
		canvas.NewText(
			draw.Pt(cvs.Width()/2, cvs.Height()/3),
			0,
			"Hello, world",
			defaultFont(),
			30,
			nil))
	cvs.AddItem(item)

	qc := ctxt.QuitChan()
	kc := ctxt.KeyboardChan()
	mc := ctxt.MouseChan()
	cvs.Flush()

	for {
		select {
		case <-qc:
			log.Exit("quitting")
			return
		case m := <-mc:
			if m.Buttons == 0 {
				break
			}
			cvs.HandleMouse(cvs, m, mc)
		case <-kc:
		}
	}
}

func defaultFont() *truetype.Font {
	goroot := os.Getenv("GOROOT")
	if goroot == "" {
		log.Exit("no goroot set")
	}
	path := goroot + "/src/pkg/freetype-go.googlecode.com/hg/luxi-fonts/luxisr.ttf"
	// Read the font data.
	fontBytes, err := ioutil.ReadFile(path)
	if err != nil {
		log.Exit(err)
	}
	font, err := truetype.Parse(fontBytes)
	if err != nil {
		log.Exit(err)
	}
	return font
}

// this will go.
type RectFlusherContext interface {
	draw.Context
	FlushImageRect(r draw.Rectangle)
}
func flushFunc(ctxt draw.Context) func(r draw.Rectangle) {
	if fctxt, ok := ctxt.(RectFlusherContext); ok {
		return func(r draw.Rectangle) {
			fctxt.FlushImageRect(r)
		}
	}
	return func(_ draw.Rectangle) {
		ctxt.FlushImage()
	}
}
<commit_msg>fix hello<commit_after>// A "simple" program to display some text and let the
// user drag it around. It will get simpler...
package main

import (
	"rog-go.googlecode.com/hg/x11"
	"exp/draw"
	"log"
	"image"
	"io/ioutil"
	"os"
	"rog-go.googlecode.com/hg/canvas"
	"freetype-go.googlecode.com/hg/freetype/truetype"
)

var cvs *canvas.Canvas

func main() {
	ctxt, err := x11.NewWindow()
	if ctxt == nil {
		log.Exitf("no window: %v", err)
	}
	screen := ctxt.Screen()

	bg := canvas.NewBackground(screen.(*image.RGBA), draw.White, flushFunc(ctxt))
	cvs = canvas.NewCanvas(nil, draw.Rect(0, 0, bg.Width(), bg.Height()))
	bg.SetItem(cvs)

	item := canvas.Draggable(
		canvas.NewText(
			draw.Pt(cvs.Width()/2, cvs.Height()/3),
			0,
			"Hello, world",
			defaultFont(),
			30,
			nil))
	cvs.AddItem(item)

	qc := ctxt.QuitChan()
	kc := ctxt.KeyboardChan()
	mc := ctxt.MouseChan()
	cvs.Flush()

	for {
		select {
		case <-qc:
			log.Exit("quitting")
			return
		case m := <-mc:
			if m.Buttons == 0 {
				break
			}
			cvs.HandleMouse(cvs, m, mc)
		case <-kc:
		}
	}
}

func defaultFont() *truetype.Font {
	goroot := os.Getenv("GOROOT")
	if goroot == "" {
		log.Exit("no goroot set")
	}
	path := goroot + "/src/pkg/freetype-go.googlecode.com/hg/luxi-fonts/luxisr.ttf"
	// Read the font data.
	fontBytes, err := ioutil.ReadFile(path)
	if err != nil {
		log.Exit(err)
	}
	font, err := truetype.Parse(fontBytes)
	if err != nil {
		log.Exit(err)
	}
	return font
}

// this will go.
type RectFlusherContext interface {
	draw.Context
	FlushImageRect(r draw.Rectangle)
}
func flushFunc(ctxt draw.Context) func(r draw.Rectangle) {
	if fctxt, ok := ctxt.(RectFlusherContext); ok {
		return func(r draw.Rectangle) {
			fctxt.FlushImageRect(r)
		}
	}
	return func(_ draw.Rectangle) {
		ctxt.FlushImage()
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"

	"github.com/ogier/pflag"
)

const (
	lzmaExt  = ".lzma"
	usageStr = `Usage: lzmago [OPTION]... [FILE]...
Compress or uncompress FILEs in the .lzma format (by default, compress FILES
in place).

  -c, --stdout      write to standard output and don't delete input files
  -d, --decompress  force decompression
  -f, --force       force overwrite of output file and compress links
  -h, --help        give this help
  -k, --keep        keep (don't delete) input files
  -L, --license     display software license
  -q, --quiet       suppress all warnings
  -v, --verbose     verbose mode
  -V, --version     display version string
  -z, --compress    force compression
  -0 ... -9         compression preset; default is 6

With no file, or when FILE is -, read standard input.

Report bugs using <https://github.com/uli-go/xz/issues>.
`
)

type V int

const defaultSpeed V = 6

func (v *V) filterArg(arg string) string {
	if len(arg) < 2 || arg[0] != '-' || arg[1] == '-' {
		return arg
	}
	buf := new(bytes.Buffer)
	buf.Grow(len(arg))
	for _, c := range arg {
		if '0' <= c && c <= '9' {
			*v = V(c - '0')
			continue
		}
		buf.WriteRune(c)
	}
	return buf.String()
}

func (v *V) filter() {
	args := make([]string, 1, len(os.Args))
	args[0] = os.Args[0]
	for i, arg := range os.Args[1:] {
		if arg == "--" {
			args = append(args, os.Args[1+i:]...)
			break

		}
		n := v.filterArg(arg)
		if n != "-" {
			args = append(args, v.filterArg(arg))
		}
	}
	os.Args = args
}

func usage(w io.Writer) {
	fmt.Fprint(w, usageStr)
}

func main() {
	// initialization
	cmdName := filepath.Base(os.Args[0])
	pflag.CommandLine = pflag.NewFlagSet(cmdName, pflag.ExitOnError)
	pflag.SetInterspersed(true)
	pflag.Usage = func() { usage(os.Stderr); os.Exit(1) }
	log.SetPrefix(fmt.Sprintf("%s: ", cmdName))
	log.SetFlags(0)

	var (
		help  = pflag.BoolP("help", "h", false, "")
		speed = defaultSpeed
	)

	speed.filter()
	log.Printf("filtered args %v", os.Args)
	pflag.Parse()

	if *help {
		usage(os.Stdout)
		os.Exit(0)
	}

	log.Printf("speed %d", speed)
}
<commit_msg>lzmago: fix double call of filter<commit_after>package main

import (
	"bytes"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"

	"github.com/ogier/pflag"
)

const (
	lzmaExt  = ".lzma"
	usageStr = `Usage: lzmago [OPTION]... [FILE]...
Compress or uncompress FILEs in the .lzma format (by default, compress FILES
in place).

  -c, --stdout      write to standard output and don't delete input files
  -d, --decompress  force decompression
  -f, --force       force overwrite of output file and compress links
  -h, --help        give this help
  -k, --keep        keep (don't delete) input files
  -L, --license     display software license
  -q, --quiet       suppress all warnings
  -v, --verbose     verbose mode
  -V, --version     display version string
  -z, --compress    force compression
  -0 ... -9         compression preset; default is 6

With no file, or when FILE is -, read standard input.

Report bugs using <https://github.com/uli-go/xz/issues>.
`
)

type V int

const defaultSpeed V = 6

func (v *V) filterArg(arg string) string {
	if len(arg) < 2 || arg[0] != '-' || arg[1] == '-' {
		return arg
	}
	buf := new(bytes.Buffer)
	buf.Grow(len(arg))
	for _, c := range arg {
		if '0' <= c && c <= '9' {
			*v = V(c - '0')
			continue
		}
		buf.WriteRune(c)
	}
	return buf.String()
}

func (v *V) filter() {
	args := make([]string, 1, len(os.Args))
	args[0] = os.Args[0]
	for i, arg := range os.Args[1:] {
		if arg == "--" {
			args = append(args, os.Args[1+i:]...)
			break

		}
		arg = v.filterArg(arg)
		if arg != "-" {
			args = append(args, arg)
		}
	}
	os.Args = args
}

func usage(w io.Writer) {
	fmt.Fprint(w, usageStr)
}

func main() {
	// initialization
	cmdName := filepath.Base(os.Args[0])
	pflag.CommandLine = pflag.NewFlagSet(cmdName, pflag.ExitOnError)
	pflag.SetInterspersed(true)
	pflag.Usage = func() { usage(os.Stderr); os.Exit(1) }
	log.SetPrefix(fmt.Sprintf("%s: ", cmdName))
	log.SetFlags(0)

	var (
		help  = pflag.BoolP("help", "h", false, "")
		speed = defaultSpeed
	)

	speed.filter()
	log.Printf("filtered args %v", os.Args)
	pflag.Parse()

	if *help {
		usage(os.Stdout)
		os.Exit(0)
	}

	log.Printf("speed %d", speed)
}
<|endoftext|>


<commit_before>// Copyright 2017 The nem-toolchain project authors. All rights reserved.
// Use of this source code is governed by a MIT license that can be found in the LICENSE file.

package main

import (
	"bufio"
	"encoding/hex"
	"fmt"
	"io/ioutil"
	"math"
	"os"
	"runtime"
	"strings"
	"time"

	"github.com/nem-toolchain/nem-toolchain/pkg/core"
	"github.com/nem-toolchain/nem-toolchain/pkg/keypair"
	"github.com/nem-toolchain/nem-toolchain/pkg/vanity"
	"github.com/urfave/cli"
)

func accountCommand() cli.Command {
	return cli.Command{
		Name:  "account",
		Usage: "Account related bundle of actions",
		Subcommands: []cli.Command{
			{
				Name:   "generate",
				Usage:  "Generate a new account",
				Action: generateAction,
				Flags: []cli.Flag{
					cli.UintFlag{
						Name:  "number, n",
						Usage: "Number of generated accounts",
						Value: 1,
					},
					cli.BoolFlag{
						Name:  "strip, s",
						Usage: "Strip output to private key only",
					},
				},
			},
			{
				Name:   "info",
				Usage:  "Show info for given account",
				Action: infoAction,
				Flags: []cli.Flag{
					cli.BoolFlag{
						Name:  "address",
						Usage: "Show public address only for given private key",
					},
					cli.BoolFlag{
						Name:  "public",
						Usage: "Show public key only for given private key",
					},
				},
			},
			{
				Name:   "vanity",
				Usage:  "Find vanity address by a given list of prefixes",
				Action: vanityAction,
				Flags: []cli.Flag{
					cli.UintFlag{
						Name:  "number, n",
						Usage: "Number of generated accounts",
						Value: 1,
					},
					cli.BoolFlag{
						Name:  "strip, s",
						Usage: "Strip output to private key only",
					},
					cli.UintFlag{
						Name:  "workers, w",
						Usage: "Number of workers for generation",
						Value: uint(runtime.NumCPU()),
					},
					cli.BoolFlag{
						Name:  "show-complexity",
						Usage: "Show additionally the specified search complexity",
					},
					cli.BoolFlag{
						Name:  "skip-estimate",
						Usage: "Skip the step to calculate estimation times to search",
					},
					cli.BoolFlag{
						Name:  "no-digits",
						Usage: "Digits in address are disallow ('234567')",
					},
					cli.StringFlag{
						Name:  "exclude",
						Usage: "Characters that must not be in the address",
					},
				},
			},
		},
	}
}

func generateAction(c *cli.Context) error {
	ch, err := chainGlobalOption(c)
	if err != nil {
		return cli.NewExitError(err.Error(), 1)
	}

	num := c.Uint("number")
	for i := uint(0); i < num; i++ {
		pair := keypair.Gen()
		if c.Bool("strip") {
			printlnPrivateKey(pair, true)
		} else {
			printAccountDetails(ch, pair)
		}
	}

	return nil
}

func infoAction(c *cli.Context) error {
	ch, err := chainGlobalOption(c)
	if err != nil {
		return cli.NewExitError(err.Error(), 1)
	}

	fi, err := os.Stdin.Stat()
	if err != nil {
		return cli.NewExitError(err.Error(), 1)
	}

	var privKeys []string
	if (fi.Mode()&os.ModeCharDevice) != 0 && fi.Size() == 0 {
		fmt.Print("Enter private key: ")
		rd := bufio.NewReader(os.Stdin)
		val, err := rd.ReadString('\n')
		if err != nil {
			return cli.NewExitError(err.Error(), 1)
		}
		privKeys = []string{val}
	} else {
		data, err := ioutil.ReadAll(os.Stdin)
		if err != nil {
			return cli.NewExitError(err.Error(), 1)
		}
		privKeys = strings.Split(string(data), "\n")
		privKeys = privKeys[:len(privKeys)-1]
	}

	for _, s := range privKeys {
		pk, err := hex.DecodeString(strings.TrimSpace(s))
		if err != nil {
			return cli.NewExitError(err.Error(), 1)
		}

		pair, err := keypair.FromSeed(pk)
		if err != nil {
			return cli.NewExitError(err.Error(), 1)
		}

		if c.Bool("address") {
			printlnAddress(ch, pair, true)
		} else if c.Bool("public") {
			printlnPublicKey(pair, true)
		} else {
			printAccountDetails(ch, pair)
		}
	}

	return nil
}

func vanityAction(c *cli.Context) error {
	ch, err := chainGlobalOption(c)
	if err != nil {
		return cli.NewExitError(err.Error(), 1)
	}

	num := c.Uint("number")
	if num == 0 {
		return nil
	}

	workers := c.Uint("workers")
	if m := uint(runtime.NumCPU()); workers == 0 || workers > m {
		workers = m
	}

	var excludeSel vanity.Selector = vanity.TrueSelector{}
	if c.IsSet("exclude") {
		excludeSel, err = vanity.NewExcludeSelector(c.String("exclude"))
		if err != nil {
			return cli.NewExitError(err.Error(), 1)
		}
	}

	var noDigitsSel vanity.Selector = vanity.TrueSelector{}
	if c.Bool("no-digits") {
		noDigitsSel, _ = vanity.NewExcludeSelector("234567")
	}

	prefixes := make([]vanity.Selector, len(c.Args()))
	for i, pr := range c.Args() {
		sel, err := vanity.NewPrefixSelector(ch, strings.ToUpper(pr))
		if err != nil {
			return cli.NewExitError(err.Error(), 1)
		}
		prefixes[i] = sel
	}

	sel := vanity.AndSelector(
		excludeSel, noDigitsSel, vanity.OrSelector(prefixes...))

	if !c.Bool("strip") && !c.Bool("skip-estimate") {
		printEstimate(workers,
			vanity.Probability(sel)/float64(num), c.Bool("show-complexity"))
	}

	rs := make(chan keypair.KeyPair)
	for i := uint(0); i < workers; i++ {
		go vanity.StartSearch(ch, sel, rs)
	}

	for i := uint(0); i < num; i++ {
		pair := <-rs
		if c.Bool("strip") {
			printlnPrivateKey(pair, true)
		} else {
			printAccountDetails(ch, pair)
		}
		go vanity.StartSearch(ch, sel, rs)
	}

	return nil
}

// printEstimate prints vanity account search time estimate
func printEstimate(workers uint, pbty float64, cplx bool) {
	fmt.Print("Calculate accounts rate")
	ticker := time.NewTicker(time.Second)
	go func() {
		for range ticker.C {
			fmt.Print(".")
		}
	}()
	rate := countActualRate(workers)
	ticker.Stop()
	fmt.Printf(" %v accounts/sec\n", math.Trunc(rate))
	printEstimateDetails(pbty, rate, cplx)
}

// countActualRate counts total number of generated keypairs per second
func countActualRate(workers uint) float64 {
	res := make(chan int, workers)
	for i := 0; i < cap(res); i++ {
		go countKeyPairs(3200, res)
	}
	rate := float64(0)
	for i := 0; i < cap(res); i++ {
		rate += float64(<-res) / 3.2
	}
	return rate
}

// countKeyPairs counts number of generated keypairs for specified interval
func countKeyPairs(milliseconds time.Duration, res chan int) {
	timeout := time.After(time.Millisecond * milliseconds)
	for count := 0; ; count++ {
		keypair.Gen().Address(core.Mainnet)
		select {
		case <-timeout:
			res <- count
			return
		default:
			continue
		}
	}
}

// printEstimateDetails prints estimate search time details
func printEstimateDetails(pbty, rate float64, cplx bool) {
	if cplx {
		fmt.Printf("Specified search complexity: %v\n", math.Trunc(1.0/pbty))
	}
	fmt.Printf("Estimate search times: %v (50%%), %v (80%%), %v (99.9%%)\n",
		timeInSeconds(vanity.NumberOfAttempts(pbty, 0.5)/rate),
		timeInSeconds(vanity.NumberOfAttempts(pbty, 0.8)/rate),
		timeInSeconds(vanity.NumberOfAttempts(pbty, 0.99)/rate))
}

// timeInSeconds formats estimated time
func timeInSeconds(val float64) string {
	val = 1e9 * math.Trunc(val)
	if val >= math.MaxInt64 || math.IsInf(val, 0) {
		return "Inf"
	}
	return time.Duration(val).String()
}

// printAccountDetails prints account details in pretty user-oriented multi-line format
func printAccountDetails(chain core.Chain, pair keypair.KeyPair) {
	fmt.Println("----")
	printlnAddress(chain, pair, false)
	printlnPublicKey(pair, false)
	printlnPrivateKey(pair, false)
}

func printlnPrivateKey(pair keypair.KeyPair, strip bool) {
	printlnCustom("Private key: ", hex.EncodeToString(pair.Private), strip)
}

func printlnPublicKey(pair keypair.KeyPair, strip bool) {
	printlnCustom("Public key: ", hex.EncodeToString(pair.Public), strip)
}

func printlnAddress(chain core.Chain, pair keypair.KeyPair, strip bool) {
	printlnCustom("Address: ", pair.Address(chain).PrettyString(), strip)
}

func printlnCustom(title, value string, strip bool) {
	if !strip {
		fmt.Print(title)
	}
	fmt.Println(value)
}
<commit_msg>Interactive mode for `account info` is unnecessary<commit_after>// Copyright 2017 The nem-toolchain project authors. All rights reserved.
// Use of this source code is governed by a MIT license that can be found in the LICENSE file.

package main

import (
	"encoding/hex"
	"fmt"
	"io/ioutil"
	"math"
	"os"
	"runtime"
	"strings"
	"time"

	"github.com/nem-toolchain/nem-toolchain/pkg/core"
	"github.com/nem-toolchain/nem-toolchain/pkg/keypair"
	"github.com/nem-toolchain/nem-toolchain/pkg/vanity"
	"github.com/urfave/cli"
)

func accountCommand() cli.Command {
	return cli.Command{
		Name:  "account",
		Usage: "Account related bundle of actions",
		Subcommands: []cli.Command{
			{
				Name:   "generate",
				Usage:  "Generate a new account",
				Action: generateAction,
				Flags: []cli.Flag{
					cli.UintFlag{
						Name:  "number, n",
						Usage: "Number of generated accounts",
						Value: 1,
					},
					cli.BoolFlag{
						Name:  "strip, s",
						Usage: "Strip output to private key only",
					},
				},
			},
			{
				Name:   "info",
				Usage:  "Show info for given account",
				Action: infoAction,
				Flags: []cli.Flag{
					cli.BoolFlag{
						Name:  "address",
						Usage: "Show public address only for given private key",
					},
					cli.BoolFlag{
						Name:  "public",
						Usage: "Show public key only for given private key",
					},
				},
			},
			{
				Name:   "vanity",
				Usage:  "Find vanity address by a given list of prefixes",
				Action: vanityAction,
				Flags: []cli.Flag{
					cli.UintFlag{
						Name:  "number, n",
						Usage: "Number of generated accounts",
						Value: 1,
					},
					cli.BoolFlag{
						Name:  "strip, s",
						Usage: "Strip output to private key only",
					},
					cli.UintFlag{
						Name:  "workers, w",
						Usage: "Number of workers for generation",
						Value: uint(runtime.NumCPU()),
					},
					cli.BoolFlag{
						Name:  "show-complexity",
						Usage: "Show additionally the specified search complexity",
					},
					cli.BoolFlag{
						Name:  "skip-estimate",
						Usage: "Skip the step to calculate estimation times to search",
					},
					cli.BoolFlag{
						Name:  "no-digits",
						Usage: "Digits in address are disallow ('234567')",
					},
					cli.StringFlag{
						Name:  "exclude",
						Usage: "Characters that must not be in the address",
					},
				},
			},
		},
	}
}

func generateAction(c *cli.Context) error {
	ch, err := chainGlobalOption(c)
	if err != nil {
		return cli.NewExitError(err.Error(), 1)
	}

	num := c.Uint("number")
	for i := uint(0); i < num; i++ {
		pair := keypair.Gen()
		if c.Bool("strip") {
			printlnPrivateKey(pair, true)
		} else {
			printAccountDetails(ch, pair)
		}
	}

	return nil
}

func infoAction(c *cli.Context) error {
	ch, err := chainGlobalOption(c)
	if err != nil {
		return cli.NewExitError(err.Error(), 1)
	}

	fi, err := os.Stdin.Stat()
	if err != nil {
		return cli.NewExitError(err.Error(), 1)
	}
	if fi.Mode()&os.ModeCharDevice != 0 {
		return cli.NewExitError("interactive input mode isn't supported", 1)
	}

	data, err := ioutil.ReadAll(os.Stdin)
	if err != nil {
		return cli.NewExitError(err.Error(), 1)
	}
	s := strings.Split(string(data), "\n")
	for _, s := range s[:len(s)-1] {
		pk, err := hex.DecodeString(strings.TrimSpace(s))
		if err != nil {
			return cli.NewExitError(err.Error(), 1)
		}

		pair, err := keypair.FromSeed(pk)
		if err != nil {
			return cli.NewExitError(err.Error(), 1)
		}

		if c.Bool("address") {
			printlnAddress(ch, pair, true)
		} else if c.Bool("public") {
			printlnPublicKey(pair, true)
		} else {
			printAccountDetails(ch, pair)
		}
	}

	return nil
}

func vanityAction(c *cli.Context) error {
	ch, err := chainGlobalOption(c)
	if err != nil {
		return cli.NewExitError(err.Error(), 1)
	}

	num := c.Uint("number")
	if num == 0 {
		return nil
	}

	workers := c.Uint("workers")
	if m := uint(runtime.NumCPU()); workers == 0 || workers > m {
		workers = m
	}

	var excludeSel vanity.Selector = vanity.TrueSelector{}
	if c.IsSet("exclude") {
		excludeSel, err = vanity.NewExcludeSelector(c.String("exclude"))
		if err != nil {
			return cli.NewExitError(err.Error(), 1)
		}
	}

	var noDigitsSel vanity.Selector = vanity.TrueSelector{}
	if c.Bool("no-digits") {
		noDigitsSel, _ = vanity.NewExcludeSelector("234567")
	}

	prefixes := make([]vanity.Selector, len(c.Args()))
	for i, pr := range c.Args() {
		sel, err := vanity.NewPrefixSelector(ch, strings.ToUpper(pr))
		if err != nil {
			return cli.NewExitError(err.Error(), 1)
		}
		prefixes[i] = sel
	}

	sel := vanity.AndSelector(
		excludeSel, noDigitsSel, vanity.OrSelector(prefixes...))

	if !c.Bool("strip") && !c.Bool("skip-estimate") {
		printEstimate(workers,
			vanity.Probability(sel)/float64(num), c.Bool("show-complexity"))
	}

	rs := make(chan keypair.KeyPair)
	for i := uint(0); i < workers; i++ {
		go vanity.StartSearch(ch, sel, rs)
	}

	for i := uint(0); i < num; i++ {
		pair := <-rs
		if c.Bool("strip") {
			printlnPrivateKey(pair, true)
		} else {
			printAccountDetails(ch, pair)
		}
		go vanity.StartSearch(ch, sel, rs)
	}

	return nil
}

// printEstimate prints vanity account search time estimate
func printEstimate(workers uint, pbty float64, cplx bool) {
	fmt.Print("Calculate accounts rate")
	ticker := time.NewTicker(time.Second)
	go func() {
		for range ticker.C {
			fmt.Print(".")
		}
	}()
	rate := countActualRate(workers)
	ticker.Stop()
	fmt.Printf(" %v accounts/sec\n", math.Trunc(rate))
	printEstimateDetails(pbty, rate, cplx)
}

// countActualRate counts total number of generated keypairs per second
func countActualRate(workers uint) float64 {
	res := make(chan int, workers)
	for i := 0; i < cap(res); i++ {
		go countKeyPairs(3200, res)
	}
	rate := float64(0)
	for i := 0; i < cap(res); i++ {
		rate += float64(<-res) / 3.2
	}
	return rate
}

// countKeyPairs counts number of generated keypairs for specified interval
func countKeyPairs(milliseconds time.Duration, res chan int) {
	timeout := time.After(time.Millisecond * milliseconds)
	for count := 0; ; count++ {
		keypair.Gen().Address(core.Mainnet)
		select {
		case <-timeout:
			res <- count
			return
		default:
			continue
		}
	}
}

// printEstimateDetails prints estimate search time details
func printEstimateDetails(pbty, rate float64, cplx bool) {
	if cplx {
		fmt.Printf("Specified search complexity: %v\n", math.Trunc(1.0/pbty))
	}
	fmt.Printf("Estimate search times: %v (50%%), %v (80%%), %v (99.9%%)\n",
		timeInSeconds(vanity.NumberOfAttempts(pbty, 0.5)/rate),
		timeInSeconds(vanity.NumberOfAttempts(pbty, 0.8)/rate),
		timeInSeconds(vanity.NumberOfAttempts(pbty, 0.99)/rate))
}

// timeInSeconds formats estimated time
func timeInSeconds(val float64) string {
	val = 1e9 * math.Trunc(val)
	if val >= math.MaxInt64 || math.IsInf(val, 0) {
		return "Inf"
	}
	return time.Duration(val).String()
}

// printAccountDetails prints account details in pretty user-oriented multi-line format
func printAccountDetails(chain core.Chain, pair keypair.KeyPair) {
	fmt.Println("----")
	printlnAddress(chain, pair, false)
	printlnPublicKey(pair, false)
	printlnPrivateKey(pair, false)
}

func printlnPrivateKey(pair keypair.KeyPair, strip bool) {
	printlnCustom("Private key: ", hex.EncodeToString(pair.Private), strip)
}

func printlnPublicKey(pair keypair.KeyPair, strip bool) {
	printlnCustom("Public key: ", hex.EncodeToString(pair.Public), strip)
}

func printlnAddress(chain core.Chain, pair keypair.KeyPair, strip bool) {
	printlnCustom("Address: ", pair.Address(chain).PrettyString(), strip)
}

func printlnCustom(title, value string, strip bool) {
	if !strip {
		fmt.Print(title)
	}
	fmt.Println(value)
}
<|endoftext|>


<commit_before>// Tests for rclone
package cmd

import (
	"testing"
)

func TestFIXME(t *testing.T) {
	// FIXME test something!
}
<commit_msg>Remove unused test file<commit_after><|endoftext|>


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

// resgen is a small CLI tool that automatically generates Resource from an API.
package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"go/format"
	"log"
	"os"
	"path/filepath"
	"regexp"
	"strings"
	"text/template"

	gojson "github.com/ChimeraCoder/gojson"

	"e-xpert_solutions/f5-rest-client/f5"
)

var tmpl = `// Copyright e-Xpert Solutions SA. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package {{ .Pkg }}

import "e-xpert_solutions/f5-rest-client/f5"

type {{ .Name }}ConfigList struct {
	Items []{{ .Name }}Config ` + "`json:\"items\"`" + `
	Kind string ` + "`json:\"kind\"`" + `
	SelfLink string ` + "`json:\"selflink\"`" + `
}

type {{ .Name }}Config struct {
	{{ .ItemDef }}
}

const {{ .Name }}Endpoint = "{{ .Endpoint }}"

type {{ .Name }}Resource struct {
	c f5.Client
}

func (r *{{ .Name }}Resource) ListAll() (*{{ .Name }}Config, error) {
	var list {{ .Name }}ConfigList
	if err := r.c.ReadQuery(BasePath+{{ .Name }}Endpoint, &list); err != nil {
		return nil, err
	}
	return &list, nil
}

func (r *{{ .Name }}Resource) Get(id string) (*{{ .Name }}Config, error) {
	var item {{ .Name }}Config
	if err := r.c.ReadQuery(BasePath+{{ .Name }}Endpoint, &item); err != nil {
		return nil, err
	}
	return &item, nil
}

func (r *{{ .Name }}Resource) Create(item {{ .Name }}Config) error {
	if err := r.c.ModQuery("POST", BasePath + {{ .Name }}Endpoint, item); err != nil {
		return err
	}
	return nil
}

func (r *{{ .Name }}Resource) Edit(id string, item {{ .Name }}Config) error {
	if err := r.c.ModQuery("PUT", BasePath + {{ .Name }}Endpoint + "/" + id, item); err != nil {
		return err
	}
	return nil
}

func (r *{{ .Name }}Resource) Delete(id string) error {
	if err := r.c.ModQuery("DELETE", BasePath + {{ .Name }}Endpoint + "/"+id, nil); err != nil {
		return err
	}
	return nil
}
`

var t = template.Must(template.New("resource").Parse(tmpl))

type templateData struct {
	Name     string
	ItemDef  string
	Pkg      string
	Endpoint string
}

func renderTemplate(outputDir string, data templateData) error {
	path := filepath.Join(outputDir, strings.ToLower(data.Name)+".go")
	if _, err := os.Stat(path); err == nil {
		return errors.New(path + " already exists")
	}
	f, err := os.Create(path)
	if err != nil {
		return fmt.Errorf("failed to create output file '%s' for %s resource: %v", path, data.Name, err)
	}
	defer f.Close()
	var buf bytes.Buffer
	if err := t.Execute(&buf, data); err != nil {
		return fmt.Errorf("failed to render template for %s resource: %v", data.Name, err)
	}
	bs, err := format.Source(buf.Bytes())
	if err != nil {
		return fmt.Errorf("failed to format generated file: %v", err)
	}
	if _, err := f.Write(bs); err != nil {
		return fmt.Errorf("failed to write generated file: %v", err)
	}
	return nil
}

var re = regexp.MustCompile("Items \\[\\]struct \\{(.*)\\} `json:\"items\"`")

func findItemDef(s string) string {
	matches := re.FindAllStringSubmatch(strings.Replace(s, "\n", "<°BREAK°>", -1), -1)
	return strings.Replace(matches[0][1], "<°BREAK°>", "\n", -1)
}

type config struct {
	BaseURL  string `json:"base_url"`
	User     string `json:"username"`
	Password string `json:"password"`
	API      map[string]struct {
		RESTPath string `json:"rest_path"`
		Endpoint string `json:"endpoint"`
	} `json:"api"`
}

func parseConfig(path string) (*config, error) {
	f, err := os.Open(path)
	if err != nil {
		return nil, fmt.Errorf("failed to open config file: %v", err)
	}
	defer f.Close()
	var cfg config
	dec := json.NewDecoder(f)
	if err := dec.Decode(&cfg); err != nil {
		return nil, fmt.Errorf("failed to parse config file: %v", err)
	}
	return &cfg, nil
}

var (
	cfgPath   = flag.String("c", "genres.conf", "configuration file path")
	outputDir = flag.String("o", ".", "output directory")
	pkgName   = flag.String("p", "foo", "package name")
)

func main() {
	flag.Parse()

	if info, err := os.Stat(*outputDir); err != nil {
		log.Fatal(err)
	} else if !info.IsDir() {
		log.Fatalf("'%s' is not a directory", *outputDir)
	}

	cfg, err := parseConfig(*cfgPath)
	if err != nil {
		log.Fatal(err)
	}

	f5Client, err := f5.NewBasicClient(cfg.BaseURL, cfg.User, cfg.Password)
	if err != nil {
		log.Fatal(err)
	}
	f5Client.DisableCertCheck()

	for name, settings := range cfg.API {
		req, err := f5Client.MakeRequest("GET", settings.RESTPath, nil)
		if err != nil {
			log.Print("failed to create http request", settings.RESTPath, ": ", err)
			continue
		}
		resp, err := f5Client.Do(req)
		if err != nil {
			log.Print("failed to query ", settings.RESTPath, ": ", err)
			continue
		}
		defer resp.Body.Close()
		listDef, err := gojson.Generate(resp.Body, name, *pkgName)
		if err != nil {
			log.Print("failed to generate structure for ", settings.RESTPath, ": ", err)
			continue
		}
		data := templateData{
			Name:     name,
			ItemDef:  findItemDef(string(listDef)),
			Pkg:      *pkgName,
			Endpoint: settings.Endpoint,
		}
		if err := renderTemplate(*outputDir, data); err != nil {
			log.Print("failed to render template: ", err)
		}
	}
}
<commit_msg>cmd/resgen: change default config file name<commit_after>// Copyright 2014-2016 The project AUTHORS. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// resgen is a small CLI tool that automatically generates Resource from an API.
package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"go/format"
	"log"
	"os"
	"path/filepath"
	"regexp"
	"strings"
	"text/template"

	gojson "github.com/ChimeraCoder/gojson"

	"e-xpert_solutions/f5-rest-client/f5"
)

var tmpl = `// Copyright e-Xpert Solutions SA. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package {{ .Pkg }}

import "e-xpert_solutions/f5-rest-client/f5"

type {{ .Name }}ConfigList struct {
	Items []{{ .Name }}Config ` + "`json:\"items\"`" + `
	Kind string ` + "`json:\"kind\"`" + `
	SelfLink string ` + "`json:\"selflink\"`" + `
}

type {{ .Name }}Config struct {
	{{ .ItemDef }}
}

const {{ .Name }}Endpoint = "{{ .Endpoint }}"

type {{ .Name }}Resource struct {
	c f5.Client
}

func (r *{{ .Name }}Resource) ListAll() (*{{ .Name }}Config, error) {
	var list {{ .Name }}ConfigList
	if err := r.c.ReadQuery(BasePath+{{ .Name }}Endpoint, &list); err != nil {
		return nil, err
	}
	return &list, nil
}

func (r *{{ .Name }}Resource) Get(id string) (*{{ .Name }}Config, error) {
	var item {{ .Name }}Config
	if err := r.c.ReadQuery(BasePath+{{ .Name }}Endpoint, &item); err != nil {
		return nil, err
	}
	return &item, nil
}

func (r *{{ .Name }}Resource) Create(item {{ .Name }}Config) error {
	if err := r.c.ModQuery("POST", BasePath + {{ .Name }}Endpoint, item); err != nil {
		return err
	}
	return nil
}

func (r *{{ .Name }}Resource) Edit(id string, item {{ .Name }}Config) error {
	if err := r.c.ModQuery("PUT", BasePath + {{ .Name }}Endpoint + "/" + id, item); err != nil {
		return err
	}
	return nil
}

func (r *{{ .Name }}Resource) Delete(id string) error {
	if err := r.c.ModQuery("DELETE", BasePath + {{ .Name }}Endpoint + "/"+id, nil); err != nil {
		return err
	}
	return nil
}
`

var t = template.Must(template.New("resource").Parse(tmpl))

type templateData struct {
	Name     string
	ItemDef  string
	Pkg      string
	Endpoint string
}

func renderTemplate(outputDir string, data templateData) error {
	path := filepath.Join(outputDir, strings.ToLower(data.Name)+".go")
	if _, err := os.Stat(path); err == nil {
		return errors.New(path + " already exists")
	}
	f, err := os.Create(path)
	if err != nil {
		return fmt.Errorf("failed to create output file '%s' for %s resource: %v", path, data.Name, err)
	}
	defer f.Close()
	var buf bytes.Buffer
	if err := t.Execute(&buf, data); err != nil {
		return fmt.Errorf("failed to render template for %s resource: %v", data.Name, err)
	}
	bs, err := format.Source(buf.Bytes())
	if err != nil {
		return fmt.Errorf("failed to format generated file: %v", err)
	}
	if _, err := f.Write(bs); err != nil {
		return fmt.Errorf("failed to write generated file: %v", err)
	}
	return nil
}

var re = regexp.MustCompile("Items \\[\\]struct \\{(.*)\\} `json:\"items\"`")

func findItemDef(s string) string {
	matches := re.FindAllStringSubmatch(strings.Replace(s, "\n", "<°BREAK°>", -1), -1)
	return strings.Replace(matches[0][1], "<°BREAK°>", "\n", -1)
}

type config struct {
	BaseURL  string `json:"base_url"`
	User     string `json:"username"`
	Password string `json:"password"`
	API      map[string]struct {
		RESTPath string `json:"rest_path"`
		Endpoint string `json:"endpoint"`
	} `json:"api"`
}

func parseConfig(path string) (*config, error) {
	f, err := os.Open(path)
	if err != nil {
		return nil, fmt.Errorf("failed to open config file: %v", err)
	}
	defer f.Close()
	var cfg config
	dec := json.NewDecoder(f)
	if err := dec.Decode(&cfg); err != nil {
		return nil, fmt.Errorf("failed to parse config file: %v", err)
	}
	return &cfg, nil
}

var (
	cfgPath   = flag.String("c", "resgen.conf", "configuration file path")
	outputDir = flag.String("o", ".", "output directory")
	pkgName   = flag.String("p", "foo", "package name")
)

func main() {
	flag.Parse()

	if info, err := os.Stat(*outputDir); err != nil {
		log.Fatal(err)
	} else if !info.IsDir() {
		log.Fatalf("'%s' is not a directory", *outputDir)
	}

	cfg, err := parseConfig(*cfgPath)
	if err != nil {
		log.Fatal(err)
	}

	f5Client, err := f5.NewBasicClient(cfg.BaseURL, cfg.User, cfg.Password)
	if err != nil {
		log.Fatal(err)
	}
	f5Client.DisableCertCheck()

	for name, settings := range cfg.API {
		req, err := f5Client.MakeRequest("GET", settings.RESTPath, nil)
		if err != nil {
			log.Print("failed to create http request", settings.RESTPath, ": ", err)
			continue
		}
		resp, err := f5Client.Do(req)
		if err != nil {
			log.Print("failed to query ", settings.RESTPath, ": ", err)
			continue
		}
		defer resp.Body.Close()
		listDef, err := gojson.Generate(resp.Body, name, *pkgName)
		if err != nil {
			log.Print("failed to generate structure for ", settings.RESTPath, ": ", err)
			continue
		}
		data := templateData{
			Name:     name,
			ItemDef:  findItemDef(string(listDef)),
			Pkg:      *pkgName,
			Endpoint: settings.Endpoint,
		}
		if err := renderTemplate(*outputDir, data); err != nil {
			log.Print("failed to render template: ", err)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"

	log "github.com/Sirupsen/logrus"

	"github.com/grid-x/backupd/pkg/backup"
	"github.com/grid-x/backupd/pkg/config"
	"github.com/grid-x/backupd/pkg/datastore"
	"github.com/grid-x/backupd/pkg/storage"
)

func main() {
	var (
		logger = log.New()

		configFile = flag.String("config-file", "config.yaml", "Config file to use")
	)

	config, err := config.ReadConfigFromFile(*configFile)
	if err != nil {
		logger.Fatalf("Problem reading config file: %s", err.Error())
	}

	if config.Storage.S3 == nil {
		logger.Fatal("Not storage setting given")
	}

	s3 := storage.NewS3(config.Storage.S3.Region, config.Storage.S3.Bucket)

	if len(config.Targets) < 1 {
		logger.Warn("No target provided")
	}

	statusc := make(chan backup.BackupJobStatus)
	var schedules []backup.Schedule

	var ds backup.DataStore
	for _, t := range config.Targets {
		switch t.Type {
		case "etcd":
			endpoint, ok := t.Settings["endpoint"].(string)
			if !ok {
				logger.Errorf("Can't convert etcd endpoint to string for target %s", t.Name)
				continue
			}
			ds = datastore.NewEtcd(endpoint)
		case "influxdb":
			endpoint, ok := t.Settings["endpoint"].(string)
			if !ok {
				logger.Errorf("Can't convert influxdb endpoint to string for target %s", t.Name)
				continue
			}
			database, ok := t.Settings["database"].(string)
			if !ok {
				logger.Errorf("Can't convert influxdb database to string for target %s", t.Name)
				continue
			}
			ds = datastore.NewInflux(endpoint, database)
		case "mongodb":
			host, ok := t.Settings["host"].(string)
			if !ok {
				logger.Errorf("Can't convert mongodb host to string for target %s", t.Name)
				continue
			}

			port, ok := t.Settings["port"].(int)
			if !ok {
				logger.Errorf("Can't convert mongodb port to string for target %s", t.Name)
				continue
			}

			user, ok := t.Settings["user"].(string)
			if !ok {
				logger.Errorf("Can't convert mongodb user to string for target %s", t.Name)
				continue
			}
			password, ok := t.Settings["password"].(string)
			if !ok {
				logger.Errorf("Can't convert mongodb password to string for target %s", t.Name)
				continue
			}
			ds = datastore.NewMongoDB(host, port, user, password)
		default:
			logger.Warnf("Target type '%s' currently not supported", t.Type)
			continue
		}
		schedules = append(schedules, backup.Schedule{
			Spec:      t.Schedule,
			BackupJob: backup.NewBackupJob(ds, s3, t.Name, statusc),
		})
		logger.Infof("Successfully added job for target: %s", t.Name)
	}

	s, err := backup.NewScheduler(schedules)
	if err != nil {
		logger.Fatal(err)
	}

	go s.Run()
	for s := range statusc {
		if s.Error == nil {
			logger.Infof("Success: Job %s took %s to finish", s.Name, s.Duration)
		} else {
			logger.Errorf("Job %s failed after %s with error %s", s.Name, s.Duration, s.Error.Error())
		}
	}
}
<commit_msg>fix(server): parse arguments properly<commit_after>package main

import (
	"flag"

	log "github.com/Sirupsen/logrus"

	"github.com/grid-x/backupd/pkg/backup"
	"github.com/grid-x/backupd/pkg/config"
	"github.com/grid-x/backupd/pkg/datastore"
	"github.com/grid-x/backupd/pkg/storage"
)

func main() {
	var (
		logger = log.New()

		configFile = flag.String("config-file", "config.yaml", "Config file to use")
	)

	flag.Parse()

	config, err := config.ReadConfigFromFile(*configFile)
	if err != nil {
		logger.Fatalf("Problem reading config file: %s", err.Error())
	}

	if config.Storage.S3 == nil {
		logger.Fatal("Not storage setting given")
	}

	s3 := storage.NewS3(config.Storage.S3.Region, config.Storage.S3.Bucket)

	if len(config.Targets) < 1 {
		logger.Warn("No target provided")
	}

	statusc := make(chan backup.BackupJobStatus)
	var schedules []backup.Schedule

	var ds backup.DataStore
	for _, t := range config.Targets {
		switch t.Type {
		case "etcd":
			endpoint, ok := t.Settings["endpoint"].(string)
			if !ok {
				logger.Errorf("Can't convert etcd endpoint to string for target %s", t.Name)
				continue
			}
			ds = datastore.NewEtcd(endpoint)
		case "influxdb":
			endpoint, ok := t.Settings["endpoint"].(string)
			if !ok {
				logger.Errorf("Can't convert influxdb endpoint to string for target %s", t.Name)
				continue
			}
			database, ok := t.Settings["database"].(string)
			if !ok {
				logger.Errorf("Can't convert influxdb database to string for target %s", t.Name)
				continue
			}
			ds = datastore.NewInflux(endpoint, database)
		case "mongodb":
			host, ok := t.Settings["host"].(string)
			if !ok {
				logger.Errorf("Can't convert mongodb host to string for target %s", t.Name)
				continue
			}

			port, ok := t.Settings["port"].(int)
			if !ok {
				logger.Errorf("Can't convert mongodb port to string for target %s", t.Name)
				continue
			}

			user, ok := t.Settings["user"].(string)
			if !ok {
				logger.Errorf("Can't convert mongodb user to string for target %s", t.Name)
				continue
			}
			password, ok := t.Settings["password"].(string)
			if !ok {
				logger.Errorf("Can't convert mongodb password to string for target %s", t.Name)
				continue
			}
			ds = datastore.NewMongoDB(host, port, user, password)
		default:
			logger.Warnf("Target type '%s' currently not supported", t.Type)
			continue
		}
		schedules = append(schedules, backup.Schedule{
			Spec:      t.Schedule,
			BackupJob: backup.NewBackupJob(ds, s3, t.Name, statusc),
		})
		logger.Infof("Successfully added job for target: %s", t.Name)
	}

	s, err := backup.NewScheduler(schedules)
	if err != nil {
		logger.Fatal(err)
	}

	go s.Run()
	for s := range statusc {
		if s.Error == nil {
			logger.Infof("Success: Job %s took %s to finish", s.Name, s.Duration)
		} else {
			logger.Errorf("Job %s failed after %s with error %s", s.Name, s.Duration, s.Error.Error())
		}
	}
}
<|endoftext|>


<commit_before>package cmd

import (
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"os"
	"path/filepath"
	"testing"

	"github.com/exercism/cli/config"
	"github.com/exercism/cli/workspace"
	"github.com/spf13/pflag"
	"github.com/spf13/viper"
	"github.com/stretchr/testify/assert"
)

func TestSubmitWithoutToken(t *testing.T) {
	flags := pflag.NewFlagSet("fake", pflag.PanicOnError)

	cfg := config.Configuration{
		Persister:       config.InMemoryPersister{},
		UserViperConfig: viper.New(),
		DefaultBaseURL:  "http://example.com",
	}

	err := runSubmit(cfg, flags, []string{})
	assert.Regexp(t, "Welcome to Exercism", err.Error())
}

func TestSubmitWithoutWorkspace(t *testing.T) {
	flags := pflag.NewFlagSet("fake", pflag.PanicOnError)

	v := viper.New()
	v.Set("token", "abc123")

	cfg := config.Configuration{
		Persister:       config.InMemoryPersister{},
		UserViperConfig: v,
		DefaultBaseURL:  "http://example.com",
	}

	err := runSubmit(cfg, flags, []string{})
	assert.Regexp(t, "run configure", err.Error())
}

func TestSubmitNonExistentFile(t *testing.T) {
	flags := pflag.NewFlagSet("fake", pflag.PanicOnError)

	tmpDir, err := ioutil.TempDir("", "submit-no-such-file")
	assert.NoError(t, err)

	v := viper.New()
	v.Set("token", "abc123")
	v.Set("workspace", tmpDir)

	cfg := config.Configuration{
		Persister:       config.InMemoryPersister{},
		UserViperConfig: v,
		DefaultBaseURL:  "http://example.com",
	}

	err = ioutil.WriteFile(filepath.Join(tmpDir, "file-1.txt"), []byte("This is file 1"), os.FileMode(0755))
	assert.NoError(t, err)

	err = ioutil.WriteFile(filepath.Join(tmpDir, "file-2.txt"), []byte("This is file 2"), os.FileMode(0755))
	assert.NoError(t, err)

	err = runSubmit(cfg, flags, []string{filepath.Join(tmpDir, "file-1.txt"), "no-such-file.txt", filepath.Join(tmpDir, "file-2.txt")})
	assert.Regexp(t, "no such file", err.Error())
}

func TestSubmitFilesAndDir(t *testing.T) {
	flags := pflag.NewFlagSet("fake", pflag.PanicOnError)

	tmpDir, err := ioutil.TempDir("", "submit-no-such-file")
	assert.NoError(t, err)

	v := viper.New()
	v.Set("token", "abc123")
	v.Set("workspace", tmpDir)

	cfg := config.Configuration{
		Persister:       config.InMemoryPersister{},
		UserViperConfig: v,
		DefaultBaseURL:  "http://example.com",
	}

	err = ioutil.WriteFile(filepath.Join(tmpDir, "file-1.txt"), []byte("This is file 1"), os.FileMode(0755))
	assert.NoError(t, err)

	err = ioutil.WriteFile(filepath.Join(tmpDir, "file-2.txt"), []byte("This is file 2"), os.FileMode(0755))
	assert.NoError(t, err)

	err = runSubmit(cfg, flags, []string{filepath.Join(tmpDir, "file-1.txt"), tmpDir, filepath.Join(tmpDir, "file-2.txt")})
	assert.Regexp(t, "is a directory", err.Error())
}

func TestSubmitFiles(t *testing.T) {
	oldOut := Out
	oldErr := Err
	Out = ioutil.Discard
	Err = ioutil.Discard
	defer func() {
		Out = oldOut
		Err = oldErr
	}()
	// The fake endpoint will populate this when it receives the call from the command.
	submittedFiles := map[string]string{}
	ts := fakeSubmitServer(t, submittedFiles)
	defer ts.Close()

	tmpDir, err := ioutil.TempDir("", "submit-files")
	assert.NoError(t, err)

	dir := filepath.Join(tmpDir, "bogus-track", "bogus-exercise")
	os.MkdirAll(filepath.Join(dir, "subdir"), os.FileMode(0755))

	type file struct {
		relativePath string
		contents     string
	}

	file1 := file{
		relativePath: "file-1.txt",
		contents:     "This is file 1.",
	}
	file2 := file{
		relativePath: filepath.Join("subdir", "file-2.txt"),
		contents:     "This is file 2.",
	}
	file3 := file{
		relativePath: "README.md",
		contents:     "The readme.",
	}

	filenames := make([]string, 0, 3)
	for _, file := range []file{file1, file2, file3} {
		path := filepath.Join(dir, file.relativePath)
		filenames = append(filenames, path)
		err := ioutil.WriteFile(path, []byte(file.contents), os.FileMode(0755))
		assert.NoError(t, err)
	}

	writeFakeSolution(t, dir, "bogus-track", "bogus-exercise")

	flags := pflag.NewFlagSet("fake", pflag.PanicOnError)
	setupSubmitFlags(flags)

	v := viper.New()
	v.Set("token", "abc123")
	v.Set("workspace", tmpDir)
	v.Set("apibaseurl", ts.URL)

	cliCfg := &config.CLIConfig{
		Config: config.New(tmpDir, "cli"),
		Tracks: config.Tracks{},
	}
	cliCfg.Tracks["bogus-track"] = config.NewTrack("bogus-track")
	err = cliCfg.Write()
	assert.NoError(t, err)

	cfg := config.Configuration{
		Persister:       config.InMemoryPersister{},
		Dir:             tmpDir,
		UserViperConfig: v,
		CLIConfig:       cliCfg,
	}

	err = runSubmit(cfg, flags, filenames)
	assert.NoError(t, err)

	// We currently have a bug, and we're not filtering anything.
	// Fix that in a separate commit.
	assert.Equal(t, 3, len(submittedFiles))

	for _, file := range []file{file1, file2, file3} {
		path := string(os.PathSeparator) + file.relativePath
		assert.Equal(t, file.contents, submittedFiles[path])
	}
}

func fakeSubmitServer(t *testing.T, submittedFiles map[string]string) *httptest.Server {
	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		err := r.ParseMultipartForm(2 << 10)
		if err != nil {
			t.Fatal(err)
		}
		mf := r.MultipartForm

		files := mf.File["files[]"]
		for _, fileHeader := range files {
			file, err := fileHeader.Open()
			if err != nil {
				t.Fatal(err)
			}
			defer file.Close()
			body, err := ioutil.ReadAll(file)
			if err != nil {
				t.Fatal(err)
			}
			submittedFiles[fileHeader.Filename] = string(body)
		}
	})
	return httptest.NewServer(handler)
}

func writeFakeSolution(t *testing.T, dir, trackID, exerciseSlug string) {
	solution := &workspace.Solution{
		ID:          "bogus-solution-uuid",
		Track:       trackID,
		Exercise:    exerciseSlug,
		URL:         "http://example.com/bogus-url",
		IsRequester: true,
	}
	err := solution.Write(dir)
	assert.NoError(t, err)
}
<commit_msg>Remove incorrect comment<commit_after>package cmd

import (
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"os"
	"path/filepath"
	"testing"

	"github.com/exercism/cli/config"
	"github.com/exercism/cli/workspace"
	"github.com/spf13/pflag"
	"github.com/spf13/viper"
	"github.com/stretchr/testify/assert"
)

func TestSubmitWithoutToken(t *testing.T) {
	flags := pflag.NewFlagSet("fake", pflag.PanicOnError)

	cfg := config.Configuration{
		Persister:       config.InMemoryPersister{},
		UserViperConfig: viper.New(),
		DefaultBaseURL:  "http://example.com",
	}

	err := runSubmit(cfg, flags, []string{})
	assert.Regexp(t, "Welcome to Exercism", err.Error())
}

func TestSubmitWithoutWorkspace(t *testing.T) {
	flags := pflag.NewFlagSet("fake", pflag.PanicOnError)

	v := viper.New()
	v.Set("token", "abc123")

	cfg := config.Configuration{
		Persister:       config.InMemoryPersister{},
		UserViperConfig: v,
		DefaultBaseURL:  "http://example.com",
	}

	err := runSubmit(cfg, flags, []string{})
	assert.Regexp(t, "run configure", err.Error())
}

func TestSubmitNonExistentFile(t *testing.T) {
	flags := pflag.NewFlagSet("fake", pflag.PanicOnError)

	tmpDir, err := ioutil.TempDir("", "submit-no-such-file")
	assert.NoError(t, err)

	v := viper.New()
	v.Set("token", "abc123")
	v.Set("workspace", tmpDir)

	cfg := config.Configuration{
		Persister:       config.InMemoryPersister{},
		UserViperConfig: v,
		DefaultBaseURL:  "http://example.com",
	}

	err = ioutil.WriteFile(filepath.Join(tmpDir, "file-1.txt"), []byte("This is file 1"), os.FileMode(0755))
	assert.NoError(t, err)

	err = ioutil.WriteFile(filepath.Join(tmpDir, "file-2.txt"), []byte("This is file 2"), os.FileMode(0755))
	assert.NoError(t, err)

	err = runSubmit(cfg, flags, []string{filepath.Join(tmpDir, "file-1.txt"), "no-such-file.txt", filepath.Join(tmpDir, "file-2.txt")})
	assert.Regexp(t, "no such file", err.Error())
}

func TestSubmitFilesAndDir(t *testing.T) {
	flags := pflag.NewFlagSet("fake", pflag.PanicOnError)

	tmpDir, err := ioutil.TempDir("", "submit-no-such-file")
	assert.NoError(t, err)

	v := viper.New()
	v.Set("token", "abc123")
	v.Set("workspace", tmpDir)

	cfg := config.Configuration{
		Persister:       config.InMemoryPersister{},
		UserViperConfig: v,
		DefaultBaseURL:  "http://example.com",
	}

	err = ioutil.WriteFile(filepath.Join(tmpDir, "file-1.txt"), []byte("This is file 1"), os.FileMode(0755))
	assert.NoError(t, err)

	err = ioutil.WriteFile(filepath.Join(tmpDir, "file-2.txt"), []byte("This is file 2"), os.FileMode(0755))
	assert.NoError(t, err)

	err = runSubmit(cfg, flags, []string{filepath.Join(tmpDir, "file-1.txt"), tmpDir, filepath.Join(tmpDir, "file-2.txt")})
	assert.Regexp(t, "is a directory", err.Error())
}

func TestSubmitFiles(t *testing.T) {
	oldOut := Out
	oldErr := Err
	Out = ioutil.Discard
	Err = ioutil.Discard
	defer func() {
		Out = oldOut
		Err = oldErr
	}()
	// The fake endpoint will populate this when it receives the call from the command.
	submittedFiles := map[string]string{}
	ts := fakeSubmitServer(t, submittedFiles)
	defer ts.Close()

	tmpDir, err := ioutil.TempDir("", "submit-files")
	assert.NoError(t, err)

	dir := filepath.Join(tmpDir, "bogus-track", "bogus-exercise")
	os.MkdirAll(filepath.Join(dir, "subdir"), os.FileMode(0755))

	type file struct {
		relativePath string
		contents     string
	}

	file1 := file{
		relativePath: "file-1.txt",
		contents:     "This is file 1.",
	}
	file2 := file{
		relativePath: filepath.Join("subdir", "file-2.txt"),
		contents:     "This is file 2.",
	}
	// We don't filter *.md files if you explicitly pass the file path.
	file3 := file{
		relativePath: "README.md",
		contents:     "The readme.",
	}

	filenames := make([]string, 0, 3)
	for _, file := range []file{file1, file2, file3} {
		path := filepath.Join(dir, file.relativePath)
		filenames = append(filenames, path)
		err := ioutil.WriteFile(path, []byte(file.contents), os.FileMode(0755))
		assert.NoError(t, err)
	}

	writeFakeSolution(t, dir, "bogus-track", "bogus-exercise")

	flags := pflag.NewFlagSet("fake", pflag.PanicOnError)
	setupSubmitFlags(flags)

	v := viper.New()
	v.Set("token", "abc123")
	v.Set("workspace", tmpDir)
	v.Set("apibaseurl", ts.URL)

	cliCfg := &config.CLIConfig{
		Config: config.New(tmpDir, "cli"),
		Tracks: config.Tracks{},
	}
	cliCfg.Tracks["bogus-track"] = config.NewTrack("bogus-track")
	err = cliCfg.Write()
	assert.NoError(t, err)

	cfg := config.Configuration{
		Persister:       config.InMemoryPersister{},
		Dir:             tmpDir,
		UserViperConfig: v,
		CLIConfig:       cliCfg,
	}

	err = runSubmit(cfg, flags, filenames)
	assert.NoError(t, err)

	assert.Equal(t, 3, len(submittedFiles))

	for _, file := range []file{file1, file2, file3} {
		path := string(os.PathSeparator) + file.relativePath
		assert.Equal(t, file.contents, submittedFiles[path])
	}
}

func fakeSubmitServer(t *testing.T, submittedFiles map[string]string) *httptest.Server {
	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		err := r.ParseMultipartForm(2 << 10)
		if err != nil {
			t.Fatal(err)
		}
		mf := r.MultipartForm

		files := mf.File["files[]"]
		for _, fileHeader := range files {
			file, err := fileHeader.Open()
			if err != nil {
				t.Fatal(err)
			}
			defer file.Close()
			body, err := ioutil.ReadAll(file)
			if err != nil {
				t.Fatal(err)
			}
			submittedFiles[fileHeader.Filename] = string(body)
		}
	})
	return httptest.NewServer(handler)
}

func writeFakeSolution(t *testing.T, dir, trackID, exerciseSlug string) {
	solution := &workspace.Solution{
		ID:          "bogus-solution-uuid",
		Track:       trackID,
		Exercise:    exerciseSlug,
		URL:         "http://example.com/bogus-url",
		IsRequester: true,
	}
	err := solution.Write(dir)
	assert.NoError(t, err)
}
<|endoftext|>