<commit_before>package main

import (
    "fmt"
    "net/http"
    "os"
    "regexp"
    "strconv"
    "strings"

    "github.com/PuerkitoBio/goquery"
    _ "github.com/garyburd/redigo/redis"
    "github.com/sfreiberg/gotwilio"
)

type RewardsParser struct {
    /**
     * Parses out remaining number of rewards
     * Example input: Limited (5093 left of 26000)
     * Example match: (5093
     */
    remainingRegex *regexp.Regexp

    /**
     * Parses out total number of rewards
     * Example input: Limited (5093 left of 26000)
     * Example match:  26000)
     */
    totalRegex *regexp.Regexp

    /**
     * Determines if remaining number of rewards is 0
     */
    soldOutRegex *regexp.Regexp
}

/**
 */
func (p *RewardsParser) compileRegexsIfNecessary() {
    if p.remainingRegex == nil {
        p.remainingRegex = regexp.MustCompile("\\((.*?) ")
        p.totalRegex = regexp.MustCompile("f (.*?)\\)")
        p.soldOutRegex = regexp.MustCompile("All gone!")
    }
}

/**
 * Looks for remaining and total number of rewards
 * @param  string  s   Input string to be searched
 * @return integer r   Remaining rewards
 * @return integer t   Total rewards
 * @return error   err Error if failure
 */
func (p *RewardsParser) parseRewardAmounts(s string) (int64, int64, error) {
    p.compileRegexsIfNecessary()

    if p.soldOutRegex.FindString(s) != "" {
        return 0, 0, nil
    }

    ur := p.remainingRegex.FindString(s)
    if ur == "" {
        return 0, 0, fmt.Errorf("error parsing string for reward amounts: %s", s)
    }
    ut := p.totalRegex.FindString(s)
    if ut == "" {
        return 0, 0, fmt.Errorf("error parsing string for total amount: %s", s)
    }

    var r, t int64
    var err error

    r, err = strconv.ParseInt(strings.Trim(ur, "( "), 10, 32)
    if err != nil {
        return 0, 0, err
    }

    t, err = strconv.ParseInt(strings.Trim(ut, "f )"), 10, 32)
    if err != nil {
        return 0, 0, err
    }

    return r, t, err
}

var rewardsParser *RewardsParser

/*
 * Gets remaining and total amounts for a Kickstarter project reward
 * @param  string proj      Kickstarter project URL suffix like: "597507018/pebble-time-awesome-smartwatch-no-compromises"
 * @param  uint   idx       Zero-based index of reward
 * @return int64  remaining Amount remaining of the reward
 * @return int64  total     Total amount of reward (will be 0 if amount remaining is 0)
 * @return error  err       Error if one has occurred
 */
func scrape(proj string, idx uint) (int64, int64, error) {
    // TODO:
    // Make this method more testable.
    // It's tightly coupled to goquery at the moment.
    doc, err := goquery.NewDocument("https://www.kickstarter.com/projects/" + proj)
    if err != nil {
        return 0, 0, err
    }

    var remaining, total int64
    doc.Find(".NS-projects-reward").EachWithBreak(func(i int, s *goquery.Selection) bool {
        if uint(i) != idx {
            return true
        }

        span := s.Find(".limited-number").Text()
        remaining, total, err = rewardsParser.parseRewardAmounts(span)
        return false
    })

    if err != nil {
        return 0, 0, err
    }

    return int64(remaining), int64(total), nil
}

// Given the last sent amount and the current remaining amount, determines if a new text should be sent
func sendMessage(lastSentAmount int64, currentAmount int64) bool {
    if lastSentAmount < 0 {
        // initial
        return true
    }

    lastSentAmount-- // Adjust values since we want to send a new text at the diff multiple
    currentAmount--
    var factor int64 = 10 // Represents the multiple of 10 that is higher than the current amount
    for factor < currentAmount {
        factor *= 10
    }
    diff := factor / 10 // Threshold for sending a new text
    lastTier := (lastSentAmount - lastSentAmount%diff) / diff
    curTier := (currentAmount - currentAmount%diff) / diff
    changed := curTier < lastTier || (currentAmount != lastSentAmount && lastSentAmount < 0)
    return changed
}

var accountSid, authToken, from string
var twilio *gotwilio.Twilio
var last int64

func handler(w http.ResponseWriter, req *http.Request) {
    w.Header().Set("Content-Type", "text/html")
    w.Write([]byte(fmt.Sprintf("
Pebble availability
\n
%d Pebble Time Steels of %d are remaining.
", last, 20000)))
}

func scrapeAndText() {
    // var timeSteelIdx uint = 3
    // fmt.Println("Starting scrape")
    // remaining, total, err := scrape("597507018/pebble-time-awesome-smartwatch-no-compromises", timeSteelIdx)
    // if remaining < 0 {
    //     fmt.Println("Failed scrape")
    //     return
    // }
    // fmt.Println(remaining, "remaining")
    // if !sendMessage(last, remaining) {
    //     last = remaining
    //     return
    // }

    // last = remaining
    // message := fmt.Sprintf("%d Pebble Time Steels of %d are remaining.", remaining, 20000)
    // fmt.Printf("Sending message: %s\n", message)
    // twilio.SendSMS(from, to, message, "", "")
}

func pingHandler(w http.ResponseWriter, req *http.Request) {
    scrapeAndText()
    w.Header().Set("Content-Type", "text/html")
    w.Write([]byte("scraped"))
}

func main() {
    // twilioSid := os.Getenv("TWILIO_SID")
    // twilioToken := os.Getenv("TWILIO_TOKEN")
    // twilioClient := gotwilio.NewTwilioClient(accountSid, authToken)
    // twilioNumber := os.Getenv("TWILIO_NUMBER")
    // redisUrl := os.Getenv("REDISCLOUD_URL")

    rewardsParser = &RewardsParser{}

    last = -1

    http.HandleFunc("/", handler)
    http.HandleFunc("/ping", pingHandler)
    err := http.ListenAndServe(":"+os.Getenv("PORT"), nil)
    if err != nil {
        panic(err)
    }
}
<commit_msg>Reactivate<commit_after>package main

import (
    "fmt"
    "net/http"
    "os"
    "regexp"
    "strconv"
    "strings"

    "github.com/PuerkitoBio/goquery"
    "github.com/sfreiberg/gotwilio"
)

type RewardsParser struct {
    /**
     * Parses out remaining number of rewards
     * Example input: Limited (5093 left of 26000)
     * Example match: (5093
     */
    remainingRegex *regexp.Regexp

    /**
     * Parses out total number of rewards
     * Example input: Limited (5093 left of 26000)
     * Example match:  26000)
     */
    totalRegex *regexp.Regexp

    /**
     * Determines if remaining number of rewards is 0
     */
    soldOutRegex *regexp.Regexp
}

/**
 */
func (p *RewardsParser) compileRegexsIfNecessary() {
    if p.remainingRegex == nil {
        p.remainingRegex = regexp.MustCompile("\\((.*?) ")
        p.totalRegex = regexp.MustCompile("f (.*?)\\)")
        p.soldOutRegex = regexp.MustCompile("All gone!")
    }
}

/**
 * Looks for remaining and total number of rewards
 * @param  string  s   Input string to be searched
 * @return integer r   Remaining rewards
 * @return integer t   Total rewards
 * @return error   err Error if failure
 */
func (p *RewardsParser) parseRewardAmounts(s string) (int64, int64, error) {
    p.compileRegexsIfNecessary()

    if p.soldOutRegex.FindString(s) != "" {
        return 0, 0, nil
    }

    ur := p.remainingRegex.FindString(s)
    if ur == "" {
        return 0, 0, fmt.Errorf("error parsing string for reward amounts: %s", s)
    }
    ut := p.totalRegex.FindString(s)
    if ut == "" {
        return 0, 0, fmt.Errorf("error parsing string for total amount: %s", s)
    }

    var r, t int64
    var err error

    r, err = strconv.ParseInt(strings.Trim(ur, "( "), 10, 32)
    if err != nil {
        return 0, 0, err
    }

    t, err = strconv.ParseInt(strings.Trim(ut, "f )"), 10, 32)
    if err != nil {
        return 0, 0, err
    }

    return r, t, err
}

var rewardsParser *RewardsParser

/*
 * Gets remaining and total amounts for a Kickstarter project reward
 * @param  string proj      Kickstarter project URL suffix like: "597507018/pebble-time-awesome-smartwatch-no-compromises"
 * @param  uint   idx       Zero-based index of reward
 * @return int64  remaining Amount remaining of the reward
 * @return int64  total     Total amount of reward (will be 0 if amount remaining is 0)
 * @return error  err       Error if one has occurred
 */
func scrape(proj string, idx uint) (int64, int64, error) {
    // TODO:
    // Make this method more testable.
    // It's tightly coupled to goquery at the moment.
    doc, err := goquery.NewDocument("https://www.kickstarter.com/projects/" + proj)
    if err != nil {
        return 0, 0, err
    }

    var remaining, total int64
    doc.Find(".NS-projects-reward").EachWithBreak(func(i int, s *goquery.Selection) bool {
        if uint(i) != idx {
            return true
        }

        span := s.Find(".limited-number").Text()
        remaining, total, err = rewardsParser.parseRewardAmounts(span)
        return false
    })

    if err != nil {
        return 0, 0, err
    }

    return int64(remaining), int64(total), nil
}

// Given the last sent amount and the current remaining amount, determines if a new text should be sent
func sendMessage(lastSentAmount int64, currentAmount int64) bool {
    if lastSentAmount < 0 {
        // initial
        return true
    }

    lastSentAmount-- // Adjust values since we want to send a new text at the diff multiple
    currentAmount--
    var factor int64 = 10 // Represents the multiple of 10 that is higher than the current amount
    for factor < currentAmount {
        factor *= 10
    }
    diff := factor / 10 // Threshold for sending a new text
    lastTier := (lastSentAmount - lastSentAmount%diff) / diff
    curTier := (currentAmount - currentAmount%diff) / diff
    changed := curTier < lastTier || (currentAmount != lastSentAmount && lastSentAmount < 0)
    return changed
}

var twilioNumber, sendToNumber string
var twilioClient *gotwilio.Twilio
var last int64

func handler(w http.ResponseWriter, req *http.Request) {
    w.Header().Set("Content-Type", "text/html")
    w.Write([]byte(fmt.Sprintf("
Pebble availability
\n
%d Pebble Time Steels of %d are remaining.
", last, 20000)))
}

func scrapeAndText() {
    var timeSteelIdx uint = 3
    fmt.Println("Starting scrape")
    remaining, total, err := scrape("597507018/pebble-time-awesome-smartwatch-no-compromises", timeSteelIdx)

    if err != nil {
        fmt.Println("Failed scrape. Error: ", err)
        return
    }

    if remaining < 0 {
        fmt.Println("Failed scrape")
        return
    }

    fmt.Println(remaining, "remaining")

    if !sendMessage(last, remaining) {
        last = remaining
        return
    }

    last = remaining
    message := fmt.Sprintf("%d Pebble Time Steels of %d are remaining.", remaining, total)
    fmt.Printf("Sending message: %s\n", message)
    twilioClient.SendSMS(twilioNumber, sendToNumber, message, "", "")
}

func pingHandler(w http.ResponseWriter, req *http.Request) {
    scrapeAndText()
    w.Header().Set("Content-Type", "text/html")
    w.Write([]byte("scraped"))
}

func main() {
    twilioSid := os.Getenv("TWILIO_SID")
    twilioToken := os.Getenv("TWILIO_TOKEN")
    twilioClient = gotwilio.NewTwilioClient(twilioSid, twilioToken)
    twilioNumber = os.Getenv("TWILIO_NUMBER")
    sendToNumber = os.Getenv("SEND_TO_NUMBER")

    rewardsParser = &RewardsParser{}

    last = -1

    http.HandleFunc("/", handler)
    http.HandleFunc("/ping", pingHandler)
    err := http.ListenAndServe(":"+os.Getenv("PORT"), nil)
    if err != nil {
        panic(err)
    }
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os/signal"
	"runtime"
	"strconv"
	"syscall"

	"os"

	"bitbucket.org/mundipagg/boletoapi/app"
	"bitbucket.org/mundipagg/boletoapi/config"
	"bitbucket.org/mundipagg/boletoapi/log"
)

var (
	processID    = os.Getpid()
	totalProcs   = runtime.NumCPU()
	devMode      = flag.Bool("dev", false, "-dev To run in dev mode")
	mockMode     = flag.Bool("mock", false, "-mock To run mock requests")
	disableLog   = flag.Bool("nolog", false, "-nolog disable seq log")
	airPlaneMode = flag.Bool("airplane-mode", false, "-airplane-mode run api in dev, mock and nolog mode")
)

func init() {
	createPIDfile()
	// Configure signal handler
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	signal.Notify(c, syscall.SIGTERM)
	go handleSignal(c)
}

func handleSignal(c chan os.Signal) {
	<-c
	config.Stop()
	log.Info("Quiting BoletoApi")
	log.Close()
	//db.GetDB().Close()
	fmt.Println("Done")
	os.Exit(1)
}

func createPIDfile() {
	p := strconv.Itoa(processID)
	ioutil.WriteFile("boletoapi.pid", []byte(p), 0644)
}

func main() {
	flag.Parse()
	logo1()
	if *airPlaneMode {
		app.Run(true, true, true)
	} else {
		app.Run(*devMode, *mockMode, *disableLog)
	}

}

func logo1() {
	l := `
$$$$$$$\            $$\            $$\                $$$$$$\            $$\
$$  __$$\           $$ |           $$ |              $$  __$$\           \__|
$$ |  $$ | $$$$$$\  $$ | $$$$$$\ $$$$$$\    $$$$$$\  $$ /  $$ | $$$$$$\  $$\
$$$$$$$\ |$$  __$$\ $$ |$$  __$$\\_$$  _|  $$  __$$\ $$$$$$$$ |$$  __$$\ $$ |
$$  __$$\ $$ /  $$ |$$ |$$$$$$$$ | $$ |    $$ /  $$ |$$  __$$ |$$ /  $$ |$$ |
$$ |  $$ |$$ |  $$ |$$ |$$   ____| $$ |$$\ $$ |  $$ |$$ |  $$ |$$ |  $$ |$$ |
$$$$$$$  |\$$$$$$  |$$ |\$$$$$$$\  \$$$$  |\$$$$$$  |$$ |  $$ |$$$$$$$  |$$ |
\_______/  \______/ \__| \_______|  \____/  \______/ \__|  \__|$$  ____/ \__|
                                                               $$ |
                                                               $$ |
                                                               \__|
	`
	fmt.Println(l)
	fmt.Println("Version: " + config.Get().Version)
}
<commit_msg>:construction: adiciona opcao para rodar a api só com o servico de mock<commit_after>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os/signal"
	"runtime"
	"strconv"
	"syscall"

	"os"

	"bitbucket.org/mundipagg/boletoapi/app"
	"bitbucket.org/mundipagg/boletoapi/config"
	"bitbucket.org/mundipagg/boletoapi/log"
	"bitbucket.org/mundipagg/boletoapi/robot"
)

var (
	processID    = os.Getpid()
	totalProcs   = runtime.NumCPU()
	devMode      = flag.Bool("dev", false, "-dev To run in dev mode")
	mockMode     = flag.Bool("mock", false, "-mock To run mock requests")
	disableLog   = flag.Bool("nolog", false, "-nolog disable seq log")
	airPlaneMode = flag.Bool("airplane-mode", false, "-airplane-mode run api in dev, mock and nolog mode")
	mockOnly     = flag.Bool("mockonly", false, "-mockonly run just mock service")
)

func init() {
	createPIDfile()
	// Configure signal handler
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	signal.Notify(c, syscall.SIGTERM)
	go handleSignal(c)
}

func handleSignal(c chan os.Signal) {
	<-c
	config.Stop()
	log.Info("Quiting BoletoApi")
	log.Close()
	//db.GetDB().Close()
	fmt.Println("Done")
	os.Exit(1)
}

func createPIDfile() {
	p := strconv.Itoa(processID)
	ioutil.WriteFile("boletoapi.pid", []byte(p), 0644)
}

func main() {
	flag.Parse()
	runtime.GOMAXPROCS(runtime.NumCPU())
	if *mockOnly {
		w := make(chan int)
		config.Install(true, true, true)
		robot.GoRobots()
		<-w
	} else {
		logo1()
		if *airPlaneMode {
			app.Run(true, true, true)
		} else {
			app.Run(*devMode, *mockMode, *disableLog)
		}
	}

}

func logo1() {
	l := `
$$$$$$$\            $$\            $$\                $$$$$$\            $$\
$$  __$$\           $$ |           $$ |              $$  __$$\           \__|
$$ |  $$ | $$$$$$\  $$ | $$$$$$\ $$$$$$\    $$$$$$\  $$ /  $$ | $$$$$$\  $$\
$$$$$$$\ |$$  __$$\ $$ |$$  __$$\\_$$  _|  $$  __$$\ $$$$$$$$ |$$  __$$\ $$ |
$$  __$$\ $$ /  $$ |$$ |$$$$$$$$ | $$ |    $$ /  $$ |$$  __$$ |$$ /  $$ |$$ |
$$ |  $$ |$$ |  $$ |$$ |$$   ____| $$ |$$\ $$ |  $$ |$$ |  $$ |$$ |  $$ |$$ |
$$$$$$$  |\$$$$$$  |$$ |\$$$$$$$\  \$$$$  |\$$$$$$  |$$ |  $$ |$$$$$$$  |$$ |
\_______/  \______/ \__| \_______|  \____/  \______/ \__|  \__|$$  ____/ \__|
                                                               $$ |
                                                               $$ |
                                                               \__|
	`
	fmt.Println(l)
	fmt.Println("Version: " + config.Get().Version)
}
<|endoftext|>


<commit_before>package main

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

func main() {
	fset := token.NewFileSet()
	pkgs, err := parser.ParseDir(fset, ".", isSrcFile, 0)
	if err != nil {
		fatal(err)
	}

	for _, ast := range pkgs {
		for _, f := range ast.Files {
			decls := findInterfaces(f.Decls)
			f.Decls = decls
			printer.Fprint(os.Stdout, fset, f)
		}
	}
}

func isSrcFile(info os.FileInfo) bool {
	return !strings.HasSuffix(info.Name(), "_test.go")
}

func findInterfaces(ds []ast.Decl) []ast.Decl {
	var decls []ast.Decl
	for _, d := range ds {
		genDecl, ok := d.(*ast.GenDecl)
		if !ok {
			continue
		}

		for _, spec := range genDecl.Specs {
			typeSpec, ok := spec.(*ast.TypeSpec)
			if !ok {
				continue
			}

			_, ok = typeSpec.Type.(*ast.InterfaceType)
			if !ok {
				continue
			}

			decls = append(decls, d)
		}
	}
	return decls
}

func fatal(err error) {
	fmt.Printf("Error %v\n", err)
	os.Exit(1)
}
<commit_msg>Write Fake struct to test package<commit_after>package main

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

func main() {
	fset := token.NewFileSet()
	pkgs, err := parser.ParseDir(fset, ".", isSrcFile, 0)
	if err != nil {
		fatal(err)
	}

	for _, p := range pkgs {
		for _, f := range p.Files {
			interfaceDecls := findInterfaces(f.Decls)
			decls := generateDecls(interfaceDecls)
			// ast.Print(fset, f)

			f.Decls = decls

			f.Name = ast.NewIdent("example_test")
			printer.Fprint(os.Stdout, fset, f)
		}
	}
}

func isSrcFile(info os.FileInfo) bool {
	return !strings.HasSuffix(info.Name(), "_test.go")
}

func findInterfaces(ds []ast.Decl) []ast.Decl {
	var decls []ast.Decl
	for _, d := range ds {
		genDecl, ok := d.(*ast.GenDecl)
		if !ok {
			continue
		}

		for _, spec := range genDecl.Specs {
			typeSpec, ok := spec.(*ast.TypeSpec)
			if !ok {
				continue
			}

			_, ok = typeSpec.Type.(*ast.InterfaceType)
			if !ok {
				continue
			}

			decls = append(decls, d)
		}
	}
	return decls
}

func generateDecls(ds []ast.Decl) []ast.Decl {
	var decls []ast.Decl
	for _, d := range ds {
		genDecl, ok := d.(*ast.GenDecl)
		if !ok {
			continue
		}

		for _, spec := range genDecl.Specs {
			typeSpec, ok := spec.(*ast.TypeSpec)
			if !ok {
				continue
			}

			interfaceType, ok := typeSpec.Type.(*ast.InterfaceType)
			if !ok {
				continue
			}

			// if we've made it this far, we have an interface to mock

			// start by prefixing the interface's name with "Fake"
			typeSpec.Name = ast.NewIdent("Fake" + typeSpec.Name.Name)

			// convert the interface into a struct
			structType := &ast.StructType{
				Struct:     interfaceType.Interface, // position of the interface keyword
				Fields:     &ast.FieldList{},        // no fields
				Incomplete: interfaceType.Incomplete,
			}
			typeSpec.Type = structType

			// save the decls into the slice
			decls = append(decls, d)

			// add FuncDecls for all the interface's methods
		}
	}
	return decls
}

func fatal(err error) {
	fmt.Printf("Error %v\n", err)
	os.Exit(1)
}
<|endoftext|>


<commit_before>// -------------------------------
// Overview of SDEES
// -------------------------------
//
// main.go:
// - Program entry
// - Processes flags
// - Initiates cleanup on close
// - Run program -> run() (run.go)
//
// run.go:
// - Handles importing/exporting
// - Pulls latest copy from server
// - Prompts for password
// - Starts new entry -> editEntry() (entries.go)
// - Pushes latest to server
//
// entries.go
// -  editEntry() opens vim, encrypts after saving and writes new entry
//
// -------------------------------
// Naming conventions
// -------------------------------
//
// Files are encrypted using GPG. The name of the files contain information
// about the date entry, the file contents, and the modification date. A typical
// filename is:
//
// yAkbAnL.onLBFi.dew9E6W.gpg
//    ^      ^      ^
//    |------------------- reversible hash-id of the date in the entry
//           |------------ 6-letter irreversible hash of the file contents
//                  |----- reversible hash-id of the modification date
//
// Multiple edits of the same entry will result in the same reversible hash-id of the date in the entry.
// A edit is determined when the 6-letter irreversible hash
// of the file contents changes. Upon this change, a new modification date is
// determined, which can be later used to sort the entries so that only the newest
// is displayed.

package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"os/signal"
	"os/user"
	"path"
	"strings"
	"syscall"

	home "github.com/mitchellh/go-homedir"
	"github.com/urfave/cli"
)

var Version string
var BuildTime string
var Build string

var RuntimeArgs struct {
	Passphrase       string
	ServerPassphrase string
	ImportFile       string
	ExportFile       string
	HomePath         string // home path, usually "~/"
	SSHKey           string // path to key, usually "~/.ssh/id_rsa"
	WorkingPath      string // main path, usually "~/.sdees/"
	FullPath         string // path with working file, usuallly "~/.sdees/notes.txt/"
	TempPath         string // usually "~/.sdees/temp/"
	SdeesDir         string // name of sdees dir, like ".sdees"
	NumberToShow     string
	TextSearch       string
	CurrentFileList  []string
	ServerFileSet    map[string]bool
	DontSync         bool
	OnlyPush         bool
	Push             bool
	Pull             bool
	Debug            bool
	EditWhole        bool
	EditLocally      bool
	ListFiles        bool
	UpdateSdees      bool
	Summarize        bool
	ConfigAgain      bool
}

var ConfigArgs struct {
	WorkingFile string
	ServerHost  string
	ServerPort  string
	ServerUser  string
	SdeesDir    string
}

func main() {

	// Handle Ctl+C from http://stackoverflow.com/questions/11268943/golang-is-it-possible-to-capture-a-ctrlc-signal-and-run-a-cleanup-function-in
	c := make(chan os.Signal, 2)
	signal.Notify(c, os.Interrupt, syscall.SIGTERM)
	go func() {
		<-c
		cleanUp()
		os.Exit(1)
	}()

	defer cleanUp()
	RuntimeArgs.SdeesDir = ".sdeesgo"
	if len(Build) == 0 {
		Build = "devdevdevdevdev"
	} else {
		Build = Build[0:7]
	}

	app := cli.NewApp()
	app.Name = "sdees"
	app.Version = Version + " " + Build + " " + BuildTime
	app.Usage = `SDEES is a program that allows Serverless Decentralized Editing of Encrypted Stuff. SDEES is for Syncing remote files, Decrypting, Editing, Encrypting, then Syncing back.

EXAMPLE USAGE:
   sdees new.txt # edit a new document, new.txt
   sdees --summary -n 5 # list a summary of last five entries
   sdees --search "dogs cats" # find all entries that mention 'dogs' or 'cats'`
	app.Action = func(c *cli.Context) error {
		// Set the log level
		fmt.Printf("sdees version %s (%s)\n", Version, Build)
		if RuntimeArgs.Debug == false {
			logger.Level(2)
		} else {
			logger.Level(0)
		}
		// Set the paths
		homeDir, _ := home.Dir()
		RuntimeArgs.HomePath = homeDir
		RuntimeArgs.WorkingPath = path.Join(homeDir, RuntimeArgs.SdeesDir)
		RuntimeArgs.SSHKey = path.Join(homeDir, ".ssh", "id_rsa")

		// Determine if intialization is needed
		if !exists(RuntimeArgs.WorkingPath) {
			initialize()
		}
		if !exists(path.Join(RuntimeArgs.WorkingPath, "config.json")) {
			initialize()
		} else {
			// Load prevoius parameters
			jsonBlob, _ := ioutil.ReadFile(path.Join(RuntimeArgs.WorkingPath, "config.json"))
			err := json.Unmarshal(jsonBlob, &ConfigArgs)
			if err != nil {
				log.Fatal(err)
			}
		}

		workingFile := c.Args().Get(0)
		if len(workingFile) > 0 {
			num, isNum := isNumber(workingFile)
			if isNum {
				allFiles := getFileList()
				workingFile = allFiles[num]
			}
			ConfigArgs.WorkingFile = workingFile
		}
		logger.Debug("Working file: %s", ConfigArgs.WorkingFile)

		// Save current config parameters
		b, err := json.Marshal(ConfigArgs)
		if err != nil {
			log.Println(err)
		}
		ioutil.WriteFile(path.Join(RuntimeArgs.WorkingPath, "config.json"), b, 0644)

		RuntimeArgs.FullPath = path.Join(RuntimeArgs.WorkingPath, ConfigArgs.WorkingFile)
		if !exists(RuntimeArgs.FullPath) {
			err := os.MkdirAll(RuntimeArgs.FullPath, 0711)
			if err != nil {
				log.Fatal(err)
			}
		}

		RuntimeArgs.TempPath = path.Join(RuntimeArgs.WorkingPath, "temp")
		if !exists(RuntimeArgs.TempPath) {
			err := os.MkdirAll(RuntimeArgs.TempPath, 0711)
			if err != nil {
				log.Fatal(err)
			}
		}

		// Run Importing/Exporting
		if len(RuntimeArgs.ImportFile) > 0 {
			importFile(RuntimeArgs.ImportFile)
			return nil
		}
		if len(RuntimeArgs.ExportFile) > 0 {
			exportFile(RuntimeArgs.ExportFile)
			return nil
		}

		// Re-initializing
		if RuntimeArgs.ConfigAgain {
			initialize()
			return nil
		}

		// Updating
		if RuntimeArgs.UpdateSdees {
			update()
			return nil
		}

		// List files if needed
		if RuntimeArgs.ListFiles {
			printFileList()
			return nil
		}

		// Get current file list
		RuntimeArgs.CurrentFileList = getEntryList()

		// run main app (run.go)
		run()
		return nil
	}
	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:        "nosync, d",
			Usage:       "Prevent syncing",
			Destination: &RuntimeArgs.DontSync,
		},
		cli.BoolFlag{
			Name:        "push, p",
			Usage:       "Only push, prevents pulling",
			Destination: &RuntimeArgs.OnlyPush,
		},
		cli.BoolFlag{
			Name:        "edit, e",
			Usage:       "Edit whole document",
			Destination: &RuntimeArgs.EditWhole,
		},
		cli.BoolFlag{
			Name:        "summary",
			Usage:       "Summarize",
			Destination: &RuntimeArgs.Summarize,
		},
		cli.StringFlag{
			Name:        "number, n",
			Usage:       "Limit number shown",
			Destination: &RuntimeArgs.NumberToShow,
		},
		cli.StringFlag{
			Name:        "search, s",
			Usage:       "View only entries that contain `TEXT`",
			Destination: &RuntimeArgs.TextSearch,
		},
		cli.BoolFlag{
			Name:        "debug",
			Usage:       "Turn on debug mode",
			Destination: &RuntimeArgs.Debug,
		},
		cli.BoolFlag{
			Name:        "config",
			Usage:       "Edit configuration parameters",
			Destination: &RuntimeArgs.ConfigAgain,
		},
		cli.BoolFlag{
			Name:        "update",
			Usage:       "Update sdees (requires Linux, Go1.6+)",
			Destination: &RuntimeArgs.UpdateSdees,
		},
		cli.BoolFlag{
			Name:        "list, ls",
			Usage:       "List available files",
			Destination: &RuntimeArgs.ListFiles,
		},
		cli.StringFlag{
			Name:        "import",
			Usage:       "Import text from `FILE`",
			Destination: &RuntimeArgs.ImportFile,
		},
		cli.StringFlag{
			Name:        "export",
			Usage:       "Export text from `FILE`",
			Destination: &RuntimeArgs.ExportFile,
		},
	}
	app.Run(os.Args)
}

func initialize() {
	// Make directory
	err := os.MkdirAll(RuntimeArgs.WorkingPath, 0711)
	if err != nil {
		log.Println("Error creating directory")
		log.Println(err)
		return
	}
	fmt.Println("sdees has capability to SSH tunnel to a remote host in order to \nkeep files synced across devices. If this is not needed, just use defaults.")
	fmt.Print("Enter remote address (default: localhost): ")
	fmt.Scanln(&ConfigArgs.ServerHost)
	if len(ConfigArgs.ServerHost) == 0 {
		ConfigArgs.ServerHost = "localhost"
	}

	currentUser, _ := user.Current()
	fmt.Printf("Enter remote user (default: %s): ", currentUser.Username)
	fmt.Scanln(&ConfigArgs.ServerUser)
	if len(ConfigArgs.ServerUser) == 0 {
		ConfigArgs.ServerUser = currentUser.Username
	}

	fmt.Printf("Enter remote port (default: %s): ", "22")
	fmt.Scanln(&ConfigArgs.ServerPort)
	if len(ConfigArgs.ServerPort) == 0 {
		ConfigArgs.ServerPort = "22"
	}

	if len(ConfigArgs.WorkingFile) == 0 {
		fmt.Printf("Enter new file (default: %s): ", "notes.txt")
		fmt.Scanln(&ConfigArgs.WorkingFile)
		if len(ConfigArgs.WorkingFile) == 0 {
			ConfigArgs.WorkingFile = "notes.txt"
		}
	}

	b, err := json.Marshal(ConfigArgs)
	if err != nil {
		log.Println(err)
	}
	ioutil.WriteFile(path.Join(RuntimeArgs.WorkingPath, "config.json"), b, 0644)

}

func update() {
	if !HasInternetAccess() {
		fmt.Println("Cannot access internet to update.")
		return
	}
	out, err := exec.Command("sdees", "--version").Output()
	if err == nil {
		fmt.Println("Current version:")
		fmt.Println(string(out))
	}
	fullCommand := strings.Split("git clone https://github.com/schollz/sdees.git tempsdees", " ")
	if err := exec.Command(fullCommand[0], fullCommand[1:]...).Run(); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}

	os.Chdir("./tempsdees")

	fullCommand = strings.Split("make install", " ")
	if err := exec.Command(fullCommand[0], fullCommand[1:]...).Run(); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}

	os.Chdir("../")
	fullCommand = strings.Split("rm -rf ./tempsdees", " ")
	if err := exec.Command(fullCommand[0], fullCommand[1:]...).Run(); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}

	out, err = exec.Command("sdees", "--version").Output()
	if err == nil {
		fmt.Println("Updated to version:")
		fmt.Println(string(out))
	}

}
<commit_msg>Changed flag for local editing<commit_after>// -------------------------------
// Overview of SDEES
// -------------------------------
//
// main.go:
// - Program entry
// - Processes flags
// - Initiates cleanup on close
// - Run program -> run() (run.go)
//
// run.go:
// - Handles importing/exporting
// - Pulls latest copy from server
// - Prompts for password
// - Starts new entry -> editEntry() (entries.go)
// - Pushes latest to server
//
// entries.go
// -  editEntry() opens vim, encrypts after saving and writes new entry
//
// -------------------------------
// Naming conventions
// -------------------------------
//
// Files are encrypted using GPG. The name of the files contain information
// about the date entry, the file contents, and the modification date. A typical
// filename is:
//
// yAkbAnL.onLBFi.dew9E6W.gpg
//    ^      ^      ^
//    |------------------- reversible hash-id of the date in the entry
//           |------------ 6-letter irreversible hash of the file contents
//                  |----- reversible hash-id of the modification date
//
// Multiple edits of the same entry will result in the same reversible hash-id of the date in the entry.
// A edit is determined when the 6-letter irreversible hash
// of the file contents changes. Upon this change, a new modification date is
// determined, which can be later used to sort the entries so that only the newest
// is displayed.

package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"os/signal"
	"os/user"
	"path"
	"strings"
	"syscall"

	home "github.com/mitchellh/go-homedir"
	"github.com/urfave/cli"
)

var Version string
var BuildTime string
var Build string

var RuntimeArgs struct {
	Passphrase       string
	ServerPassphrase string
	ImportFile       string
	ExportFile       string
	HomePath         string // home path, usually "~/"
	SSHKey           string // path to key, usually "~/.ssh/id_rsa"
	WorkingPath      string // main path, usually "~/.sdees/"
	FullPath         string // path with working file, usuallly "~/.sdees/notes.txt/"
	TempPath         string // usually "~/.sdees/temp/"
	SdeesDir         string // name of sdees dir, like ".sdees"
	NumberToShow     string
	TextSearch       string
	CurrentFileList  []string
	ServerFileSet    map[string]bool
	DontSync         bool
	OnlyPush         bool
	Push             bool
	Pull             bool
	Debug            bool
	EditWhole        bool
	EditLocally      bool
	ListFiles        bool
	UpdateSdees      bool
	Summarize        bool
	ConfigAgain      bool
}

var ConfigArgs struct {
	WorkingFile string
	ServerHost  string
	ServerPort  string
	ServerUser  string
	SdeesDir    string
}

func main() {

	// Handle Ctl+C from http://stackoverflow.com/questions/11268943/golang-is-it-possible-to-capture-a-ctrlc-signal-and-run-a-cleanup-function-in
	c := make(chan os.Signal, 2)
	signal.Notify(c, os.Interrupt, syscall.SIGTERM)
	go func() {
		<-c
		cleanUp()
		os.Exit(1)
	}()

	defer cleanUp()
	RuntimeArgs.SdeesDir = ".sdeesgo"
	if len(Build) == 0 {
		Build = "devdevdevdevdev"
	} else {
		Build = Build[0:7]
	}

	app := cli.NewApp()
	app.Name = "sdees"
	app.Version = Version + " " + Build + " " + BuildTime
	app.Usage = `SDEES is a program that allows Serverless Decentralized Editing of Encrypted Stuff. SDEES is for Syncing remote files, Decrypting, Editing, Encrypting, then Syncing back.

EXAMPLE USAGE:
   sdees new.txt # edit a new document, new.txt
   sdees --summary -n 5 # list a summary of last five entries
   sdees --search "dogs cats" # find all entries that mention 'dogs' or 'cats'`
	app.Action = func(c *cli.Context) error {
		// Set the log level
		fmt.Printf("sdees version %s (%s)\n", Version, Build)
		if RuntimeArgs.Debug == false {
			logger.Level(2)
		} else {
			logger.Level(0)
		}
		// Set the paths
		homeDir, _ := home.Dir()
		RuntimeArgs.HomePath = homeDir
		RuntimeArgs.WorkingPath = path.Join(homeDir, RuntimeArgs.SdeesDir)
		RuntimeArgs.SSHKey = path.Join(homeDir, ".ssh", "id_rsa")

		// Determine if intialization is needed
		if !exists(RuntimeArgs.WorkingPath) {
			initialize()
		}
		if !exists(path.Join(RuntimeArgs.WorkingPath, "config.json")) {
			initialize()
		} else {
			// Load prevoius parameters
			jsonBlob, _ := ioutil.ReadFile(path.Join(RuntimeArgs.WorkingPath, "config.json"))
			err := json.Unmarshal(jsonBlob, &ConfigArgs)
			if err != nil {
				log.Fatal(err)
			}
		}

		workingFile := c.Args().Get(0)
		if len(workingFile) > 0 {
			num, isNum := isNumber(workingFile)
			if isNum {
				allFiles := getFileList()
				workingFile = allFiles[num]
			}
			ConfigArgs.WorkingFile = workingFile
		}
		logger.Debug("Working file: %s", ConfigArgs.WorkingFile)

		// Save current config parameters
		b, err := json.Marshal(ConfigArgs)
		if err != nil {
			log.Println(err)
		}
		ioutil.WriteFile(path.Join(RuntimeArgs.WorkingPath, "config.json"), b, 0644)

		RuntimeArgs.FullPath = path.Join(RuntimeArgs.WorkingPath, ConfigArgs.WorkingFile)
		if !exists(RuntimeArgs.FullPath) {
			err := os.MkdirAll(RuntimeArgs.FullPath, 0711)
			if err != nil {
				log.Fatal(err)
			}
		}

		RuntimeArgs.TempPath = path.Join(RuntimeArgs.WorkingPath, "temp")
		if !exists(RuntimeArgs.TempPath) {
			err := os.MkdirAll(RuntimeArgs.TempPath, 0711)
			if err != nil {
				log.Fatal(err)
			}
		}

		// Run Importing/Exporting
		if len(RuntimeArgs.ImportFile) > 0 {
			importFile(RuntimeArgs.ImportFile)
			return nil
		}
		if len(RuntimeArgs.ExportFile) > 0 {
			exportFile(RuntimeArgs.ExportFile)
			return nil
		}

		// Re-initializing
		if RuntimeArgs.ConfigAgain {
			initialize()
			return nil
		}

		// Updating
		if RuntimeArgs.UpdateSdees {
			update()
			return nil
		}

		// List files if needed
		if RuntimeArgs.ListFiles {
			printFileList()
			return nil
		}

		// Get current file list
		RuntimeArgs.CurrentFileList = getEntryList()

		// run main app (run.go)
		run()
		return nil
	}
	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:        "local, l",
			Usage:       "Local editing (no syncing)",
			Destination: &RuntimeArgs.DontSync,
		},
		cli.BoolFlag{
			Name:        "push, p",
			Usage:       "Only push, prevents pulling",
			Destination: &RuntimeArgs.OnlyPush,
		},
		cli.BoolFlag{
			Name:        "edit, e",
			Usage:       "Edit whole document",
			Destination: &RuntimeArgs.EditWhole,
		},
		cli.BoolFlag{
			Name:        "summary",
			Usage:       "Summarize",
			Destination: &RuntimeArgs.Summarize,
		},
		cli.StringFlag{
			Name:        "number, n",
			Usage:       "Limit number shown",
			Destination: &RuntimeArgs.NumberToShow,
		},
		cli.StringFlag{
			Name:        "search, s",
			Usage:       "View only entries that contain `TEXT`",
			Destination: &RuntimeArgs.TextSearch,
		},
		cli.BoolFlag{
			Name:        "debug",
			Usage:       "Turn on debug mode",
			Destination: &RuntimeArgs.Debug,
		},
		cli.BoolFlag{
			Name:        "config",
			Usage:       "Edit configuration parameters",
			Destination: &RuntimeArgs.ConfigAgain,
		},
		cli.BoolFlag{
			Name:        "update",
			Usage:       "Update sdees (requires Linux, Go1.6+)",
			Destination: &RuntimeArgs.UpdateSdees,
		},
		cli.BoolFlag{
			Name:        "list, ls",
			Usage:       "List available files",
			Destination: &RuntimeArgs.ListFiles,
		},
		cli.StringFlag{
			Name:        "import",
			Usage:       "Import text from `FILE`",
			Destination: &RuntimeArgs.ImportFile,
		},
		cli.StringFlag{
			Name:        "export",
			Usage:       "Export text from `FILE`",
			Destination: &RuntimeArgs.ExportFile,
		},
	}
	app.Run(os.Args)
}

func initialize() {
	// Make directory
	err := os.MkdirAll(RuntimeArgs.WorkingPath, 0711)
	if err != nil {
		log.Println("Error creating directory")
		log.Println(err)
		return
	}
	fmt.Println("sdees has capability to SSH tunnel to a remote host in order to \nkeep files synced across devices. If this is not needed, just use defaults.")
	fmt.Print("Enter remote address (default: localhost): ")
	fmt.Scanln(&ConfigArgs.ServerHost)
	if len(ConfigArgs.ServerHost) == 0 {
		ConfigArgs.ServerHost = "localhost"
	}

	currentUser, _ := user.Current()
	fmt.Printf("Enter remote user (default: %s): ", currentUser.Username)
	fmt.Scanln(&ConfigArgs.ServerUser)
	if len(ConfigArgs.ServerUser) == 0 {
		ConfigArgs.ServerUser = currentUser.Username
	}

	fmt.Printf("Enter remote port (default: %s): ", "22")
	fmt.Scanln(&ConfigArgs.ServerPort)
	if len(ConfigArgs.ServerPort) == 0 {
		ConfigArgs.ServerPort = "22"
	}

	if len(ConfigArgs.WorkingFile) == 0 {
		fmt.Printf("Enter new file (default: %s): ", "notes.txt")
		fmt.Scanln(&ConfigArgs.WorkingFile)
		if len(ConfigArgs.WorkingFile) == 0 {
			ConfigArgs.WorkingFile = "notes.txt"
		}
	}

	b, err := json.Marshal(ConfigArgs)
	if err != nil {
		log.Println(err)
	}
	ioutil.WriteFile(path.Join(RuntimeArgs.WorkingPath, "config.json"), b, 0644)

}

func update() {
	if !HasInternetAccess() {
		fmt.Println("Cannot access internet to update.")
		return
	}
	out, err := exec.Command("sdees", "--version").Output()
	if err == nil {
		fmt.Println("Current version:")
		fmt.Println(string(out))
	}
	fullCommand := strings.Split("git clone https://github.com/schollz/sdees.git tempsdees", " ")
	if err := exec.Command(fullCommand[0], fullCommand[1:]...).Run(); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}

	os.Chdir("./tempsdees")

	fullCommand = strings.Split("make install", " ")
	if err := exec.Command(fullCommand[0], fullCommand[1:]...).Run(); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}

	os.Chdir("../")
	fullCommand = strings.Split("rm -rf ./tempsdees", " ")
	if err := exec.Command(fullCommand[0], fullCommand[1:]...).Run(); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}

	out, err = exec.Command("sdees", "--version").Output()
	if err == nil {
		fmt.Println("Updated to version:")
		fmt.Println(string(out))
	}

}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"

	"github.com/codegangsta/cli"
	"github.com/codegangsta/envy/lib"
	"github.com/codegangsta/gin/lib"

	"log"
	"os"
	"os/signal"
	"path/filepath"
	"strconv"
	"syscall"
	"time"
)

var (
	startTime  = time.Now()
	logger     = log.New(os.Stdout, "[gin] ", 0)
	immediate  = false
	buildError error
)

func main() {
	app := cli.NewApp()
	app.Name = "gin"
	app.Usage = "A live reload utility for Go web applications."
	app.Action = MainAction
	app.Flags = []cli.Flag{
		cli.IntFlag{
			Name:  "port,p",
			Value: 3000,
			Usage: "port for the proxy server",
		},
		cli.IntFlag{
			Name:  "appPort,a",
			Value: 3001,
			Usage: "port for the Go web server",
		},
		cli.StringFlag{
			Name:  "bin,b",
			Value: "gin-bin",
			Usage: "name of generated binary file",
		},
		cli.StringFlag{
			Name:  "path,t",
			Value: ".",
			Usage: "Path to watch files from",
		},
		cli.BoolFlag{
			Name:  "immediate,i",
			Usage: "run the server immediately after it's built",
		},
		cli.BoolFlag{
			Name:  "godep,g",
			Usage: "use godep when building",
		},
	}
	app.Commands = []cli.Command{
		{
			Name:      "run",
			ShortName: "r",
			Usage:     "Run the gin proxy in the current working directory",
			Action:    MainAction,
		},
		{
			Name:      "env",
			ShortName: "e",
			Usage:     "Display environment variables set by the .env file",
			Action:    EnvAction,
		},
	}

	app.Run(os.Args)
}

func MainAction(c *cli.Context) {
	port := c.GlobalInt("port")
	appPort := strconv.Itoa(c.GlobalInt("appPort"))
	immediate = c.GlobalBool("immediate")

	// Bootstrap the environment
	envy.Bootstrap()

	// Set the PORT env
	os.Setenv("PORT", appPort)

	wd, err := os.Getwd()
	if err != nil {
		logger.Fatal(err)
	}

	builder := gin.NewBuilder(c.GlobalString("path"), c.GlobalString("bin"), c.GlobalBool("godep"))
	runner := gin.NewRunner(filepath.Join(wd, builder.Binary()), c.Args()...)
	runner.SetWriter(os.Stdout)
	proxy := gin.NewProxy(builder, runner)

	config := &gin.Config{
		Port:    port,
		ProxyTo: "http://localhost:" + appPort,
	}

	err = proxy.Run(config)
	if err != nil {
		logger.Fatal(err)
	}

	logger.Printf("listening on port %d\n", port)

	shutdown(runner)

	// build right now
	build(builder, runner, logger)

	// scan for changes
	scanChanges(c.GlobalString("path"), func(path string) {
		runner.Kill()
		build(builder, runner, logger)
	})
}

func EnvAction(c *cli.Context) {
	// Bootstrap the environment
	env, err := envy.Bootstrap()
	if err != nil {
		logger.Fatalln(err)
	}

	for k, v := range env {
		fmt.Printf("%s: %s\n", k, v)
	}

}

func build(builder gin.Builder, runner gin.Runner, logger *log.Logger) {
	err := builder.Build()
	if err != nil {
		buildError = err
		logger.Println("ERROR! Build failed.")
		fmt.Println(builder.Errors())
	} else {
		// print success only if there were errors before
		if buildError != nil {
			logger.Println("Build Successful")
		}
		buildError = nil
		if immediate {
			runner.Run()
		}
	}

	time.Sleep(100 * time.Millisecond)
}

type scanCallback func(path string)

func scanChanges(watchPath string, cb scanCallback) {
	for {
		filepath.Walk(watchPath, func(path string, info os.FileInfo, err error) error {
			if path == ".git" {
				return filepath.SkipDir
			}

			// ignore hidden files
			if filepath.Base(path)[0] == '.' {
				return nil
			}

			ext := filepath.Ext(path)
			if ext == ".go" || ext == ".html" && info.ModTime().After(startTime) {
				cb(path)
				startTime = time.Now()
				return errors.New("done")
			}

			return nil
		})
		time.Sleep(500 * time.Millisecond)
	}
}

func shutdown(runner gin.Runner) {
	c := make(chan os.Signal, 2)
	signal.Notify(c, os.Interrupt, syscall.SIGTERM)
	go func() {
		s := <-c
		log.Println("Got signal: ", s)
		err := runner.Kill()
		if err != nil {
			log.Print("Error killing: ", err)
		}
		os.Exit(1)
	}()
}
<commit_msg>Super simple logic fix<commit_after>package main

import (
	"errors"
	"fmt"

	"github.com/codegangsta/cli"
	"github.com/codegangsta/envy/lib"
	"github.com/codegangsta/gin/lib"

	"log"
	"os"
	"os/signal"
	"path/filepath"
	"strconv"
	"syscall"
	"time"
)

var (
	startTime  = time.Now()
	logger     = log.New(os.Stdout, "[gin] ", 0)
	immediate  = false
	buildError error
)

func main() {
	app := cli.NewApp()
	app.Name = "gin"
	app.Usage = "A live reload utility for Go web applications."
	app.Action = MainAction
	app.Flags = []cli.Flag{
		cli.IntFlag{
			Name:  "port,p",
			Value: 3000,
			Usage: "port for the proxy server",
		},
		cli.IntFlag{
			Name:  "appPort,a",
			Value: 3001,
			Usage: "port for the Go web server",
		},
		cli.StringFlag{
			Name:  "bin,b",
			Value: "gin-bin",
			Usage: "name of generated binary file",
		},
		cli.StringFlag{
			Name:  "path,t",
			Value: ".",
			Usage: "Path to watch files from",
		},
		cli.BoolFlag{
			Name:  "immediate,i",
			Usage: "run the server immediately after it's built",
		},
		cli.BoolFlag{
			Name:  "godep,g",
			Usage: "use godep when building",
		},
	}
	app.Commands = []cli.Command{
		{
			Name:      "run",
			ShortName: "r",
			Usage:     "Run the gin proxy in the current working directory",
			Action:    MainAction,
		},
		{
			Name:      "env",
			ShortName: "e",
			Usage:     "Display environment variables set by the .env file",
			Action:    EnvAction,
		},
	}

	app.Run(os.Args)
}

func MainAction(c *cli.Context) {
	port := c.GlobalInt("port")
	appPort := strconv.Itoa(c.GlobalInt("appPort"))
	immediate = c.GlobalBool("immediate")

	// Bootstrap the environment
	envy.Bootstrap()

	// Set the PORT env
	os.Setenv("PORT", appPort)

	wd, err := os.Getwd()
	if err != nil {
		logger.Fatal(err)
	}

	builder := gin.NewBuilder(c.GlobalString("path"), c.GlobalString("bin"), c.GlobalBool("godep"))
	runner := gin.NewRunner(filepath.Join(wd, builder.Binary()), c.Args()...)
	runner.SetWriter(os.Stdout)
	proxy := gin.NewProxy(builder, runner)

	config := &gin.Config{
		Port:    port,
		ProxyTo: "http://localhost:" + appPort,
	}

	err = proxy.Run(config)
	if err != nil {
		logger.Fatal(err)
	}

	logger.Printf("listening on port %d\n", port)

	shutdown(runner)

	// build right now
	build(builder, runner, logger)

	// scan for changes
	scanChanges(c.GlobalString("path"), func(path string) {
		runner.Kill()
		build(builder, runner, logger)
	})
}

func EnvAction(c *cli.Context) {
	// Bootstrap the environment
	env, err := envy.Bootstrap()
	if err != nil {
		logger.Fatalln(err)
	}

	for k, v := range env {
		fmt.Printf("%s: %s\n", k, v)
	}

}

func build(builder gin.Builder, runner gin.Runner, logger *log.Logger) {
	err := builder.Build()
	if err != nil {
		buildError = err
		logger.Println("ERROR! Build failed.")
		fmt.Println(builder.Errors())
	} else {
		// print success only if there were errors before
		if buildError != nil {
			logger.Println("Build Successful")
		}
		buildError = nil
		if immediate {
			runner.Run()
		}
	}

	time.Sleep(100 * time.Millisecond)
}

type scanCallback func(path string)

func scanChanges(watchPath string, cb scanCallback) {
	for {
		filepath.Walk(watchPath, func(path string, info os.FileInfo, err error) error {
			if path == ".git" {
				return filepath.SkipDir
			}

			// ignore hidden files
			if filepath.Base(path)[0] == '.' {
				return nil
			}

			ext := filepath.Ext(path)
			if (ext == ".go" || ext == ".html") && info.ModTime().After(startTime) {
				cb(path)
				startTime = time.Now()
				return errors.New("done")
			}

			return nil
		})
		time.Sleep(500 * time.Millisecond)
	}
}

func shutdown(runner gin.Runner) {
	c := make(chan os.Signal, 2)
	signal.Notify(c, os.Interrupt, syscall.SIGTERM)
	go func() {
		s := <-c
		log.Println("Got signal: ", s)
		err := runner.Kill()
		if err != nil {
			log.Print("Error killing: ", err)
		}
		os.Exit(1)
	}()
}
<|endoftext|>


<commit_before>// Copyright 2017 The Kubernetes Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cronjob

import (
	"context"

	batch "k8s.io/api/batch/v1"
	meta "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/apimachinery/pkg/util/rand"
	client "k8s.io/client-go/kubernetes"

	"k8s.io/dashboard/api/pkg/api"
	"k8s.io/dashboard/api/pkg/errors"
	metricapi "k8s.io/dashboard/api/pkg/integration/metric/api"
	"k8s.io/dashboard/api/pkg/resource/common"
	"k8s.io/dashboard/api/pkg/resource/dataselect"
	"k8s.io/dashboard/api/pkg/resource/job"
)

const (
	CronJobAPIVersion = "v1"
	CronJobKindName   = "cronjob"
)

var emptyJobList = &job.JobList{
	Jobs:   make([]job.Job, 0),
	Errors: make([]error, 0),
	ListMeta: api.ListMeta{
		TotalItems: 0,
	},
}

// GetCronJobJobs returns list of jobs owned by cron job.
func GetCronJobJobs(client client.Interface, metricClient metricapi.MetricClient,
	dsQuery *dataselect.DataSelectQuery, namespace, name string, active bool) (*job.JobList, error) {

	cronJob, err := client.BatchV1beta1().CronJobs(namespace).Get(context.TODO(), name, meta.GetOptions{})
	if err != nil {
		return emptyJobList, err
	}

	channels := &common.ResourceChannels{
		JobList:   common.GetJobListChannel(client, common.NewSameNamespaceQuery(namespace), 1),
		PodList:   common.GetPodListChannel(client, common.NewSameNamespaceQuery(namespace), 1),
		EventList: common.GetEventListChannel(client, common.NewSameNamespaceQuery(namespace), 1),
	}

	jobs := <-channels.JobList.List
	err = <-channels.JobList.Error
	nonCriticalErrors, criticalError := errors.HandleError(err)
	if criticalError != nil {
		return emptyJobList, nil
	}

	pods := <-channels.PodList.List
	err = <-channels.PodList.Error
	nonCriticalErrors, criticalError = errors.AppendError(err, nonCriticalErrors)
	if criticalError != nil {
		return emptyJobList, criticalError
	}

	events := <-channels.EventList.List
	err = <-channels.EventList.Error
	nonCriticalErrors, criticalError = errors.AppendError(err, nonCriticalErrors)
	if criticalError != nil {
		return emptyJobList, criticalError
	}

	jobs.Items = filterJobsByOwnerUID(cronJob.UID, jobs.Items)
	jobs.Items = filterJobsByState(active, jobs.Items)

	return job.ToJobList(jobs.Items, pods.Items, events.Items, nonCriticalErrors, dsQuery, metricClient), nil
}

// TriggerCronJob manually triggers a cron job and creates a new job.
func TriggerCronJob(client client.Interface,
	namespace, name string) error {

	cronJob, err := client.BatchV1().CronJobs(namespace).Get(context.TODO(), name, meta.GetOptions{})

	if err != nil {
		return err
	}

	annotations := make(map[string]string)
	annotations["cronjob.kubernetes.io/instantiate"] = "manual"

	labels := make(map[string]string)
	for k, v := range cronJob.Spec.JobTemplate.Labels {
		labels[k] = v
	}

	//job name cannot exceed DNS1053LabelMaxLength (52 characters)
	var newJobName string
	if len(cronJob.Name) < 42 {
		newJobName = cronJob.Name + "-manual-" + rand.String(3)
	} else {
		newJobName = cronJob.Name[0:41] + "-manual-" + rand.String(3)
	}

	jobToCreate := &batch.Job{
		ObjectMeta: meta.ObjectMeta{
			Name:        newJobName,
			Namespace:   namespace,
			Annotations: annotations,
			Labels:      labels,
			OwnerReferences: []meta.OwnerReference{{
				APIVersion: CronJobAPIVersion,
				Kind:       CronJobKindName,
				Name:       cronJob.Name,
				UID:        cronJob.UID,
			}},
		},
		Spec: cronJob.Spec.JobTemplate.Spec,
	}

	_, err = client.BatchV1().Jobs(namespace).Create(context.TODO(), jobToCreate, meta.CreateOptions{})

	if err != nil {
		return err
	}

	return nil
}

func filterJobsByOwnerUID(UID types.UID, jobs []batch.Job) (matchingJobs []batch.Job) {
	for _, j := range jobs {
		for _, i := range j.OwnerReferences {
			if i.UID == UID {
				matchingJobs = append(matchingJobs, j)
				break
			}
		}
	}
	return
}

func filterJobsByState(active bool, jobs []batch.Job) (matchingJobs []batch.Job) {
	for _, j := range jobs {
		if active && j.Status.Active > 0 {
			matchingJobs = append(matchingJobs, j)
		} else if !active && j.Status.Active == 0 {
			matchingJobs = append(matchingJobs, j)
		} else {
			//sup
		}
	}
	return
}
<commit_msg>Use batch/v1 for fetching cronjobs (#7465)<commit_after>// Copyright 2017 The Kubernetes Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cronjob

import (
	"context"

	batch "k8s.io/api/batch/v1"
	meta "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/apimachinery/pkg/util/rand"
	client "k8s.io/client-go/kubernetes"

	"k8s.io/dashboard/api/pkg/api"
	"k8s.io/dashboard/api/pkg/errors"
	metricapi "k8s.io/dashboard/api/pkg/integration/metric/api"
	"k8s.io/dashboard/api/pkg/resource/common"
	"k8s.io/dashboard/api/pkg/resource/dataselect"
	"k8s.io/dashboard/api/pkg/resource/job"
)

const (
	CronJobAPIVersion = "v1"
	CronJobKindName   = "cronjob"
)

var emptyJobList = &job.JobList{
	Jobs:   make([]job.Job, 0),
	Errors: make([]error, 0),
	ListMeta: api.ListMeta{
		TotalItems: 0,
	},
}

// GetCronJobJobs returns list of jobs owned by cron job.
func GetCronJobJobs(client client.Interface, metricClient metricapi.MetricClient,
	dsQuery *dataselect.DataSelectQuery, namespace, name string, active bool) (*job.JobList, error) {

	cronJob, err := client.BatchV1().CronJobs(namespace).Get(context.TODO(), name, meta.GetOptions{})
	if err != nil {
		return emptyJobList, err
	}

	channels := &common.ResourceChannels{
		JobList:   common.GetJobListChannel(client, common.NewSameNamespaceQuery(namespace), 1),
		PodList:   common.GetPodListChannel(client, common.NewSameNamespaceQuery(namespace), 1),
		EventList: common.GetEventListChannel(client, common.NewSameNamespaceQuery(namespace), 1),
	}

	jobs := <-channels.JobList.List
	err = <-channels.JobList.Error
	nonCriticalErrors, criticalError := errors.HandleError(err)
	if criticalError != nil {
		return emptyJobList, nil
	}

	pods := <-channels.PodList.List
	err = <-channels.PodList.Error
	nonCriticalErrors, criticalError = errors.AppendError(err, nonCriticalErrors)
	if criticalError != nil {
		return emptyJobList, criticalError
	}

	events := <-channels.EventList.List
	err = <-channels.EventList.Error
	nonCriticalErrors, criticalError = errors.AppendError(err, nonCriticalErrors)
	if criticalError != nil {
		return emptyJobList, criticalError
	}

	jobs.Items = filterJobsByOwnerUID(cronJob.UID, jobs.Items)
	jobs.Items = filterJobsByState(active, jobs.Items)

	return job.ToJobList(jobs.Items, pods.Items, events.Items, nonCriticalErrors, dsQuery, metricClient), nil
}

// TriggerCronJob manually triggers a cron job and creates a new job.
func TriggerCronJob(client client.Interface,
	namespace, name string) error {

	cronJob, err := client.BatchV1().CronJobs(namespace).Get(context.TODO(), name, meta.GetOptions{})

	if err != nil {
		return err
	}

	annotations := make(map[string]string)
	annotations["cronjob.kubernetes.io/instantiate"] = "manual"

	labels := make(map[string]string)
	for k, v := range cronJob.Spec.JobTemplate.Labels {
		labels[k] = v
	}

	//job name cannot exceed DNS1053LabelMaxLength (52 characters)
	var newJobName string
	if len(cronJob.Name) < 42 {
		newJobName = cronJob.Name + "-manual-" + rand.String(3)
	} else {
		newJobName = cronJob.Name[0:41] + "-manual-" + rand.String(3)
	}

	jobToCreate := &batch.Job{
		ObjectMeta: meta.ObjectMeta{
			Name:        newJobName,
			Namespace:   namespace,
			Annotations: annotations,
			Labels:      labels,
			OwnerReferences: []meta.OwnerReference{{
				APIVersion: CronJobAPIVersion,
				Kind:       CronJobKindName,
				Name:       cronJob.Name,
				UID:        cronJob.UID,
			}},
		},
		Spec: cronJob.Spec.JobTemplate.Spec,
	}

	_, err = client.BatchV1().Jobs(namespace).Create(context.TODO(), jobToCreate, meta.CreateOptions{})

	if err != nil {
		return err
	}

	return nil
}

func filterJobsByOwnerUID(UID types.UID, jobs []batch.Job) (matchingJobs []batch.Job) {
	for _, j := range jobs {
		for _, i := range j.OwnerReferences {
			if i.UID == UID {
				matchingJobs = append(matchingJobs, j)
				break
			}
		}
	}
	return
}

func filterJobsByState(active bool, jobs []batch.Job) (matchingJobs []batch.Job) {
	for _, j := range jobs {
		if active && j.Status.Active > 0 {
			matchingJobs = append(matchingJobs, j)
		} else if !active && j.Status.Active == 0 {
			matchingJobs = append(matchingJobs, j)
		} else {
			//sup
		}
	}
	return
}
<|endoftext|>


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

package main

import (
	"bytes"
	"flag"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"text/tabwriter"

	"github.com/pkg/errors"
	"github.com/sdboyer/gps"
)

const (
	manifestName = "manifest.json"
	lockName     = "lock.json"
)

var (
	depContext *ctx
	verbose    = flag.Bool("v", false, "enable verbose logging")
)

type command interface {
	Name() string           // "foobar"
	Args() string           // "<baz> [quux...]"
	ShortHelp() string      // "Foo the first bar"
	LongHelp() string       // "Foo the first bar meeting the following conditions..."
	Register(*flag.FlagSet) // command-specific flags
	Hidden() bool           // indicates whether the command should be hidden from help output
	Run([]string) error
}

func main() {

	// Build the list of available commands.
	commands := []command{
		&initCommand{},
		&statusCommand{},
		&ensureCommand{},
		&removeCommand{},
		&hashinCommand{},
	}

	usage := func() {
		fmt.Fprintln(os.Stderr, "Usage: dep <command>")
		fmt.Fprintln(os.Stderr)
		fmt.Fprintln(os.Stderr, "Commands:")
		fmt.Fprintln(os.Stderr)
		w := tabwriter.NewWriter(os.Stderr, 0, 4, 2, ' ', 0)
		for _, command := range commands {
			if !command.Hidden() {
				fmt.Fprintf(w, "\t%s\t%s\n", command.Name(), command.ShortHelp())
			}
		}
		w.Flush()
		fmt.Fprintln(os.Stderr)
	}

	if len(os.Args) <= 1 || len(os.Args) == 2 && (strings.Contains(strings.ToLower(os.Args[1]), "help") || strings.ToLower(os.Args[1]) == "-h") {
		usage()
		os.Exit(1)
	}

	// Set up the dep context.
	// TODO(pb): can this be deglobalized, pretty please?
	hc, err := newContext()
	if err != nil {
		fmt.Fprint(os.Stderr, err.Error())
		os.Exit(1)
	}
	depContext = hc

	for _, command := range commands {
		if name := command.Name(); os.Args[1] == name {
			// Build flag set with global flags in there.
			// TODO(pb): can we deglobalize verbose, pretty please?
			fs := flag.NewFlagSet(name, flag.ExitOnError)
			fs.BoolVar(verbose, "v", false, "enable verbose logging")

			// Register the subcommand flags in there, too.
			command.Register(fs)

			// Override the usage text to something nicer.
			resetUsage(fs, command.Name(), command.Args(), command.LongHelp())

			// Parse the flags the user gave us.
			if err := fs.Parse(os.Args[2:]); err != nil {
				fs.Usage()
				os.Exit(1)
			}

			// Run the command with the post-flag-processing args.
			if err := command.Run(fs.Args()); err != nil {
				fmt.Fprintf(os.Stderr, "%v\n", err)
				os.Exit(1)
			}

			// Easy peasy livin' breezy.
			return
		}
	}

	fmt.Fprintf(os.Stderr, "%s: no such command\n", os.Args[1])
	usage()
	os.Exit(1)
}

func resetUsage(fs *flag.FlagSet, name, args, longHelp string) {
	var (
		hasFlags   bool
		flagBlock  bytes.Buffer
		flagWriter = tabwriter.NewWriter(&flagBlock, 0, 4, 2, ' ', 0)
	)
	fs.VisitAll(func(f *flag.Flag) {
		hasFlags = true
		// Default-empty string vars should read "(default: <none>)"
		// rather than the comparatively ugly "(default: )".
		defValue := f.DefValue
		if defValue == "" {
			defValue = "<none>"
		}
		fmt.Fprintf(flagWriter, "\t-%s\t%s (default: %s)\n", f.Name, f.Usage, defValue)
	})
	flagWriter.Flush()
	fs.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: dep %s %s\n", name, args)
		fmt.Fprintln(os.Stderr)
		fmt.Fprintln(os.Stderr, strings.TrimSpace(longHelp))
		fmt.Fprintln(os.Stderr)
		if hasFlags {
			fmt.Fprintln(os.Stderr, "Flags:")
			fmt.Fprintln(os.Stderr)
			fmt.Fprintln(os.Stderr, flagBlock.String())
		}
	}
}

var (
	errProjectNotFound = errors.New("could not find project manifest.json, use dep init to initiate a manifest")
)

func findProjectRootFromWD() (string, error) {
	path, err := os.Getwd()
	if err != nil {
		return "", fmt.Errorf("could not get working directory: %s", err)
	}
	return findProjectRoot(path)
}

// search upwards looking for a manifest file until we get to the root of the
// filesystem
func findProjectRoot(from string) (string, error) {
	for {
		mp := filepath.Join(from, manifestName)

		_, err := os.Stat(mp)
		if err == nil {
			return from, nil
		}
		if !os.IsNotExist(err) {
			// Some err other than non-existence - return that out
			return "", err
		}

		parent := filepath.Dir(from)
		if parent == from {
			return "", errProjectNotFound
		}
		from = parent
	}
}

type project struct {
	// absroot is the absolute path to the root directory of the project.
	absroot string
	// importroot is the import path of the project's root directory.
	importroot gps.ProjectRoot
	m          *manifest
	l          *lock
}

// makeParams is a simple helper to create a gps.SolveParameters without setting
// any nils incorrectly.
func (p *project) makeParams() gps.SolveParameters {
	params := gps.SolveParameters{
		RootDir: p.absroot,
	}

	if p.m != nil {
		params.Manifest = p.m
	}

	if p.l != nil {
		params.Lock = p.l
	}

	return params
}

func logf(format string, args ...interface{}) {
	// TODO: something else?
	fmt.Fprintf(os.Stderr, "dep: "+format+"\n", args...)
}

func vlogf(format string, args ...interface{}) {
	if !*verbose {
		return
	}
	logf(format, args...)
}
<commit_msg>use Fprintln instead of Fprint<commit_after>// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"flag"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"text/tabwriter"

	"github.com/pkg/errors"
	"github.com/sdboyer/gps"
)

const (
	manifestName = "manifest.json"
	lockName     = "lock.json"
)

var (
	depContext *ctx
	verbose    = flag.Bool("v", false, "enable verbose logging")
)

type command interface {
	Name() string           // "foobar"
	Args() string           // "<baz> [quux...]"
	ShortHelp() string      // "Foo the first bar"
	LongHelp() string       // "Foo the first bar meeting the following conditions..."
	Register(*flag.FlagSet) // command-specific flags
	Hidden() bool           // indicates whether the command should be hidden from help output
	Run([]string) error
}

func main() {

	// Build the list of available commands.
	commands := []command{
		&initCommand{},
		&statusCommand{},
		&ensureCommand{},
		&removeCommand{},
		&hashinCommand{},
	}

	usage := func() {
		fmt.Fprintln(os.Stderr, "Usage: dep <command>")
		fmt.Fprintln(os.Stderr)
		fmt.Fprintln(os.Stderr, "Commands:")
		fmt.Fprintln(os.Stderr)
		w := tabwriter.NewWriter(os.Stderr, 0, 4, 2, ' ', 0)
		for _, command := range commands {
			if !command.Hidden() {
				fmt.Fprintf(w, "\t%s\t%s\n", command.Name(), command.ShortHelp())
			}
		}
		w.Flush()
		fmt.Fprintln(os.Stderr)
	}

	if len(os.Args) <= 1 || len(os.Args) == 2 && (strings.Contains(strings.ToLower(os.Args[1]), "help") || strings.ToLower(os.Args[1]) == "-h") {
		usage()
		os.Exit(1)
	}

	// Set up the dep context.
	// TODO(pb): can this be deglobalized, pretty please?
	hc, err := newContext()
	if err != nil {
		fmt.Fprintln(os.Stderr, err.Error())
		os.Exit(1)
	}
	depContext = hc

	for _, command := range commands {
		if name := command.Name(); os.Args[1] == name {
			// Build flag set with global flags in there.
			// TODO(pb): can we deglobalize verbose, pretty please?
			fs := flag.NewFlagSet(name, flag.ExitOnError)
			fs.BoolVar(verbose, "v", false, "enable verbose logging")

			// Register the subcommand flags in there, too.
			command.Register(fs)

			// Override the usage text to something nicer.
			resetUsage(fs, command.Name(), command.Args(), command.LongHelp())

			// Parse the flags the user gave us.
			if err := fs.Parse(os.Args[2:]); err != nil {
				fs.Usage()
				os.Exit(1)
			}

			// Run the command with the post-flag-processing args.
			if err := command.Run(fs.Args()); err != nil {
				fmt.Fprintf(os.Stderr, "%v\n", err)
				os.Exit(1)
			}

			// Easy peasy livin' breezy.
			return
		}
	}

	fmt.Fprintf(os.Stderr, "%s: no such command\n", os.Args[1])
	usage()
	os.Exit(1)
}

func resetUsage(fs *flag.FlagSet, name, args, longHelp string) {
	var (
		hasFlags   bool
		flagBlock  bytes.Buffer
		flagWriter = tabwriter.NewWriter(&flagBlock, 0, 4, 2, ' ', 0)
	)
	fs.VisitAll(func(f *flag.Flag) {
		hasFlags = true
		// Default-empty string vars should read "(default: <none>)"
		// rather than the comparatively ugly "(default: )".
		defValue := f.DefValue
		if defValue == "" {
			defValue = "<none>"
		}
		fmt.Fprintf(flagWriter, "\t-%s\t%s (default: %s)\n", f.Name, f.Usage, defValue)
	})
	flagWriter.Flush()
	fs.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: dep %s %s\n", name, args)
		fmt.Fprintln(os.Stderr)
		fmt.Fprintln(os.Stderr, strings.TrimSpace(longHelp))
		fmt.Fprintln(os.Stderr)
		if hasFlags {
			fmt.Fprintln(os.Stderr, "Flags:")
			fmt.Fprintln(os.Stderr)
			fmt.Fprintln(os.Stderr, flagBlock.String())
		}
	}
}

var (
	errProjectNotFound = errors.New("could not find project manifest.json, use dep init to initiate a manifest")
)

func findProjectRootFromWD() (string, error) {
	path, err := os.Getwd()
	if err != nil {
		return "", fmt.Errorf("could not get working directory: %s", err)
	}
	return findProjectRoot(path)
}

// search upwards looking for a manifest file until we get to the root of the
// filesystem
func findProjectRoot(from string) (string, error) {
	for {
		mp := filepath.Join(from, manifestName)

		_, err := os.Stat(mp)
		if err == nil {
			return from, nil
		}
		if !os.IsNotExist(err) {
			// Some err other than non-existence - return that out
			return "", err
		}

		parent := filepath.Dir(from)
		if parent == from {
			return "", errProjectNotFound
		}
		from = parent
	}
}

type project struct {
	// absroot is the absolute path to the root directory of the project.
	absroot string
	// importroot is the import path of the project's root directory.
	importroot gps.ProjectRoot
	m          *manifest
	l          *lock
}

// makeParams is a simple helper to create a gps.SolveParameters without setting
// any nils incorrectly.
func (p *project) makeParams() gps.SolveParameters {
	params := gps.SolveParameters{
		RootDir: p.absroot,
	}

	if p.m != nil {
		params.Manifest = p.m
	}

	if p.l != nil {
		params.Lock = p.l
	}

	return params
}

func logf(format string, args ...interface{}) {
	// TODO: something else?
	fmt.Fprintf(os.Stderr, "dep: "+format+"\n", args...)
}

func vlogf(format string, args ...interface{}) {
	if !*verbose {
		return
	}
	logf(format, args...)
}
<|endoftext|>


<commit_before>/* Copyright (c) 2015, Daniel Martí <mvdan@mvdan.cc> */
/* See LICENSE for licensing information */

package main

import (
	"flag"
	"fmt"
	"go/ast"
	"go/build"
	"go/importer"
	"go/parser"
	"go/token"
	"go/types"
	"io"
	"os"
	"path/filepath"
	"regexp"
)

var (
	verbose = flag.Bool("v", false, "print the names of packages as they are checked")
)

func init() {
	if err := typesInit(); err != nil {
		errExit(err)
	}
}

func main() {
	flag.Parse()
	if err := checkPaths(flag.Args(), os.Stdout); err != nil {
		errExit(err)
	}
}

func errExit(err error) {
	fmt.Fprintf(os.Stderr, "%v\n", err)
	os.Exit(1)
}

func typesMatch(wanted, got []types.Type) bool {
	if len(wanted) != len(got) {
		return false
	}
	for i, w := range wanted {
		g := got[i]
		if !types.ConvertibleTo(g, w) {
			return false
		}
	}
	return true
}

func resultsMatch(wanted, got []types.Type) bool {
	if len(got) == 0 {
		return true
	}
	return typesMatch(wanted, got)
}

func usedMatch(t types.Type, usedAs []types.Type) bool {
	if len(usedAs) < 1 {
		return true
	}
	for _, u := range usedAs {
		if !types.ConvertibleTo(t, u) {
			return false
		}
	}
	return true
}

func interfaceMatching(calls map[string]funcSign, usedAs []types.Type) string {
	matchesIface := func(iface ifaceSign) bool {
		if len(calls) > len(iface.funcs) {
			return false
		}
		if !usedMatch(iface.t, usedAs) {
			return false
		}
		for name, f := range iface.funcs {
			c, e := calls[name]
			if !e {
				return false
			}
			if !typesMatch(f.params, c.params) {
				return false
			}
			if !resultsMatch(f.results, c.results) {
				return false
			}
		}
		return true
	}
	for name, iface := range parsed {
		if matchesIface(iface) {
			return name
		}
	}
	return ""
}

var skipDir = regexp.MustCompile(`^(testdata|vendor|_.*)$`)

func getDirs(d string, recursive bool) ([]string, error) {
	var dirs []string
	walkFn := func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if skipDir.MatchString(info.Name()) {
			return filepath.SkipDir
		}
		if info.IsDir() {
			dirs = append(dirs, path)
			if !recursive {
				return filepath.SkipDir
			}
		}
		return nil
	}
	if err := filepath.Walk(d, walkFn); err != nil {
		return nil, err
	}
	return dirs, nil
}

func getPkgs(p string) ([]*build.Package, []string, error) {
	recursive := filepath.Base(p) == "..."
	if !recursive {
		info, err := os.Stat(p)
		if err != nil {
			return nil, nil, err
		}
		if !info.IsDir() {
			pkg := &build.Package{
				Name:    "stdin",
				GoFiles: []string{p},
			}
			return []*build.Package{pkg}, []string{"."}, nil
		}
	}
	d := p
	if recursive {
		d = p[:len(p)-4]
	}
	dirs, err := getDirs(d, recursive)
	if err != nil {
		return nil, nil, err
	}
	wd, err := os.Getwd()
	if err != nil {
		return nil, nil, err
	}
	var pkgs []*build.Package
	var basedirs []string
	for _, d := range dirs {
		pkg, err := build.Import("./"+d, wd, 0)
		if _, ok := err.(*build.NoGoError); ok {
			continue
		}
		if err != nil {
			return nil, nil, err
		}
		pkgs = append(pkgs, pkg)
		basedirs = append(basedirs, d)
	}
	return pkgs, basedirs, nil
}

func checkPaths(paths []string, w io.Writer) error {
	conf := &types.Config{Importer: importer.Default()}
	for _, p := range paths {
		pkgs, basedirs, err := getPkgs(p)
		if err != nil {
			return err
		}
		for i, pkg := range pkgs {
			basedir := basedirs[i]
			if err := checkPkg(conf, pkg, basedir, w); err != nil {
				return err
			}
		}
	}
	return nil
}

func checkPkg(conf *types.Config, pkg *build.Package, basedir string, w io.Writer) error {
	if *verbose {
		importPath := pkg.ImportPath
		if importPath == "" {
			importPath = "command-line-arguments"
		}
		fmt.Fprintln(w, importPath)
	}
	gp := &goPkg{
		Package: pkg,
		fset:    token.NewFileSet(),
	}
	for _, p := range pkg.GoFiles {
		fp := filepath.Join(basedir, p)
		if err := gp.parsePath(fp); err != nil {
			return err
		}
	}
	if err := gp.check(conf, w); err != nil {
		return err
	}
	return nil
}

type goPkg struct {
	*build.Package

	fset  *token.FileSet
	files []*ast.File
}

func (gp *goPkg) parsePath(fp string) error {
	f, err := os.Open(fp)
	if err != nil {
		return err
	}
	defer f.Close()
	if err := gp.parseReader(fp, f); err != nil {
		return err
	}
	return nil
}

func (gp *goPkg) parseReader(name string, r io.Reader) error {
	f, err := parser.ParseFile(gp.fset, name, r, 0)
	if err != nil {
		return err
	}
	gp.files = append(gp.files, f)
	return nil
}

func (gp *goPkg) check(conf *types.Config, w io.Writer) error {
	info := &types.Info{
		Types: make(map[ast.Expr]types.TypeAndValue),
		Defs:  make(map[*ast.Ident]types.Object),
		Uses:  make(map[*ast.Ident]types.Object),
	}
	_, err := conf.Check(gp.Name, gp.fset, gp.files, info)
	if err != nil {
		return err
	}
	v := &Visitor{
		Info: info,
		w:    w,
		fset: gp.fset,
	}
	for _, f := range gp.files {
		ast.Walk(v, f)
	}
	return nil
}

type Visitor struct {
	*types.Info

	w    io.Writer
	fset *token.FileSet

	nodes []ast.Node

	params map[string]types.Type
	called map[string]map[string]funcSign
	usedAs map[string][]types.Type

	inBlock bool
}

func typeMap(t *types.Tuple) map[string]types.Type {
	m := make(map[string]types.Type, t.Len())
	for i := 0; i < t.Len(); i++ {
		p := t.At(i)
		m[p.Name()] = p.Type()
	}
	return m
}

func paramType(sign *types.Signature, i int) types.Type {
	params := sign.Params()
	extra := sign.Variadic() && i >= params.Len()-1
	if !extra {
		if i >= params.Len() {
			// builtins with multiple signatures
			return nil
		}
		return params.At(i).Type()
	}
	stype := params.At(params.Len() - 1).Type().(*types.Slice)
	return stype.Elem()
}

func (v *Visitor) addUsed(name string, as types.Type) {
	if as == nil {
		return
	}
	v.usedAs[name] = append(v.usedAs[name], as)
}

func (v *Visitor) Visit(node ast.Node) ast.Visitor {
	var top ast.Node
	if len(v.nodes) > 0 {
		top = v.nodes[len(v.nodes)-1]
	}
	switch x := node.(type) {
	case *ast.File:
	case *ast.FuncDecl:
		f := v.Defs[x.Name].(*types.Func)
		sign := f.Type().(*types.Signature)
		v.params = typeMap(sign.Params())
		v.called = make(map[string]map[string]funcSign)
		v.usedAs = make(map[string][]types.Type)
	case *ast.BlockStmt:
		v.inBlock = true
	case *ast.AssignStmt:
		if !v.inBlock {
			return nil
		}
		for i, e := range x.Rhs {
			id, ok := e.(*ast.Ident)
			if !ok {
				continue
			}
			lid, ok := x.Lhs[i].(*ast.Ident)
			if !ok {
				continue
			}
			name := id.Name
			if _, e := v.params[name]; !e {
				continue
			}
			v.addUsed(name, v.Types[lid].Type)
		}
	case *ast.CallExpr:
		if !v.inBlock {
			return nil
		}
		if v.usedAs == nil {
			break
		}
		sign := funcSignature(v.Types[x.Fun].Type)
		if sign == nil {
			break
		}
		for i, e := range x.Args {
			id, ok := e.(*ast.Ident)
			if !ok {
				continue
			}
			name := id.Name
			if _, e := v.params[name]; !e {
				continue
			}
			v.addUsed(name, paramType(sign, i))
		}
		v.onCall(x)
	case nil:
		v.nodes = v.nodes[:len(v.nodes)-1]
		if _, ok := top.(*ast.FuncDecl); ok {
			v.funcEnded(top.Pos())
			v.params = nil
			v.called = nil
			v.usedAs = nil
			v.inBlock = false
		}
	}
	if node != nil {
		v.nodes = append(v.nodes, node)
	}
	return v
}

func funcSignature(t types.Type) *types.Signature {
	switch x := t.(type) {
	case *types.Signature:
		return x
	case *types.Named:
		return funcSignature(x.Underlying())
	default:
		return nil
	}
}

func (v *Visitor) onCall(ce *ast.CallExpr) {
	sel, ok := ce.Fun.(*ast.SelectorExpr)
	if !ok {
		return
	}
	left, ok := sel.X.(*ast.Ident)
	if !ok {
		return
	}
	vname := left.Name
	if _, e := v.params[vname]; !e {
		return
	}
	sign := funcSignature(v.Types[ce.Fun].Type)
	if sign == nil {
		return
	}
	c := funcSign{}
	results := sign.Results()
	for i := 0; i < results.Len(); i++ {
		v := results.At(i)
		c.results = append(c.results, v.Type())
	}
	for _, a := range ce.Args {
		c.params = append(c.params, v.Types[a].Type)
	}
	if _, e := v.called[vname]; !e {
		v.called[vname] = make(map[string]funcSign)
	}
	fname := sel.Sel.Name
	v.called[vname][fname] = c
	return
}

func (v *Visitor) funcEnded(pos token.Pos) {
	for name, methods := range v.called {
		usedAs := v.usedAs[name]
		iface := interfaceMatching(methods, usedAs)
		if iface == "" {
			continue
		}
		param, e := v.params[name]
		if !e {
			continue
		}
		if iface == param.String() {
			continue
		}
		pos := v.fset.Position(pos)
		fmt.Fprintf(v.w, "%s:%d: %s can be %s\n",
			pos.Filename, pos.Line, name, iface)
	}
}
<commit_msg>Simplify code structure by using a param struct<commit_after>/* Copyright (c) 2015, Daniel Martí <mvdan@mvdan.cc> */
/* See LICENSE for licensing information */

package main

import (
	"flag"
	"fmt"
	"go/ast"
	"go/build"
	"go/importer"
	"go/parser"
	"go/token"
	"go/types"
	"io"
	"os"
	"path/filepath"
	"regexp"
)

var (
	verbose = flag.Bool("v", false, "print the names of packages as they are checked")
)

func init() {
	if err := typesInit(); err != nil {
		errExit(err)
	}
}

func main() {
	flag.Parse()
	if err := checkPaths(flag.Args(), os.Stdout); err != nil {
		errExit(err)
	}
}

func errExit(err error) {
	fmt.Fprintf(os.Stderr, "%v\n", err)
	os.Exit(1)
}

func typesMatch(wanted, got []types.Type) bool {
	if len(wanted) != len(got) {
		return false
	}
	for i, w := range wanted {
		g := got[i]
		if !types.ConvertibleTo(g, w) {
			return false
		}
	}
	return true
}

func resultsMatch(wanted, got []types.Type) bool {
	if len(got) == 0 {
		return true
	}
	return typesMatch(wanted, got)
}

func usedMatch(t types.Type, usedAs []types.Type) bool {
	if len(usedAs) < 1 {
		return true
	}
	for _, u := range usedAs {
		if !types.ConvertibleTo(t, u) {
			return false
		}
	}
	return true
}

func interfaceMatching(p *param) string {
	matchesIface := func(iface ifaceSign) bool {
		if len(p.calls) > len(iface.funcs) {
			return false
		}
		if !usedMatch(iface.t, p.usedAs) {
			return false
		}
		for name, f := range iface.funcs {
			c, e := p.calls[name]
			if !e {
				return false
			}
			if !typesMatch(f.params, c.params) {
				return false
			}
			if !resultsMatch(f.results, c.results) {
				return false
			}
		}
		return true
	}
	for name, iface := range parsed {
		if matchesIface(iface) {
			return name
		}
	}
	return ""
}

var skipDir = regexp.MustCompile(`^(testdata|vendor|_.*)$`)

func getDirs(d string, recursive bool) ([]string, error) {
	var dirs []string
	walkFn := func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if skipDir.MatchString(info.Name()) {
			return filepath.SkipDir
		}
		if info.IsDir() {
			dirs = append(dirs, path)
			if !recursive {
				return filepath.SkipDir
			}
		}
		return nil
	}
	if err := filepath.Walk(d, walkFn); err != nil {
		return nil, err
	}
	return dirs, nil
}

func getPkgs(p string) ([]*build.Package, []string, error) {
	recursive := filepath.Base(p) == "..."
	if !recursive {
		info, err := os.Stat(p)
		if err != nil {
			return nil, nil, err
		}
		if !info.IsDir() {
			pkg := &build.Package{
				Name:    "stdin",
				GoFiles: []string{p},
			}
			return []*build.Package{pkg}, []string{"."}, nil
		}
	}
	d := p
	if recursive {
		d = p[:len(p)-4]
	}
	dirs, err := getDirs(d, recursive)
	if err != nil {
		return nil, nil, err
	}
	wd, err := os.Getwd()
	if err != nil {
		return nil, nil, err
	}
	var pkgs []*build.Package
	var basedirs []string
	for _, d := range dirs {
		pkg, err := build.Import("./"+d, wd, 0)
		if _, ok := err.(*build.NoGoError); ok {
			continue
		}
		if err != nil {
			return nil, nil, err
		}
		pkgs = append(pkgs, pkg)
		basedirs = append(basedirs, d)
	}
	return pkgs, basedirs, nil
}

func checkPaths(paths []string, w io.Writer) error {
	conf := &types.Config{Importer: importer.Default()}
	for _, p := range paths {
		pkgs, basedirs, err := getPkgs(p)
		if err != nil {
			return err
		}
		for i, pkg := range pkgs {
			basedir := basedirs[i]
			if err := checkPkg(conf, pkg, basedir, w); err != nil {
				return err
			}
		}
	}
	return nil
}

func checkPkg(conf *types.Config, pkg *build.Package, basedir string, w io.Writer) error {
	if *verbose {
		importPath := pkg.ImportPath
		if importPath == "" {
			importPath = "command-line-arguments"
		}
		fmt.Fprintln(w, importPath)
	}
	gp := &goPkg{
		Package: pkg,
		fset:    token.NewFileSet(),
	}
	for _, p := range pkg.GoFiles {
		fp := filepath.Join(basedir, p)
		if err := gp.parsePath(fp); err != nil {
			return err
		}
	}
	if err := gp.check(conf, w); err != nil {
		return err
	}
	return nil
}

type goPkg struct {
	*build.Package

	fset  *token.FileSet
	files []*ast.File
}

func (gp *goPkg) parsePath(fp string) error {
	f, err := os.Open(fp)
	if err != nil {
		return err
	}
	defer f.Close()
	if err := gp.parseReader(fp, f); err != nil {
		return err
	}
	return nil
}

func (gp *goPkg) parseReader(name string, r io.Reader) error {
	f, err := parser.ParseFile(gp.fset, name, r, 0)
	if err != nil {
		return err
	}
	gp.files = append(gp.files, f)
	return nil
}

func (gp *goPkg) check(conf *types.Config, w io.Writer) error {
	info := &types.Info{
		Types: make(map[ast.Expr]types.TypeAndValue),
		Defs:  make(map[*ast.Ident]types.Object),
		Uses:  make(map[*ast.Ident]types.Object),
	}
	_, err := conf.Check(gp.Name, gp.fset, gp.files, info)
	if err != nil {
		return err
	}
	v := &Visitor{
		Info: info,
		w:    w,
		fset: gp.fset,
	}
	for _, f := range gp.files {
		ast.Walk(v, f)
	}
	return nil
}

type param struct {
	t types.Type

	calls  map[string]funcSign
	usedAs []types.Type
}

type Visitor struct {
	*types.Info

	w     io.Writer
	fset  *token.FileSet
	nodes []ast.Node

	params  map[string]*param
	inBlock bool
}

func paramsMap(t *types.Tuple) map[string]*param {
	m := make(map[string]*param, t.Len())
	for i := 0; i < t.Len(); i++ {
		p := t.At(i)
		m[p.Name()] = &param{
			t:     p.Type(),
			calls: make(map[string]funcSign),
		}
	}
	return m
}

func paramType(sign *types.Signature, i int) types.Type {
	params := sign.Params()
	extra := sign.Variadic() && i >= params.Len()-1
	if !extra {
		if i >= params.Len() {
			// builtins with multiple signatures
			return nil
		}
		return params.At(i).Type()
	}
	stype := params.At(params.Len() - 1).Type().(*types.Slice)
	return stype.Elem()
}

func (v *Visitor) addUsed(name string, as types.Type) {
	if as == nil {
		return
	}
	p := v.params[name]
	p.usedAs = append(p.usedAs, as)
}

func (v *Visitor) Visit(node ast.Node) ast.Visitor {
	var top ast.Node
	if len(v.nodes) > 0 {
		top = v.nodes[len(v.nodes)-1]
	}
	switch x := node.(type) {
	case *ast.File:
	case *ast.FuncDecl:
		f := v.Defs[x.Name].(*types.Func)
		sign := f.Type().(*types.Signature)
		v.params = paramsMap(sign.Params())
	case *ast.BlockStmt:
		v.inBlock = true
	case *ast.AssignStmt:
		if !v.inBlock {
			return nil
		}
		for i, e := range x.Rhs {
			id, ok := e.(*ast.Ident)
			if !ok {
				continue
			}
			lid, ok := x.Lhs[i].(*ast.Ident)
			if !ok {
				continue
			}
			if _, e := v.params[id.Name]; !e {
				continue
			}
			v.addUsed(id.Name, v.Types[lid].Type)
		}
	case *ast.CallExpr:
		if !v.inBlock {
			return nil
		}
		sign := funcSignature(v.Types[x.Fun].Type)
		if sign == nil {
			break
		}
		for i, e := range x.Args {
			id, ok := e.(*ast.Ident)
			if !ok {
				continue
			}
			if _, e := v.params[id.Name]; !e {
				continue
			}
			v.addUsed(id.Name, paramType(sign, i))
		}
		v.onCall(x)
	case nil:
		v.nodes = v.nodes[:len(v.nodes)-1]
		if _, ok := top.(*ast.FuncDecl); ok {
			v.funcEnded(top.Pos())
			v.params = nil
			v.inBlock = false
		}
	}
	if node != nil {
		v.nodes = append(v.nodes, node)
	}
	return v
}

func funcSignature(t types.Type) *types.Signature {
	switch x := t.(type) {
	case *types.Signature:
		return x
	case *types.Named:
		return funcSignature(x.Underlying())
	default:
		return nil
	}
}

func (v *Visitor) onCall(ce *ast.CallExpr) {
	sel, ok := ce.Fun.(*ast.SelectorExpr)
	if !ok {
		return
	}
	left, ok := sel.X.(*ast.Ident)
	if !ok {
		return
	}
	vname := left.Name
	p, e := v.params[vname]
	if !e {
		return
	}
	sign := funcSignature(v.Types[ce.Fun].Type)
	if sign == nil {
		return
	}
	c := funcSign{}
	results := sign.Results()
	for i := 0; i < results.Len(); i++ {
		c.results = append(c.results, results.At(i).Type())
	}
	for _, a := range ce.Args {
		c.params = append(c.params, v.Types[a].Type)
	}
	p.calls[sel.Sel.Name] = c
	return
}

func (v *Visitor) funcEnded(pos token.Pos) {
	for name, p := range v.params {
		iface := interfaceMatching(p)
		if iface == "" {
			continue
		}
		if iface == p.t.String() {
			continue
		}
		pos := v.fset.Position(pos)
		fmt.Fprintf(v.w, "%s:%d: %s can be %s\n",
			pos.Filename, pos.Line, name, iface)
	}
}
<|endoftext|>