<commit_before>package config

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"

	"github.com/astaxie/beego/config"
	"github.com/astaxie/beego/logs"
	"github.com/astaxie/beego/utils"
	"github.com/ysqi/atop/common/util"
)

var (
	// AppCfg is the instance of Config, store the config information from file
	AppCfg *myAppConfig
	// AppPath is the absolute path to the app
	AppPath string
	// AppCfgPath is the path to the config files
	AppCfgPath string
)

func init() {
	var err error
	if AppPath, err = filepath.Abs(filepath.Dir(os.Args[0])); err != nil {
		panic(err)
	}

	if p := os.Getenv("AppConfigPath"); p != "" && utils.FileExists(p) {
		AppCfgPath = p
	} else {
		workPath, err := os.Getwd()
		if err != nil {
			panic(err)
		}
		AppCfgPath = filepath.Join(workPath, "conf", "app.conf")
	}
	if !utils.FileExists(AppCfgPath) {
		AppCfgPath = filepath.Join(AppPath, "conf", "app.conf")
		if !utils.FileExists(AppCfgPath) {
			if path, err := util.SearchFile(filepath.Join("conf", "app.conf")); err == nil {
				AppCfgPath = path
			} else {
				AppCfgPath = ""
				AppCfg = &myAppConfig{
					innerConfig: config.NewFakeConfig(),
					RunMode:     "dev",
				}
				return
			}
		}
	}
	if err = parseConfig(AppCfgPath); err != nil {
		panic(err)
	}
}

// now only support ini, next will support json.
func parseConfig(appConfigPath string) (err error) {
	AppCfg, err = newAppConfig("ini", appConfigPath)
	if err != nil {
		return err
	}
	return assignConfig(AppCfg)
}

func assignConfig(ac config.Configer) error {
	// set the run mode first
	if envRunMode := os.Getenv(ac.DefaultString("AppName", "MyAPP") + "_RunMode"); envRunMode != "" {
		AppCfg.RunMode = envRunMode
	} else if runMode := ac.String("RunMode"); runMode != "" {
		AppCfg.RunMode = runMode
	}
	AppCfg.AppName = ac.String("AppName")

	logOuputs := make(map[string]string)
	if lo := ac.String("LogOutputs"); lo != "" {
		los := strings.Split(lo, ";")
		for _, v := range los {
			if logType2Config := strings.SplitN(v, ",", 2); len(logType2Config) == 2 {
				logOuputs[logType2Config[0]] = logType2Config[1]
			} else {
				continue
			}
		}
	}

	//init log
	logs.Reset()
	for adaptor, config := range logOuputs {
		err := logs.SetLogger(adaptor, config)
		if err != nil {
			fmt.Fprintln(os.Stderr, fmt.Sprintf("%s with the config %q got err:%s", adaptor, config, err.Error()))
		}
	}
	logs.SetLogFuncCall(true)
	return nil
}

type myAppConfig struct {
	innerConfig config.Configer
	RunMode     string
	AppName     string
}

func newAppConfig(appConfigProvider, appConfigPath string) (*myAppConfig, error) {
	ac, err := config.NewConfig(appConfigProvider, appConfigPath)
	if err != nil {
		return nil, err
	}
	return &myAppConfig{innerConfig: ac, RunMode: "dev"}, nil
}

func (b *myAppConfig) Set(key, val string) error {
	if err := b.innerConfig.Set(b.RunMode+"::"+key, val); err != nil {
		return err
	}
	return b.innerConfig.Set(key, val)
}

func (b *myAppConfig) String(key string) string {
	if v := b.innerConfig.String(b.RunMode + "::" + key); v != "" {
		return v
	}
	return b.innerConfig.String(key)
}

func (b *myAppConfig) Strings(key string) []string {
	if v := b.innerConfig.Strings(b.RunMode + "::" + key); len(v) > 0 {
		return v
	}
	return b.innerConfig.Strings(key)
}

func (b *myAppConfig) Int(key string) (int, error) {
	if v, err := b.innerConfig.Int(b.RunMode + "::" + key); err == nil {
		return v, nil
	}
	return b.innerConfig.Int(key)
}

func (b *myAppConfig) Int64(key string) (int64, error) {
	if v, err := b.innerConfig.Int64(b.RunMode + "::" + key); err == nil {
		return v, nil
	}
	return b.innerConfig.Int64(key)
}

func (b *myAppConfig) Bool(key string) (bool, error) {
	if v, err := b.innerConfig.Bool(b.RunMode + "::" + key); err == nil {
		return v, nil
	}
	return b.innerConfig.Bool(key)
}

func (b *myAppConfig) Float(key string) (float64, error) {
	if v, err := b.innerConfig.Float(b.RunMode + "::" + key); err == nil {
		return v, nil
	}
	return b.innerConfig.Float(key)
}

func (b *myAppConfig) DefaultString(key string, defaultVal string) string {
	if v := b.String(key); v != "" {
		return v
	}
	return defaultVal
}

func (b *myAppConfig) DefaultStrings(key string, defaultVal []string) []string {
	if v := b.Strings(key); len(v) != 0 {
		return v
	}
	return defaultVal
}

func (b *myAppConfig) DefaultInt(key string, defaultVal int) int {
	if v, err := b.Int(key); err == nil {
		return v
	}
	return defaultVal
}

func (b *myAppConfig) DefaultInt64(key string, defaultVal int64) int64 {
	if v, err := b.Int64(key); err == nil {
		return v
	}
	return defaultVal
}

func (b *myAppConfig) DefaultBool(key string, defaultVal bool) bool {
	if v, err := b.Bool(key); err == nil {
		return v
	}
	return defaultVal
}

func (b *myAppConfig) DefaultFloat(key string, defaultVal float64) float64 {
	if v, err := b.Float(key); err == nil {
		return v
	}
	return defaultVal
}

func (b *myAppConfig) DIY(key string) (interface{}, error) {
	return b.innerConfig.DIY(key)
}

func (b *myAppConfig) GetSection(section string) (map[string]string, error) {
	return b.innerConfig.GetSection(section)
}

func (b *myAppConfig) SaveConfigFile(filename string) error {
	return b.innerConfig.SaveConfigFile(filename)
}
<commit_msg>配置文件使用log2记录日志<commit_after>package config

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"

	"github.com/astaxie/beego/config"
	"github.com/astaxie/beego/logs"
	"github.com/astaxie/beego/utils"
	"github.com/ysqi/atop/common/log2"
	"github.com/ysqi/atop/common/util"
)

var (
	// AppCfg is the instance of Config, store the config information from file
	AppCfg *myAppConfig
	// AppPath is the absolute path to the app
	AppPath string
	// AppCfgPath is the path to the config files
	AppCfgPath string
)

func init() {
	var err error
	if AppPath, err = filepath.Abs(filepath.Dir(os.Args[0])); err != nil {
		panic(err)
	}
	if p := os.Getenv("AppConfigPath"); p != "" && utils.FileExists(p) {
		AppCfgPath = p
	} else {
		workPath, err := os.Getwd()
		if err != nil {
			panic(err)
		}
		AppCfgPath = filepath.Join(workPath, "conf", "app.conf")
	}
	if !utils.FileExists(AppCfgPath) {
		AppCfgPath = filepath.Join(AppPath, "conf", "app.conf")
		if !utils.FileExists(AppCfgPath) {
			if path, err := util.SearchFile(filepath.Join("conf", "app.conf")); err == nil {
				AppCfgPath = path
			} else {
				AppCfgPath = ""
				AppCfg = &myAppConfig{
					innerConfig: config.NewFakeConfig(),
					RunMode:     "dev",
				}
				return
			}
		}
	}
	log2.Infof("App Config Path=%q", AppCfgPath)
	if err = parseConfig(AppCfgPath); err != nil {
		panic(err)
	}
}

// now only support ini, next will support json.
func parseConfig(appConfigPath string) (err error) {
	AppCfg, err = newAppConfig("ini", appConfigPath)
	if err != nil {
		return err
	}
	return assignConfig(AppCfg)
}

func assignConfig(ac config.Configer) error {
	// set the run mode first
	if envRunMode := os.Getenv(ac.DefaultString("AppName", "MyAPP") + "_RunMode"); envRunMode != "" {
		AppCfg.RunMode = envRunMode
	} else if runMode := ac.String("RunMode"); runMode != "" {
		AppCfg.RunMode = runMode
	}
	AppCfg.AppName = ac.String("AppName")

	logOuputs := make(map[string]string)
	if lo := ac.String("LogOutputs"); lo != "" {
		los := strings.Split(lo, ";")
		for _, v := range los {
			if logType2Config := strings.SplitN(v, ",", 2); len(logType2Config) == 2 {
				logOuputs[logType2Config[0]] = logType2Config[1]
			} else {
				continue
			}
		}
	}

	//init log
	logs.Reset()
	for adaptor, config := range logOuputs {
		err := logs.SetLogger(adaptor, config)
		if err != nil {
			fmt.Fprintln(os.Stderr, fmt.Sprintf("%s with the config %q got err:%s", adaptor, config, err.Error()))
		}
	}
	logs.SetLogFuncCall(true)
	return nil
}

type myAppConfig struct {
	innerConfig config.Configer
	RunMode     string
	AppName     string
}

func newAppConfig(appConfigProvider, appConfigPath string) (*myAppConfig, error) {
	ac, err := config.NewConfig(appConfigProvider, appConfigPath)
	if err != nil {
		return nil, err
	}
	return &myAppConfig{innerConfig: ac, RunMode: "dev"}, nil
}

func (b *myAppConfig) Set(key, val string) error {
	if err := b.innerConfig.Set(b.RunMode+"::"+key, val); err != nil {
		return err
	}
	return b.innerConfig.Set(key, val)
}

func (b *myAppConfig) String(key string) string {
	if v := b.innerConfig.String(b.RunMode + "::" + key); v != "" {
		return v
	}
	return b.innerConfig.String(key)
}

func (b *myAppConfig) Strings(key string) []string {
	if v := b.innerConfig.Strings(b.RunMode + "::" + key); len(v) > 0 {
		return v
	}
	return b.innerConfig.Strings(key)
}

func (b *myAppConfig) Int(key string) (int, error) {
	if v, err := b.innerConfig.Int(b.RunMode + "::" + key); err == nil {
		return v, nil
	}
	return b.innerConfig.Int(key)
}

func (b *myAppConfig) Int64(key string) (int64, error) {
	if v, err := b.innerConfig.Int64(b.RunMode + "::" + key); err == nil {
		return v, nil
	}
	return b.innerConfig.Int64(key)
}

func (b *myAppConfig) Bool(key string) (bool, error) {
	if v, err := b.innerConfig.Bool(b.RunMode + "::" + key); err == nil {
		return v, nil
	}
	return b.innerConfig.Bool(key)
}

func (b *myAppConfig) Float(key string) (float64, error) {
	if v, err := b.innerConfig.Float(b.RunMode + "::" + key); err == nil {
		return v, nil
	}
	return b.innerConfig.Float(key)
}

func (b *myAppConfig) DefaultString(key string, defaultVal string) string {
	if v := b.String(key); v != "" {
		return v
	}
	return defaultVal
}

func (b *myAppConfig) DefaultStrings(key string, defaultVal []string) []string {
	if v := b.Strings(key); len(v) != 0 {
		return v
	}
	return defaultVal
}

func (b *myAppConfig) DefaultInt(key string, defaultVal int) int {
	if v, err := b.Int(key); err == nil {
		return v
	}
	return defaultVal
}

func (b *myAppConfig) DefaultInt64(key string, defaultVal int64) int64 {
	if v, err := b.Int64(key); err == nil {
		return v
	}
	return defaultVal
}

func (b *myAppConfig) DefaultBool(key string, defaultVal bool) bool {
	if v, err := b.Bool(key); err == nil {
		return v
	}
	return defaultVal
}

func (b *myAppConfig) DefaultFloat(key string, defaultVal float64) float64 {
	if v, err := b.Float(key); err == nil {
		return v
	}
	return defaultVal
}

func (b *myAppConfig) DIY(key string) (interface{}, error) {
	return b.innerConfig.DIY(key)
}

func (b *myAppConfig) GetSection(section string) (map[string]string, error) {
	return b.innerConfig.GetSection(section)
}

func (b *myAppConfig) SaveConfigFile(filename string) error {
	return b.innerConfig.SaveConfigFile(filename)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"net"
	"net/http"
	"os"
	"os/signal"
	"os/user"
	"runtime"
	"strconv"
	"syscall"

	"github.com/Sirupsen/logrus"
	"github.com/lomik/go-carbon/carbon"
	"github.com/lomik/go-carbon/logging"
	daemon "github.com/sevlyar/go-daemon"
)

import _ "net/http/pprof"

// Version of go-carbon
const Version = "0.9.0"

func httpServe(addr string) (func(), error) {
	tcpAddr, err := net.ResolveTCPAddr("tcp", addr)
	if err != nil {
		return nil, err
	}

	listener, err := net.ListenTCP("tcp", tcpAddr)
	if err != nil {
		return nil, err
	}

	go http.Serve(listener, nil)
	return func() { listener.Close() }, nil
}

func main() {
	var err error

	/* CONFIG start */

	configFile := flag.String("config", "", "Filename of config")
	printDefaultConfig := flag.Bool("config-print-default", false, "Print default config")
	checkConfig := flag.Bool("check-config", false, "Check config and exit")

	printVersion := flag.Bool("version", false, "Print version")

	isDaemon := flag.Bool("daemon", false, "Run in background")
	pidfile := flag.String("pidfile", "", "Pidfile path (only for daemon)")

	flag.Parse()

	if *printVersion {
		fmt.Print(Version)
		return
	}

	if *printDefaultConfig {
		if err = carbon.PrintConfig(carbon.NewConfig()); err != nil {
			log.Fatal(err)
		}
		return
	}

	app := carbon.New(*configFile)

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

	cfg := app.Config

	var runAsUser *user.User
	if cfg.Common.User != "" {
		runAsUser, err = user.Lookup(cfg.Common.User)
		if err != nil {
			log.Fatal(err)
		}
	}

	if err := logging.SetLevel(cfg.Common.LogLevel); err != nil {
		log.Fatal(err)
	}

	// config parsed successfully. Exit in check-only mode
	if *checkConfig {
		return
	}

	if err := logging.PrepareFile(cfg.Common.Logfile, runAsUser); err != nil {
		logrus.Fatal(err)
	}

	if err := logging.SetFile(cfg.Common.Logfile); err != nil {
		logrus.Fatal(err)
	}

	if *isDaemon {
		runtime.LockOSThread()

		context := new(daemon.Context)
		if *pidfile != "" {
			context.PidFileName = *pidfile
			context.PidFilePerm = 0644
		}

		if runAsUser != nil {
			uid, err := strconv.ParseInt(runAsUser.Uid, 10, 0)
			if err != nil {
				log.Fatal(err)
			}

			gid, err := strconv.ParseInt(runAsUser.Gid, 10, 0)
			if err != nil {
				log.Fatal(err)
			}

			context.Credential = &syscall.Credential{
				Uid: uint32(uid),
				Gid: uint32(gid),
			}
		}

		child, _ := context.Reborn()

		if child != nil {
			return
		}
		defer context.Release()

		runtime.UnlockOSThread()
	}
	/* CONFIG end */

	// pprof
	// httpStop := func() {}
	if cfg.Pprof.Enabled {
		_, err = httpServe(cfg.Pprof.Listen)
		if err != nil {
			logrus.Fatal(err)
		}
	}

	if err = app.Start(); err != nil {
		logrus.Fatal(err)
	} else {
		logrus.Info("started")
	}

	go func() {
		c := make(chan os.Signal, 1)
		signal.Notify(c, syscall.SIGUSR2)
		for {
			<-c
			app.DumpStop()
		}
	}()

	go func() {
		c := make(chan os.Signal, 1)
		signal.Notify(c, syscall.SIGHUP)
		for {
			<-c
			logrus.Info("HUP received. Reload config")
			if err := app.ReloadConfig(); err != nil {
				logrus.Errorf("Config reload failed: %s", err.Error())
			} else {
				logrus.Info("Config successfully reloaded")
			}
		}
	}()

	app.Loop()

	logrus.Info("stopped")
}
<commit_msg>Add a newline to -version output<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"net"
	"net/http"
	"os"
	"os/signal"
	"os/user"
	"runtime"
	"strconv"
	"syscall"

	"github.com/Sirupsen/logrus"
	"github.com/lomik/go-carbon/carbon"
	"github.com/lomik/go-carbon/logging"
	daemon "github.com/sevlyar/go-daemon"
)

import _ "net/http/pprof"

// Version of go-carbon
const Version = "0.9.0"

func httpServe(addr string) (func(), error) {
	tcpAddr, err := net.ResolveTCPAddr("tcp", addr)
	if err != nil {
		return nil, err
	}

	listener, err := net.ListenTCP("tcp", tcpAddr)
	if err != nil {
		return nil, err
	}

	go http.Serve(listener, nil)
	return func() { listener.Close() }, nil
}

func main() {
	var err error

	/* CONFIG start */

	configFile := flag.String("config", "", "Filename of config")
	printDefaultConfig := flag.Bool("config-print-default", false, "Print default config")
	checkConfig := flag.Bool("check-config", false, "Check config and exit")

	printVersion := flag.Bool("version", false, "Print version")

	isDaemon := flag.Bool("daemon", false, "Run in background")
	pidfile := flag.String("pidfile", "", "Pidfile path (only for daemon)")

	flag.Parse()

	if *printVersion {
		fmt.Println(Version)
		return
	}

	if *printDefaultConfig {
		if err = carbon.PrintConfig(carbon.NewConfig()); err != nil {
			log.Fatal(err)
		}
		return
	}

	app := carbon.New(*configFile)

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

	cfg := app.Config

	var runAsUser *user.User
	if cfg.Common.User != "" {
		runAsUser, err = user.Lookup(cfg.Common.User)
		if err != nil {
			log.Fatal(err)
		}
	}

	if err := logging.SetLevel(cfg.Common.LogLevel); err != nil {
		log.Fatal(err)
	}

	// config parsed successfully. Exit in check-only mode
	if *checkConfig {
		return
	}

	if err := logging.PrepareFile(cfg.Common.Logfile, runAsUser); err != nil {
		logrus.Fatal(err)
	}

	if err := logging.SetFile(cfg.Common.Logfile); err != nil {
		logrus.Fatal(err)
	}

	if *isDaemon {
		runtime.LockOSThread()

		context := new(daemon.Context)
		if *pidfile != "" {
			context.PidFileName = *pidfile
			context.PidFilePerm = 0644
		}

		if runAsUser != nil {
			uid, err := strconv.ParseInt(runAsUser.Uid, 10, 0)
			if err != nil {
				log.Fatal(err)
			}

			gid, err := strconv.ParseInt(runAsUser.Gid, 10, 0)
			if err != nil {
				log.Fatal(err)
			}

			context.Credential = &syscall.Credential{
				Uid: uint32(uid),
				Gid: uint32(gid),
			}
		}

		child, _ := context.Reborn()

		if child != nil {
			return
		}
		defer context.Release()

		runtime.UnlockOSThread()
	}
	/* CONFIG end */

	// pprof
	// httpStop := func() {}
	if cfg.Pprof.Enabled {
		_, err = httpServe(cfg.Pprof.Listen)
		if err != nil {
			logrus.Fatal(err)
		}
	}

	if err = app.Start(); err != nil {
		logrus.Fatal(err)
	} else {
		logrus.Info("started")
	}

	go func() {
		c := make(chan os.Signal, 1)
		signal.Notify(c, syscall.SIGUSR2)
		for {
			<-c
			app.DumpStop()
		}
	}()

	go func() {
		c := make(chan os.Signal, 1)
		signal.Notify(c, syscall.SIGHUP)
		for {
			<-c
			logrus.Info("HUP received. Reload config")
			if err := app.ReloadConfig(); err != nil {
				logrus.Errorf("Config reload failed: %s", err.Error())
			} else {
				logrus.Info("Config successfully reloaded")
			}
		}
	}()

	app.Loop()

	logrus.Info("stopped")
}
<|endoftext|>


<commit_before>package main

import (
	"html/template"
	"log"
	"net/http"
)

// GLOBALS DECLARED HERE

var mediaDir string
var tmplDir = "./templates/"
var templates map[string]*template.Template
var pageData = PageData{}
var firstStart = true

// THE VIEW CODE IS HERE

func generateTemplates() {
	templates = make(map[string]*template.Template)
	modulus := template.FuncMap{"mod": func(i, j int) bool { return i%j == 0 }}
	templatesList := []string{"index.html", "about.html", "movie.html", "alreadyplaying.html", "setup.html", "nothingfound.html"}
	for _, tmpl := range templatesList {
		t := template.New("base.html").Funcs(modulus)
		templates[tmpl] = template.Must(t.ParseFiles(tmplDir+"base.html", tmplDir+tmpl))
	}
}

func renderTemplate(w http.ResponseWriter, tmpl string) {
	err := templates[tmpl].Execute(w, pageData)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

// HANDLERS ARE HERE

func indexHandler(w http.ResponseWriter, r *http.Request) {
	if firstStart {
		http.Redirect(w, r, "/setup", http.StatusFound)
		return
	}
	err := r.ParseForm()
	if err != nil {
		panic(err)
	}
	tmpl := "index.html"
	switch r.Method {
	case "GET":
		if pageData.Player.Playing {
			tmpl = "alreadyplaying.html"
		}
	case "POST":
		if pageData.Player.Playing {
			player := pageData.Player
			currentFilm := pageData.CurrentFilm
			pageData = PageData{}
			err = generateMovies(mediaDir)
			if err != nil {
				panic(err)
			}
			pageData.CurrentFilm = currentFilm
			pageData.Player = player
			tmpl = "alreadyplaying.html"
		} else {
			pageData = PageData{}
			err = generateMovies(mediaDir)
			if err != nil {
				panic(err)
			}
		}
	}
	renderTemplate(w, tmpl)
}

func aboutHandler(w http.ResponseWriter, r *http.Request) {
	renderTemplate(w, "about.html")
}

func setupHandler(w http.ResponseWriter, r *http.Request) {
	tmpl := "setup.html"
	err := r.ParseForm()
	if err != nil {
		panic(err)
	}
	if r.Method == "POST" {
		mediaDir = r.Form["filepath"][0]
		if err := generateMovies(mediaDir); err != nil {
			tmpl = "nothingfound.html"
		} else {
			firstStart = false
			http.Redirect(w, r, "/", http.StatusFound)
			return
		}
	}
	renderTemplate(w, tmpl)
}

func movieHandler(w http.ResponseWriter, r *http.Request) {
	command := r.URL.Query().Get("command")
	film := r.URL.Query().Get("movie")

	if pageData.Player.Playing == false {
		if film == "" {
			log.Println("No film was selected")
			http.Redirect(w, r, "/", http.StatusFound)
			return
		}
		err := pageData.Player.StartFilm(film)
		if err != nil {
			log.Printf("Following error occurred: %v\n", err)
			http.Redirect(w, r, "/", http.StatusFound)
			return
		}
		pageData.CurrentFilm = film
	} else if pageData.Player.Playing && (film == "" || pageData.Player.FilmName == film) {
		if command == "kill" {
			err := pageData.Player.EndFilm()
			if err != nil {
				log.Printf("Following error occurred: %v\n", err)
			}
			http.Redirect(w, r, "/", http.StatusFound)
			return
		} else if command != "" {
			err := pageData.Player.SendCommandToFilm(command)
			if err != nil {
				log.Printf("Following error occurred: %v\n", err)
			}
		}
	} else {
		http.Redirect(w, r, "/", http.StatusFound)
		return
	}
	renderTemplate(w, "movie.html")
}

// IT ALL STARTS HERE

func main() {
	generateTemplates()
	http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))
	http.HandleFunc("/", indexHandler)
	http.HandleFunc("/about", aboutHandler)
	http.HandleFunc("/setup", setupHandler)
	http.HandleFunc("/movie", movieHandler)
	http.ListenAndServe(":8080", nil)

}
<commit_msg>Add console logging of error received when rendering templates<commit_after>package main

import (
	"html/template"
	"log"
	"net/http"
)

// GLOBALS DECLARED HERE

var mediaDir string
var tmplDir = "./templates/"
var templates map[string]*template.Template
var pageData = PageData{}
var firstStart = true

// THE VIEW CODE IS HERE

func generateTemplates() {
	templates = make(map[string]*template.Template)
	modulus := template.FuncMap{"mod": func(i, j int) bool { return i%j == 0 }}
	templatesList := []string{"index.html", "about.html", "movie.html", "alreadyplaying.html", "setup.html", "nothingfound.html"}
	for _, tmpl := range templatesList {
		t := template.New("base.html").Funcs(modulus)
		templates[tmpl] = template.Must(t.ParseFiles(tmplDir+"base.html", tmplDir+tmpl))
	}
}

func renderTemplate(w http.ResponseWriter, tmpl string) {
	err := templates[tmpl].Execute(w, pageData)
	if err != nil {
		log.Printf("The follwing error occurred: %v", err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

// HANDLERS ARE HERE

func indexHandler(w http.ResponseWriter, r *http.Request) {
	if firstStart {
		http.Redirect(w, r, "/setup", http.StatusFound)
		return
	}
	err := r.ParseForm()
	if err != nil {
		panic(err)
	}
	tmpl := "index.html"
	switch r.Method {
	case "GET":
		if pageData.Player.Playing {
			tmpl = "alreadyplaying.html"
		}
	case "POST":
		if pageData.Player.Playing {
			player := pageData.Player
			currentFilm := pageData.CurrentFilm
			pageData = PageData{}
			err = generateMovies(mediaDir)
			if err != nil {
				panic(err)
			}
			pageData.CurrentFilm = currentFilm
			pageData.Player = player
			tmpl = "alreadyplaying.html"
		} else {
			pageData = PageData{}
			err = generateMovies(mediaDir)
			if err != nil {
				panic(err)
			}
		}
	}
	renderTemplate(w, tmpl)
}

func aboutHandler(w http.ResponseWriter, r *http.Request) {
	renderTemplate(w, "about.html")
}

func setupHandler(w http.ResponseWriter, r *http.Request) {
	tmpl := "setup.html"
	err := r.ParseForm()
	if err != nil {
		panic(err)
	}
	if r.Method == "POST" {
		mediaDir = r.Form["filepath"][0]
		if err := generateMovies(mediaDir); err != nil {
			tmpl = "nothingfound.html"
		} else {
			firstStart = false
			http.Redirect(w, r, "/", http.StatusFound)
			return
		}
	}
	renderTemplate(w, tmpl)
}

func movieHandler(w http.ResponseWriter, r *http.Request) {
	command := r.URL.Query().Get("command")
	film := r.URL.Query().Get("movie")

	if pageData.Player.Playing == false {
		if film == "" {
			log.Println("No film was selected")
			http.Redirect(w, r, "/", http.StatusFound)
			return
		}
		err := pageData.Player.StartFilm(film)
		if err != nil {
			log.Printf("Following error occurred: %v\n", err)
			http.Redirect(w, r, "/", http.StatusFound)
			return
		}
		pageData.CurrentFilm = film
	} else if pageData.Player.Playing && (film == "" || pageData.Player.FilmName == film) {
		if command == "kill" {
			err := pageData.Player.EndFilm()
			if err != nil {
				log.Printf("Following error occurred: %v\n", err)
			}
			http.Redirect(w, r, "/", http.StatusFound)
			return
		} else if command != "" {
			err := pageData.Player.SendCommandToFilm(command)
			if err != nil {
				log.Printf("Following error occurred: %v\n", err)
			}
		}
	} else {
		http.Redirect(w, r, "/", http.StatusFound)
		return
	}
	renderTemplate(w, "movie.html")
}

// IT ALL STARTS HERE

func main() {
	generateTemplates()
	http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))
	http.HandleFunc("/", indexHandler)
	http.HandleFunc("/about", aboutHandler)
	http.HandleFunc("/setup", setupHandler)
	http.HandleFunc("/movie", movieHandler)
	http.ListenAndServe(":8080", nil)

}
<|endoftext|>


<commit_before>package golangsdk

import (
	"crypto/tls"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"strconv"
	"time"
)

const (
	zincBaseURL = "https://api.zinc.io/v1"
)

type Retailer string

const (
	Amazon     Retailer = "amazon"
	AmazonUK   Retailer = "amazon_uk"
	AmazonCA   Retailer = "amazon_ca"
	AmazonMX   Retailer = "amazon_mx"
	Walmart    Retailer = "walmart"
	Aliexpress Retailer = "aliexpress"
)

var DefaultProductOptions = ProductOptions{
	Timeout: time.Duration(time.Second * 90),
}

type Zinc struct {
	ClientToken string
	ZincBaseURL string
}

func GetRetailer(retailer string) (Retailer, error) {
	switch retailer {
	case "amazon":
		return Amazon, nil
	case "amazon_uk":
		return AmazonUK, nil
	case "amazon_ca":
		return AmazonCA, nil
	case "amazon_mx":
		return AmazonMX, nil
	case "walmart":
		return Walmart, nil
	case "aliexpress":
		return Aliexpress, nil
	default:
		return Amazon, fmt.Errorf("Invalid retailer string")
	}
}

func NewZinc(clientToken string) (*Zinc, error) {
	z := Zinc{
		ClientToken: clientToken,
		ZincBaseURL: zincBaseURL,
	}
	return &z, nil
}

type ProductOffersResponse struct {
	Code     string            `json:"code"`
	Data     ErrorDataResponse `json:"data"`
	Status   string            `json:"status"`
	Retailer string            `json:"retailer"`
	Offers   []ProductOffer    `json:"offers"`
}

type ProductOffer struct {
	Available            bool             `json:"available"`
	Addon                bool             `json:"addon"`
	Condition            string           `json:"condition"`
	ShippingOptions      []ShippingOption `json:"shipping_options"`
	HandlingDays         HandlingDays     `json:"handling_days"`
	PrimeOnly            bool             `json:"prime_only"`
	MarketplaceFulfilled bool             `json:"marketplace_fulfilled"`
	Currency             string           `json:"currency"`
	Seller               Seller           `json:"seller"`
	BuyBoxWinner         bool             `json:"buy_box_winner"`
	International        bool             `json:"international"`
	OfferId              string           `json:"offer_id"`
	Price                int              `json:"price"`
}

type ShippingOption struct {
	Price int `json:"price"`
}

type HandlingDays struct {
	Max int `json:"max"`
	Min int `json:"min"`
}

type Seller struct {
	NumRatings      int    `json:"num_ratings"`
	PercentPositive int    `json:"percent_positive"`
	FirstParty      bool   `json:"first_party"`
	Name            string `json:"name"`
	Id              string `json:"id"`
}

type ProductDetailsResponse struct {
	Code               string              `json:"code"`
	Data               ErrorDataResponse   `json:"data"`
	Status             string              `json:"status"`
	ProductDescription string              `json:"product_description"`
	PostDescription    string              `json:"post_description"`
	Retailer           string              `json:"retailer"`
	Epids              []ExternalProductId `json:"epids"`
	ProductDetails     []string            `json:"product_details"`
	Title              string              `json:"title"`
	VariantSpecifics   []VariantSpecific   `json:"variant_specifics"`
	ProductId          json.Number         `json:"product_id"`
	MainImage          string              `json:"main_image"`
	Brand              string              `json:"brand"`
	MPN                string              `json:"mpn"`
	Images             []string            `json:"images"`
	FeatureBullets     []string            `json:"feature_bullets"`
}

type ExternalProductId struct {
	Type  string `json:"type"`
	Value string `json:"value"`
}

type VariantSpecific struct {
	Dimension string `json:"dimension"`
	Value     string `json:"value"`
}

type ErrorDataResponse struct {
	Message string `json:"message"`
}

type ProductOptions struct {
	MaxAge    int           `json:"max_age"`
	NewerThan time.Time     `json:"newer_than"`
	Timeout   time.Duration `json:"timeout"`
}

type ZincError struct {
	ErrorMessage string            `json:"error"`
	Data         ErrorDataResponse `json:"data"`
}

func (z ZincError) Error() string {
	return z.ErrorMessage
}

func SimpleError(errorStr string) ZincError {
	return ZincError{ErrorMessage: errorStr}
}

func (z Zinc) GetProductInfo(productId string, retailer Retailer, options ProductOptions) (*ProductOffersResponse, *ProductDetailsResponse, error) {
	offersChan := make(chan *ProductOffersResponse, 1)
	detailsChan := make(chan *ProductDetailsResponse, 1)
	errorsChan := make(chan error, 2)

	go func() {
		offers, err := z.GetProductOffers(productId, retailer, options)
		errorsChan <- err
		offersChan <- offers
	}()

	go func() {
		details, err := z.GetProductDetails(productId, retailer, options)
		errorsChan <- err
		detailsChan <- details
	}()

	offers := <-offersChan
	details := <-detailsChan
	for i := 0; i < 2; i++ {
		err := <-errorsChan
		if err != nil {
			return nil, nil, err
		}
	}
	return offers, details, nil
}

func (z Zinc) GetProductOffers(productId string, retailer Retailer, options ProductOptions) (*ProductOffersResponse, error) {
	values := url.Values{}
	values.Set("retailer", string(retailer))
	values.Set("version", "2")
	if options.MaxAge != 0 {
		values.Set("max_age", strconv.Itoa(options.MaxAge))
	}
	if !options.NewerThan.IsZero() {
		values.Set("newer_than", strconv.FormatInt(options.NewerThan.Unix(), 10))
	}
	requestPath := fmt.Sprintf("%v/products/%v/offers?%v", z.ZincBaseURL, productId, values.Encode())

	respBody, err := z.sendGetRequest(requestPath, options.Timeout)
	if err != nil {
		return nil, SimpleError(err.Error())
	}
	var resp ProductOffersResponse
	if err := json.Unmarshal(respBody, &resp); err != nil {
		log.Printf("[Golangsdk] Unable to unmarshal offers response body=%v", string(respBody))
		return nil, SimpleError(err.Error())
	}
	if resp.Status == "failed" {
		msg := fmt.Sprintf("Zinc API returned status 'failed' data=%+v", resp.Data)
		return &resp, ZincError{ErrorMessage: msg, Data: resp.Data}
	}
	return &resp, nil
}

func (z Zinc) GetProductDetails(productId string, retailer Retailer, options ProductOptions) (*ProductDetailsResponse, error) {
	values := url.Values{}
	values.Set("retailer", string(retailer))
	if options.MaxAge != 0 {
		values.Set("max_age", strconv.Itoa(options.MaxAge))
	}
	if !options.NewerThan.IsZero() {
		values.Set("newer_than", strconv.FormatInt(options.NewerThan.Unix(), 10))
	}
	requestPath := fmt.Sprintf("%v/products/%v?%v", z.ZincBaseURL, productId, values.Encode())

	respBody, err := z.sendGetRequest(requestPath, options.Timeout)
	if err != nil {
		return nil, SimpleError(err.Error())
	}
	var resp ProductDetailsResponse
	if err := json.Unmarshal(respBody, &resp); err != nil {
		log.Printf("[Golangsdk] Unable to unmarshal details response body=%v", string(respBody))
		return nil, SimpleError(err.Error())
	}
	if resp.Status == "failed" {
		msg := fmt.Sprintf("Zinc API returned status 'failed' data=%+v", resp.Data)
		return &resp, ZincError{ErrorMessage: msg, Data: resp.Data}
	}
	return &resp, nil
}

func (z Zinc) sendGetRequest(requestPath string, timeout time.Duration) ([]byte, error) {
	httpReq, err := http.NewRequest("GET", requestPath, nil)
	if err != nil {
		return nil, err
	}
	httpReq.SetBasicAuth(z.ClientToken, "")
	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}
	client := &http.Client{Transport: tr, Timeout: timeout}
	resp, err := client.Do(httpReq)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	return respBody, nil
}
<commit_msg>Allow for priority option.<commit_after>package golangsdk

import (
	"crypto/tls"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"strconv"
	"time"
)

const (
	zincBaseURL = "https://api.zinc.io/v1"
)

type Retailer string

const (
	Amazon     Retailer = "amazon"
	AmazonUK   Retailer = "amazon_uk"
	AmazonCA   Retailer = "amazon_ca"
	AmazonMX   Retailer = "amazon_mx"
	Walmart    Retailer = "walmart"
	Aliexpress Retailer = "aliexpress"
)

var DefaultProductOptions = ProductOptions{
	Timeout: time.Duration(time.Second * 90),
}

type Zinc struct {
	ClientToken string
	ZincBaseURL string
}

func GetRetailer(retailer string) (Retailer, error) {
	switch retailer {
	case "amazon":
		return Amazon, nil
	case "amazon_uk":
		return AmazonUK, nil
	case "amazon_ca":
		return AmazonCA, nil
	case "amazon_mx":
		return AmazonMX, nil
	case "walmart":
		return Walmart, nil
	case "aliexpress":
		return Aliexpress, nil
	default:
		return Amazon, fmt.Errorf("Invalid retailer string")
	}
}

func NewZinc(clientToken string) (*Zinc, error) {
	z := Zinc{
		ClientToken: clientToken,
		ZincBaseURL: zincBaseURL,
	}
	return &z, nil
}

type ProductOffersResponse struct {
	Code     string            `json:"code"`
	Data     ErrorDataResponse `json:"data"`
	Status   string            `json:"status"`
	Retailer string            `json:"retailer"`
	Offers   []ProductOffer    `json:"offers"`
}

type ProductOffer struct {
	Available            bool             `json:"available"`
	Addon                bool             `json:"addon"`
	Condition            string           `json:"condition"`
	ShippingOptions      []ShippingOption `json:"shipping_options"`
	HandlingDays         HandlingDays     `json:"handling_days"`
	PrimeOnly            bool             `json:"prime_only"`
	MarketplaceFulfilled bool             `json:"marketplace_fulfilled"`
	Currency             string           `json:"currency"`
	Seller               Seller           `json:"seller"`
	BuyBoxWinner         bool             `json:"buy_box_winner"`
	International        bool             `json:"international"`
	OfferId              string           `json:"offer_id"`
	Price                int              `json:"price"`
}

type ShippingOption struct {
	Price int `json:"price"`
}

type HandlingDays struct {
	Max int `json:"max"`
	Min int `json:"min"`
}

type Seller struct {
	NumRatings      int    `json:"num_ratings"`
	PercentPositive int    `json:"percent_positive"`
	FirstParty      bool   `json:"first_party"`
	Name            string `json:"name"`
	Id              string `json:"id"`
}

type ProductDetailsResponse struct {
	Code               string              `json:"code"`
	Data               ErrorDataResponse   `json:"data"`
	Status             string              `json:"status"`
	ProductDescription string              `json:"product_description"`
	PostDescription    string              `json:"post_description"`
	Retailer           string              `json:"retailer"`
	Epids              []ExternalProductId `json:"epids"`
	ProductDetails     []string            `json:"product_details"`
	Title              string              `json:"title"`
	VariantSpecifics   []VariantSpecific   `json:"variant_specifics"`
	ProductId          json.Number         `json:"product_id"`
	MainImage          string              `json:"main_image"`
	Brand              string              `json:"brand"`
	MPN                string              `json:"mpn"`
	Images             []string            `json:"images"`
	FeatureBullets     []string            `json:"feature_bullets"`
}

type ExternalProductId struct {
	Type  string `json:"type"`
	Value string `json:"value"`
}

type VariantSpecific struct {
	Dimension string `json:"dimension"`
	Value     string `json:"value"`
}

type ErrorDataResponse struct {
	Message string `json:"message"`
}

type ProductOptions struct {
	MaxAge    int           `json:"max_age"`
	Priority  int           `json:"priority"`
	NewerThan time.Time     `json:"newer_than"`
	Timeout   time.Duration `json:"timeout"`
}

type ZincError struct {
	ErrorMessage string            `json:"error"`
	Data         ErrorDataResponse `json:"data"`
}

func (z ZincError) Error() string {
	return z.ErrorMessage
}

func SimpleError(errorStr string) ZincError {
	return ZincError{ErrorMessage: errorStr}
}

func (z Zinc) GetProductInfo(productId string, retailer Retailer, options ProductOptions) (*ProductOffersResponse, *ProductDetailsResponse, error) {
	offersChan := make(chan *ProductOffersResponse, 1)
	detailsChan := make(chan *ProductDetailsResponse, 1)
	errorsChan := make(chan error, 2)

	go func() {
		offers, err := z.GetProductOffers(productId, retailer, options)
		errorsChan <- err
		offersChan <- offers
	}()

	go func() {
		details, err := z.GetProductDetails(productId, retailer, options)
		errorsChan <- err
		detailsChan <- details
	}()

	offers := <-offersChan
	details := <-detailsChan
	for i := 0; i < 2; i++ {
		err := <-errorsChan
		if err != nil {
			return nil, nil, err
		}
	}
	return offers, details, nil
}

func (z Zinc) GetProductOffers(productId string, retailer Retailer, options ProductOptions) (*ProductOffersResponse, error) {
	values := url.Values{}
	values.Set("retailer", string(retailer))
	values.Set("version", "2")
	if options.MaxAge != 0 {
		values.Set("max_age", strconv.Itoa(options.MaxAge))
	}
	if !options.NewerThan.IsZero() {
		values.Set("newer_than", strconv.FormatInt(options.NewerThan.Unix(), 10))
	}
	requestPath := fmt.Sprintf("%v/products/%v/offers?%v", z.ZincBaseURL, productId, values.Encode())

	respBody, err := z.sendGetRequest(requestPath, options.Timeout)
	if err != nil {
		return nil, SimpleError(err.Error())
	}
	var resp ProductOffersResponse
	if err := json.Unmarshal(respBody, &resp); err != nil {
		log.Printf("[Golangsdk] Unable to unmarshal offers response body=%v", string(respBody))
		return nil, SimpleError(err.Error())
	}
	if resp.Status == "failed" {
		msg := fmt.Sprintf("Zinc API returned status 'failed' data=%+v", resp.Data)
		return &resp, ZincError{ErrorMessage: msg, Data: resp.Data}
	}
	return &resp, nil
}

func (z Zinc) GetProductDetails(productId string, retailer Retailer, options ProductOptions) (*ProductDetailsResponse, error) {
	values := url.Values{}
	values.Set("retailer", string(retailer))
	if options.MaxAge != 0 {
		values.Set("max_age", strconv.Itoa(options.MaxAge))
	}
	if !options.NewerThan.IsZero() {
		values.Set("newer_than", strconv.FormatInt(options.NewerThan.Unix(), 10))
	}
	if options.Priority != 0 {
		values.Set("priority", strconv.Itoa(options.Priority))
	}
	requestPath := fmt.Sprintf("%v/products/%v?%v", z.ZincBaseURL, productId, values.Encode())

	respBody, err := z.sendGetRequest(requestPath, options.Timeout)
	if err != nil {
		return nil, SimpleError(err.Error())
	}
	var resp ProductDetailsResponse
	if err := json.Unmarshal(respBody, &resp); err != nil {
		log.Printf("[Golangsdk] Unable to unmarshal details response body=%v", string(respBody))
		return nil, SimpleError(err.Error())
	}
	if resp.Status == "failed" {
		msg := fmt.Sprintf("Zinc API returned status 'failed' data=%+v", resp.Data)
		return &resp, ZincError{ErrorMessage: msg, Data: resp.Data}
	}
	return &resp, nil
}

func (z Zinc) sendGetRequest(requestPath string, timeout time.Duration) ([]byte, error) {
	httpReq, err := http.NewRequest("GET", requestPath, nil)
	if err != nil {
		return nil, err
	}
	httpReq.SetBasicAuth(z.ClientToken, "")
	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}
	client := &http.Client{Transport: tr, Timeout: timeout}
	resp, err := client.Do(httpReq)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	return respBody, nil
}
<|endoftext|>


<commit_before>package gopp

import (
	"bytes"
	"fmt"
	"go/parser"
	"go/printer"
	"go/scanner"
	"go/token"
	"io"
	"io/ioutil"
	"os"
	"strings"
)

type Token struct {
	Position token.Pos
	Token    token.Token
	String   string
}

type gopp struct {
	defines                 map[string]interface{}
	output                  chan Token
	StripComments, ignoring bool
	Prefix                  string
}

func (g *gopp) DefineValue(key string, value interface{}) {
	g.defines[key] = value
}

func (g *gopp) Define(key string) {
	g.DefineValue(key, nil)
}

func (g *gopp) Undefine(key string) {
	delete(g.defines, key)
}

func (g *gopp) Parse(r io.Reader) error {
	src, err := ioutil.ReadAll(r)
	if err != nil {
		return err
	}

	fset := token.NewFileSet()
	file := fset.AddFile("<stdin>", fset.Base(), len(src))

	s := scanner.Scanner{}
	s.Init(file, src, nil, scanner.ScanComments)

	go func() {
		for {
			pos, tok_, str := s.Scan()
			if len(str) == 0 {
				str = tok_.String()
			}
			tok := Token{pos, tok_, str}

			if tok.Token == token.EOF {
				break
			}

			if tok.Token != token.COMMENT && !g.ignoring {
				val, ok := g.defines[tok.String]
				if ok {
					tok.String = val.(string)
				}
				g.output <- tok
				continue
			}

			if !strings.HasPrefix(str, g.Prefix) {
				if !g.StripComments && !g.ignoring {
					tok.String += "\n"
					g.output <- tok
				}
				continue
			}

			// Trim the prefix from the start.
			strTrim := strings.Replace(tok.String, g.Prefix, "", 1)
			lnr := strings.SplitN(strTrim, " ", 2)
			if len(lnr) < 1 {
				fmt.Println("Invalid gopp comment:", str)
				continue
			}

			cmd := strings.ToLower(lnr[0])

			if cmd == "ifdef" {
				if len(lnr) != 2 {
					continue
				}
				def := lnr[1]
				_, ok := g.defines[def]
				g.ignoring = !ok
			} else if cmd == "ifndef" {
				if len(lnr) != 2 {
					continue
				}
				def := lnr[1]
				_, ok := g.defines[def]
				g.ignoring = ok
			} else if cmd == "else" {
				g.ignoring = !g.ignoring
			} else if cmd == "endif" && g.ignoring {
				g.ignoring = false
			} else if cmd == "define" && !g.ignoring {
				if len(lnr) != 2 {
					continue
				}
				lnr = strings.SplitN(lnr[1], " ", 2)
				g.DefineValue(lnr[0], lnr[1])
			} else if cmd == "undef" && !g.ignoring {
				if len(lnr) != 2 {
					continue
				}
				g.Undefine(lnr[1])
			}
		}
		close(g.output)
	}()
	return nil
}

func (g *gopp) Print(w io.Writer) {
	outbuf := new(bytes.Buffer)
	for tok := range g.output {
		fmt.Fprintf(outbuf, " %s", tok.String)
	}

	fset := token.NewFileSet()
	file, err := parser.ParseFile(fset, "<stdin>", outbuf, parser.ParseComments)
	if err != nil {
		panic(err)
	}

	printer.Fprint(os.Stdout, fset, file)
}

// This resets the bits of the gopp which you should really redefine
// each time you want to parse a new file.
func (g *gopp) Reset() {
	g.defines = make(map[string]interface{})
	g.output = make(chan Token)
	g.ignoring = false
}

// New creates a new gopp instance with sane defaults.
func New(strip bool) *gopp {
	return &gopp{
		defines:       make(map[string]interface{}),
		output:        make(chan Token),
		StripComments: strip,
		ignoring:      false,
		Prefix:        "//gopp:",
	}
}
<commit_msg>gopp/gopp.go: documented exported functions and types.<commit_after>// gopp provides an easy to use (but somewhat illogical) preprocessor for Go.
package gopp

import (
	"bytes"
	"fmt"
	"go/parser"
	"go/printer"
	"go/scanner"
	"go/token"
	"io"
	"io/ioutil"
	"os"
	"strings"
)

const version = "0.3"

// Token provides a simple struct face to the `pos, tok, lit` returned by
// Go's go/scanner package. This is passed around by gopp internally in a chan.
type Token struct {
	Position token.Pos
	Token    token.Token
	String   string
}

type gopp struct {
	defines                 map[string]interface{}
	output                  chan Token
	StripComments, ignoring bool
	Prefix                  string
}

// DefineValue takes a key and a value, and defines them as a macro to use when
// preprocessing a Go file.
func (g *gopp) DefineValue(key string, value interface{}) {
	g.defines[key] = value
}

// Define takes a key, and sets it to the sane default of 1, which can then be
// used when preprocessing a Go file.
func (g *gopp) Define(key string) {
	g.DefineValue(key, 1)
}

// Undefine will remove a given macro from the macro list used when processing
// Go files.
func (g *gopp) Undefine(key string) {
	delete(g.defines, key)
}

// Parse takes an io.Reader (usually from an os.Open call), and will process the
// resulting code read from it, preprocessing and substituting in macros as
// required.
func (g *gopp) Parse(r io.Reader) error {
	src, err := ioutil.ReadAll(r)
	if err != nil {
		return err
	}

	fset := token.NewFileSet()
	file := fset.AddFile("<stdin>", fset.Base(), len(src))

	s := scanner.Scanner{}
	s.Init(file, src, nil, scanner.ScanComments)

	go func() {
		for {
			pos, tok_, str := s.Scan()
			if len(str) == 0 {
				str = tok_.String()
			}
			tok := Token{pos, tok_, str}

			if tok.Token == token.EOF {
				break
			}

			if tok.Token != token.COMMENT && !g.ignoring {
				val, ok := g.defines[tok.String]
				if ok {
					tok.String = val.(string)
				}
				g.output <- tok
				continue
			}

			if !strings.HasPrefix(str, g.Prefix) {
				if !g.StripComments && !g.ignoring {
					tok.String += "\n"
					g.output <- tok
				}
				continue
			}

			// Trim the prefix from the start.
			strTrim := strings.Replace(tok.String, g.Prefix, "", 1)
			lnr := strings.SplitN(strTrim, " ", 2)
			if len(lnr) < 1 {
				fmt.Println("Invalid gopp comment:", str)
				continue
			}

			cmd := strings.ToLower(lnr[0])

			if cmd == "ifdef" {
				if len(lnr) != 2 {
					continue
				}
				def := lnr[1]
				_, ok := g.defines[def]
				g.ignoring = !ok
			} else if cmd == "ifndef" {
				if len(lnr) != 2 {
					continue
				}
				def := lnr[1]
				_, ok := g.defines[def]
				g.ignoring = ok
			} else if cmd == "else" {
				g.ignoring = !g.ignoring
			} else if cmd == "endif" && g.ignoring {
				g.ignoring = false
			} else if cmd == "define" && !g.ignoring {
				if len(lnr) != 2 {
					continue
				}
				lnr = strings.SplitN(lnr[1], " ", 2)
				g.DefineValue(lnr[0], lnr[1])
			} else if cmd == "undef" && !g.ignoring {
				if len(lnr) != 2 {
					continue
				}
				g.Undefine(lnr[1])
			}
		}
		close(g.output)
	}()
	return nil
}

// Print takes the resulting new AST after a call to Parse, and will print it
// to the given io.Writer
func (g *gopp) Print(w io.Writer) {
	outbuf := new(bytes.Buffer)
	for tok := range g.output {
		fmt.Fprintf(outbuf, " %s", tok.String)
	}

	fset := token.NewFileSet()
	file, err := parser.ParseFile(fset, "<stdin>", outbuf, parser.ParseComments)
	if err != nil {
		panic(err)
	}

	printer.Fprint(os.Stdout, fset, file)
}

// Reset will redefine the bits of a gopp instance, which you can use (e.g.)
// each time you want to parse a new file.
func (g *gopp) Reset() {
	g.defines = make(map[string]interface{})
	g.output = make(chan Token)
	g.ignoring = false
}

// New creates a new gopp instance with sane defaults.
func New(strip bool) (g *gopp) {
	 g = &gopp{
		defines:       make(map[string]interface{}),
		output:        make(chan Token),
		StripComments: strip,
		ignoring:      false,
		Prefix:        "//gopp:",
	}
	g.DefineValue("_GOPP", version)
	return
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"path/filepath"
	"fmt"
	"regexp"
	"bytes"
	"errors"
	goopt "github.com/droundy/goopt"
	"./highlight"
	"./ignore"
)

var Author = "Alexander Solovyov"
var Version = "0.3.3"
var Summary = "gr [OPTS] string-to-search\n"

var byteNewLine []byte = []byte("\n")

var onlyName = goopt.Flag([]string{"-n", "--filename"}, []string{},
	"print only filenames", "")
var ignoreFiles = goopt.Strings([]string{"-x", "--exclude"}, "RE",
	"exclude files that match the regexp from search")
var singleline = goopt.Flag([]string{"-s", "--singleline"}, []string{},
	"match on a single line (^/$ will be beginning/end of line)", "")
var replace = goopt.String([]string{"-r", "--replace"}, "",
	"replace found substrings with this string")
var force = goopt.Flag([]string{"--force"}, []string{},
	"force replacement in binary files", "")
var showVersion = goopt.Flag([]string{"-v", "--version"}, []string{},
	"show version and exit", "")

func main() {
	goopt.Author = Author
	goopt.Version = Version
	goopt.Summary = Summary
	goopt.Usage = func() string {
		return fmt.Sprintf("Usage of goreplace %s:\n\t", Version) +
			goopt.Summary + "\n" + goopt.Help()
	}

	cwd, _ := os.Getwd()
	ignorer := ignore.New(cwd)
	goopt.Summary += fmt.Sprintf("\n%s", ignorer)

	goopt.Parse(nil)

	if *showVersion {
		println("goreplace " + goopt.Version)
		return
	}

	ignorer.Append(*ignoreFiles)

	if len(goopt.Args) == 0 {
		println(goopt.Usage())
		return
	}

	pattern, err := regexp.Compile(goopt.Args[0])
	errhandle(err, true, "can't compile regexp %s", goopt.Args[0])

	searchFiles(pattern, ignorer)
}

func errhandle(err error, exit bool, moreinfo string, a ...interface{}) {
	if err == nil {
		return
	}
	fmt.Fprintf(os.Stderr, "ERR %s\n%s\n", err, fmt.Sprintf(moreinfo, a...))
	if exit {
		os.Exit(1)
	}
}

func searchFiles(pattern *regexp.Regexp, ignorer ignore.Ignorer) {
	v := &GRVisitor{pattern, ignorer, false}

	errors := make(chan error, 64)

	filepath.Walk(".", walkFunc(v, errors))

	select {
	case err := <-errors:
		errhandle(err, true, "some error")
	default:
	}
}

func walkFunc(v *GRVisitor, errors chan <- error) filepath.WalkFunc {
	return func (fn string, fi *os.FileInfo, err error) error {
		if err != nil {
			errors <- err
			return nil
		}

		if fi.IsDirectory() {
			if !v.VisitDir(fn, fi) {
				return filepath.SkipDir
			}
			return nil
		}

		v.VisitFile(fn, fi)
		return nil
	}
}

type GRVisitor struct {
	pattern *regexp.Regexp
	ignorer ignore.Ignorer
	// Used to prevent sparse newline at the end of output
	prependNewLine bool
}

func (v *GRVisitor) VisitDir(fn string, fi *os.FileInfo) bool {
	return !v.ignorer.Ignore(fi.Name, true)
}

func (v *GRVisitor) VisitFile(fn string, fi *os.FileInfo) {
	if !fi.IsRegular() {
		return
	}

	if fi.Size >= 1024*1024*10 {
		fmt.Fprintf(os.Stderr, "Skipping %s, too big: %d\n", fn, fi.Size)
		return
	}

	if fi.Size == 0 {
		return
	}

	if v.ignorer.Ignore(fn, false) {
		return
	}

	f, content := v.GetFileAndContent(fn, fi)
	defer f.Close()

	if len(*replace) == 0 {
		v.SearchFile(fn, content)
		return
	}

	changed, result := v.ReplaceInFile(fn, content)
	if changed {
		f.Seek(0, 0)
		n, err := f.Write(result)
		errhandle(err, true, "Error writing replacement in file %s", fn)
		if int64(n) < fi.Size {
			err := f.Truncate(int64(n))
			errhandle(err, true, "Error truncating file to size %d", f)
		}
	}
}

func (v *GRVisitor) GetFileAndContent(fn string, fi *os.FileInfo) (
	f *os.File, content []byte) {
	var err error
	var msg string

	if len(*replace) > 0 {
		f, err = os.OpenFile(fn, os.O_RDWR, 0666)
		msg = "can't open file %s for reading and writing"
	} else {
		f, err = os.Open(fn)
		msg = "can't open file %s for reading"
	}

	if err != nil {
		errhandle(err, false, msg, fn)
		return
	}

	content = make([]byte, fi.Size)
	n, err := f.Read(content)
	errhandle(err, true, "can't read file %s", fn)
	if int64(n) != fi.Size {
		panic(fmt.Sprintf("Not whole file was read, only %d from %d",
			n, fi.Size))
	}

	return
}

func (v *GRVisitor) SearchFile(fn string, content []byte) {
	lines := IntList([]int{})
	binary := false

	if bytes.IndexByte(content, 0) != -1 {
		binary = true
	}

	for _, info := range v.FindAllIndex(content) {
		if lines.Contains(info.num) {
			continue
		}

		if v.prependNewLine {
			fmt.Println("")
			v.prependNewLine = false
		}

		var first = len(lines) == 0
		lines = append(lines, info.num)

		if first {
			if binary && !*onlyName {
				fmt.Printf("Binary file %s matches\n", fn)
				break
			} else {
				highlight.Printf("green", "%s\n", fn)
			}
		}

		if *onlyName {
			return
		}

		highlight.Printf("bold yellow", "%d:", info.num)
		highlight.Reprintlnf("on_yellow", v.pattern, "%s", info.line)
	}

	if len(lines) > 0 {
		v.prependNewLine = true
	}
}

func getSuffix(num int) string {
	if num > 1 {
		return "s"
	}
	return ""
}

func (v *GRVisitor) ReplaceInFile(fn string, content []byte) (
	changed bool, result []byte) {
	changed = false
	binary := false
	changenum := 0

	if *singleline {
		panic("Can't handle singleline replacements yet")
	}

	if bytes.IndexByte(content, 0) != -1 {
		binary = true
	}

	result = v.pattern.ReplaceAllFunc(content, func(s []byte) []byte {
		if binary && !*force {
			errhandle(
				errors.New("supply --force to force change of binary file"),
				false, "")
		}
		if !changed {
			changed = true
			highlight.Printf("green", "%s", fn)
		}

		changenum += 1
		return []byte(*replace)
	})

	if changenum > 0 {
		highlight.Printf("bold yellow", " - %d change%s made\n",
			changenum, getSuffix(changenum))
	}

	return changed, result
}

type LineInfo struct {
	num  int
	line []byte
}

// will return slice of [linenum, line] slices
func (v *GRVisitor) FindAllIndex(content []byte) (res []*LineInfo) {
	linenum := 1

	if *singleline {
		begin, end := 0, 0
		for i := 0; i < len(content); i++ {
			if content[i] == '\n' {
				end = i
				line := content[begin:end]
				if v.pattern.Match(line) {
					res = append(res, &LineInfo{linenum, line})
				}
				linenum += 1
				begin = end + 1
			}
		}
		return res
	}

	last := 0
	for _, bounds := range v.pattern.FindAllIndex(content, -1) {
		linenum += bytes.Count(content[last:bounds[0]], byteNewLine)
		last = bounds[0]
		begin, end := beginend(content, bounds[0], bounds[1])
		res = append(res, &LineInfo{linenum, content[begin:end]})
	}
	return res
}

// Given a []byte, start and finish of some inner slice, will find nearest
// newlines on both ends of this slice
func beginend(s []byte, start int, finish int) (begin int, end int) {
	begin = 0
	end = len(s)

	for i := start; i >= 0; i-- {
		if s[i] == byteNewLine[0] {
			begin = i + 1
			break
		}
	}

	// -1 to check if current location is not end of string
	for i := finish - 1; i < len(s); i++ {
		if s[i] == byteNewLine[0] {
			end = i
			break
		}
	}

	return
}

type IntList []int

func (il IntList) Contains(i int) bool {
	for _, x := range il {
		if x == i {
			return true
		}
	}
	return false
}
<commit_msg>update to current go<commit_after>package main

import (
	"bytes"
	"errors"
	"fmt"
	goopt "github.com/droundy/goopt"
	"./highlight"
	"./ignore"
	"os"
	"path/filepath"
	"regexp"
)

var Author = "Alexander Solovyov"
var Version = "0.3.3"
var Summary = "gr [OPTS] string-to-search\n"

var byteNewLine []byte = []byte("\n")

var onlyName = goopt.Flag([]string{"-n", "--filename"}, []string{},
	"print only filenames", "")
var ignoreFiles = goopt.Strings([]string{"-x", "--exclude"}, "RE",
	"exclude files that match the regexp from search")
var singleline = goopt.Flag([]string{"-s", "--singleline"}, []string{},
	"match on a single line (^/$ will be beginning/end of line)", "")
var replace = goopt.String([]string{"-r", "--replace"}, "",
	"replace found substrings with this string")
var force = goopt.Flag([]string{"--force"}, []string{},
	"force replacement in binary files", "")
var showVersion = goopt.Flag([]string{"-v", "--version"}, []string{},
	"show version and exit", "")

func main() {
	goopt.Author = Author
	goopt.Version = Version
	goopt.Summary = Summary
	goopt.Usage = func() string {
		return fmt.Sprintf("Usage of goreplace %s:\n\t", Version) +
			goopt.Summary + "\n" + goopt.Help()
	}

	cwd, _ := os.Getwd()
	ignorer := ignore.New(cwd)
	goopt.Summary += fmt.Sprintf("\n%s", ignorer)

	goopt.Parse(nil)

	if *showVersion {
		println("goreplace " + goopt.Version)
		return
	}

	ignorer.Append(*ignoreFiles)

	if len(goopt.Args) == 0 {
		println(goopt.Usage())
		return
	}

	pattern, err := regexp.Compile(goopt.Args[0])
	errhandle(err, true, "can't compile regexp %s", goopt.Args[0])

	searchFiles(pattern, ignorer)
}

func errhandle(err error, exit bool, moreinfo string, a ...interface{}) {
	if err == nil {
		return
	}
	fmt.Fprintf(os.Stderr, "ERR %s\n%s\n", err, fmt.Sprintf(moreinfo, a...))
	if exit {
		os.Exit(1)
	}
}

func searchFiles(pattern *regexp.Regexp, ignorer ignore.Ignorer) {
	v := &GRVisitor{pattern, ignorer, false}

	errors := make(chan error, 64)

	filepath.Walk(".", walkFunc(v, errors))

	select {
	case err := <-errors:
		errhandle(err, true, "some error")
	default:
	}
}

func walkFunc(v *GRVisitor, errors chan<- error) filepath.WalkFunc {
	return func(fn string, fi os.FileInfo, err error) error {
		if err != nil {
			errors <- err
			return nil
		}

		if fi.IsDir() {
			if !v.VisitDir(fn, fi) {
				return filepath.SkipDir
			}
			return nil
		}

		v.VisitFile(fn, fi)
		return nil
	}
}

type GRVisitor struct {
	pattern *regexp.Regexp
	ignorer ignore.Ignorer
	// Used to prevent sparse newline at the end of output
	prependNewLine bool
}

func (v *GRVisitor) VisitDir(fn string, fi os.FileInfo) bool {
	return !v.ignorer.Ignore(fi.Name(), true)
}

func (v *GRVisitor) VisitFile(fn string, fi os.FileInfo) {
	if fi.IsDir() {
		return
	}

	if fi.Size() >= 1024*1024*10 {
		fmt.Fprintf(os.Stderr, "Skipping %s, too big: %d\n", fn, fi.Size())
		return
	}

	if fi.Size() == 0 {
		return
	}

	if v.ignorer.Ignore(fn, false) {
		return
	}

	f, content := v.GetFileAndContent(fn, fi)
	defer f.Close()

	if len(*replace) == 0 {
		v.SearchFile(fn, content)
		return
	}

	changed, result := v.ReplaceInFile(fn, content)
	if changed {
		f.Seek(0, 0)
		n, err := f.Write(result)
		errhandle(err, true, "Error writing replacement in file %s", fn)
		if int64(n) < fi.Size() {
			err := f.Truncate(int64(n))
			errhandle(err, true, "Error truncating file to size %d", f)
		}
	}
}

func (v *GRVisitor) GetFileAndContent(fn string, fi os.FileInfo) (f *os.File, content []byte) {
	var err error
	var msg string

	if len(*replace) > 0 {
		f, err = os.OpenFile(fn, os.O_RDWR, 0666)
		msg = "can't open file %s for reading and writing"
	} else {
		f, err = os.Open(fn)
		msg = "can't open file %s for reading"
	}

	if err != nil {
		errhandle(err, false, msg, fn)
		return
	}

	content = make([]byte, fi.Size())
	n, err := f.Read(content)
	errhandle(err, true, "can't read file %s", fn)
	if int64(n) != fi.Size() {
		panic(fmt.Sprintf("Not whole file was read, only %d from %d",
			n, fi.Size()))
	}

	return
}

func (v *GRVisitor) SearchFile(fn string, content []byte) {
	lines := IntList([]int{})
	binary := false

	if bytes.IndexByte(content, 0) != -1 {
		binary = true
	}

	for _, info := range v.FindAllIndex(content) {
		if lines.Contains(info.num) {
			continue
		}

		if v.prependNewLine {
			fmt.Println("")
			v.prependNewLine = false
		}

		var first = len(lines) == 0
		lines = append(lines, info.num)

		if first {
			if binary && !*onlyName {
				fmt.Printf("Binary file %s matches\n", fn)
				break
			} else {
				highlight.Printf("green", "%s\n", fn)
			}
		}

		if *onlyName {
			return
		}

		highlight.Printf("bold yellow", "%d:", info.num)
		highlight.Reprintlnf("on_yellow", v.pattern, "%s", info.line)
	}

	if len(lines) > 0 {
		v.prependNewLine = true
	}
}

func getSuffix(num int) string {
	if num > 1 {
		return "s"
	}
	return ""
}

func (v *GRVisitor) ReplaceInFile(fn string, content []byte) (changed bool, result []byte) {
	changed = false
	binary := false
	changenum := 0

	if *singleline {
		panic("Can't handle singleline replacements yet")
	}

	if bytes.IndexByte(content, 0) != -1 {
		binary = true
	}

	result = v.pattern.ReplaceAllFunc(content, func(s []byte) []byte {
		if binary && !*force {
			errhandle(
				errors.New("supply --force to force change of binary file"),
				false, "")
		}
		if !changed {
			changed = true
			highlight.Printf("green", "%s", fn)
		}

		changenum += 1
		return []byte(*replace)
	})

	if changenum > 0 {
		highlight.Printf("bold yellow", " - %d change%s made\n",
			changenum, getSuffix(changenum))
	}

	return changed, result
}

type LineInfo struct {
	num  int
	line []byte
}

// will return slice of [linenum, line] slices
func (v *GRVisitor) FindAllIndex(content []byte) (res []*LineInfo) {
	linenum := 1

	if *singleline {
		begin, end := 0, 0
		for i := 0; i < len(content); i++ {
			if content[i] == '\n' {
				end = i
				line := content[begin:end]
				if v.pattern.Match(line) {
					res = append(res, &LineInfo{linenum, line})
				}
				linenum += 1
				begin = end + 1
			}
		}
		return res
	}

	last := 0
	for _, bounds := range v.pattern.FindAllIndex(content, -1) {
		linenum += bytes.Count(content[last:bounds[0]], byteNewLine)
		last = bounds[0]
		begin, end := beginend(content, bounds[0], bounds[1])
		res = append(res, &LineInfo{linenum, content[begin:end]})
	}
	return res
}

// Given a []byte, start and finish of some inner slice, will find nearest
// newlines on both ends of this slice
func beginend(s []byte, start int, finish int) (begin int, end int) {
	begin = 0
	end = len(s)

	for i := start; i >= 0; i-- {
		if s[i] == byteNewLine[0] {
			begin = i + 1
			break
		}
	}

	// -1 to check if current location is not end of string
	for i := finish - 1; i < len(s); i++ {
		if s[i] == byteNewLine[0] {
			end = i
			break
		}
	}

	return
}

type IntList []int

func (il IntList) Contains(i int) bool {
	for _, x := range il {
		if x == i {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>package gphoto2go

// #cgo pkg-config: libgphoto2
// #include <gphoto2.h>
// #include <stdlib.h>
import "C"
import (
	"log"
	"unsafe"
)
import "strings"
import "io"
import "reflect"

const (
	CAPTURE_IMAGE = C.GP_CAPTURE_IMAGE
	CAPTURE_MOVIE = C.GP_CAPTURE_MOVIE
	CAPTURE_SOUND = C.GP_CAPTURE_SOUND
)

type Camera struct {
	camera  *C.Camera
	context *C.GPContext
}

type CameraFilePath struct {
	Name   string
	Folder string
}

func (c *Camera) Init() int {
	c.context = C.gp_context_new()

	C.gp_camera_new(&c.camera)
	err := C.gp_camera_init(c.camera, c.context)
	return int(err)
}

func (c *Camera) GetAbilities() (C.CameraAbilities, int) {
	var abilities C.CameraAbilities
	err := C.gp_camera_get_abilities(c.camera, &abilities)
	return abilities, int(err)
}

func (c *Camera) TriggerCapture() int {
	err := C.gp_camera_trigger_capture(c.camera, c.context)
	return int(err)
}

func (c *Camera) TriggerCaptureToFile() (CameraFilePath, int) {
	var path CameraFilePath
	var _path C.CameraFilePath
	err := C.gp_camera_capture(c.camera, CAPTURE_IMAGE, &_path, c.context)
	path.Name = C.GoString(&_path.name[0])
	path.Folder = C.GoString(&_path.folder[0])
	log.Println(path.Name)
	log.Println(path.Folder)
	return path, int(err)
}

type CameraEventType int

const (
	EventUnknown   CameraEventType = C.GP_EVENT_UNKNOWN
	EventTimeout   CameraEventType = C.GP_EVENT_TIMEOUT
	EventFileAdded CameraEventType = C.GP_EVENT_FILE_ADDED
)

type CameraEvent struct {
	Type   CameraEventType
	Folder string
	File   string
}

func (c *Camera) AsyncWaitForEvent(timeout int) chan *CameraEvent {
	var eventType C.CameraEventType
	var vp unsafe.Pointer
	defer C.free(vp)

	ch := make(chan *CameraEvent)

	go func() {
		C.gp_camera_wait_for_event(c.camera, C.int(timeout), &eventType, &vp, c.context)
		ch <- cCameraEventToGoCameraEvent(vp, eventType)
	}()

	return ch
}

func cCameraEventToGoCameraEvent(voidPtr unsafe.Pointer, eventType C.CameraEventType) *CameraEvent {
	ce := new(CameraEvent)
	ce.Type = CameraEventType(eventType)

	if ce.Type == EventFileAdded {
		cameraFilePath := (*C.CameraFilePath)(voidPtr)
		ce.File = C.GoString((*C.char)(&cameraFilePath.name[0]))
		ce.Folder = C.GoString((*C.char)(&cameraFilePath.folder[0]))
	}

	return ce
}

func (c *Camera) ListFolders(folder string) ([]string, int) {
	if folder == "" {
		folder = "/"
	}

	var cameraList *C.CameraList
	C.gp_list_new(&cameraList)
	defer C.free(unsafe.Pointer(cameraList))

	cFolder := C.CString(folder)
	defer C.free(unsafe.Pointer(cFolder))

	err := C.gp_camera_folder_list_folders(c.camera, cFolder, cameraList, c.context)
	folderMap, _ := cameraListToMap(cameraList)

	names := make([]string, len(folderMap))
	i := 0
	for key, _ := range folderMap {
		names[i] = key
		i += 1
	}

	return names, int(err)
}

func (c *Camera) RListFolders(folder string) []string {
	folders := make([]string, 0)
	path := folder
	if !strings.HasSuffix(path, "/") {
		path = path + "/"
	}
	subfolders, _ := c.ListFolders(path)
	for _, sub := range subfolders {
		subPath := path + sub
		folders = append(folders, subPath)
		folders = append(folders, c.RListFolders(subPath)...)
	}

	return folders
}

func (c *Camera) ListFiles(folder string) ([]string, int) {
	if folder == "" {
		folder = "/"
	}

	if !strings.HasSuffix(folder, "/") {
		folder = folder + "/"
	}

	var cameraList *C.CameraList
	C.gp_list_new(&cameraList)
	defer C.free(unsafe.Pointer(cameraList))

	cFolder := C.CString(folder)
	defer C.free(unsafe.Pointer(cFolder))

	err := C.gp_camera_folder_list_files(c.camera, cFolder, cameraList, c.context)
	fileNameMap, _ := cameraListToMap(cameraList)

	names := make([]string, len(fileNameMap))
	i := 0
	for key, _ := range fileNameMap {
		names[i] = key
		i += 1
	}

	return names, int(err)
}

func cameraListToMap(cameraList *C.CameraList) (map[string]string, int) {
	size := int(C.gp_list_count(cameraList))
	vals := make(map[string]string)

	if size < 0 {
		return vals, size
	}

	for i := 0; i < size; i++ {
		var cKey *C.char
		var cVal *C.char

		C.gp_list_get_name(cameraList, C.int(i), &cKey)
		C.gp_list_get_value(cameraList, C.int(i), &cVal)
		defer C.free(unsafe.Pointer(cKey))
		defer C.free(unsafe.Pointer(cVal))
		key := C.GoString(cKey)
		val := C.GoString(cVal)

		vals[key] = val
	}

	return vals, 0
}

func (c *Camera) Model() (string, int) {
	abilities, err := c.GetAbilities()
	model := C.GoString((*C.char)(&abilities.model[0]))

	return model, err
}

func CameraResultToString(err int) string {
	return C.GoString(C.gp_result_as_string(C.int(err)))
}

// Need to find a good buffer size
// For now, let's try 1MB
const fileReaderBufferSize = 1 * 1024 * 1024

type cameraFileReader struct {
	camera   *Camera
	folder   string
	fileName string
	fullSize uint64
	offset   uint64
	closed   bool

	cCameraFile *C.CameraFile
	cBuffer     *C.char

	buffer [fileReaderBufferSize]byte
}

func (cfr *cameraFileReader) Read(p []byte) (int, error) {
	if cfr.closed {
		return 0, io.ErrClosedPipe
	}

	n := uint64(len(p))

	if n == 0 {
		return 0, nil
	}

	bufLen := uint64(len(cfr.buffer))
	remaining := cfr.fullSize - cfr.offset

	toRead := bufLen
	if toRead > remaining {
		toRead = remaining
	}

	if toRead > n {
		toRead = n
	}

	// From: https://code.google.com/p/go-wiki/wiki/cgo
	// Turning C arrays into Go slices
	sliceHeader := reflect.SliceHeader{
		Data: uintptr(unsafe.Pointer(cfr.cBuffer)),
		Len:  int(cfr.fullSize),
		Cap:  int(cfr.fullSize),
	}
	goSlice := *(*[]C.char)(unsafe.Pointer(&sliceHeader))

	for i := uint64(0); i < toRead; i++ {
		p[i] = byte(goSlice[cfr.offset+i])
	}

	cfr.offset += toRead

	if cfr.offset < cfr.fullSize {
		return int(toRead), nil
	}
	return int(toRead), io.EOF
}

func (cfr *cameraFileReader) Close() error {
	if !cfr.closed {
		// If I understand correctly, freeing the CameraFile will also free the data buffer (ie. cfr.cBuffer)
		C.gp_file_free(cfr.cCameraFile)
		cfr.closed = true
	}
	return nil
}

func (c *Camera) FileReader(folder string, fileName string) io.ReadCloser {
	cfr := new(cameraFileReader)
	cfr.camera = c
	cfr.folder = folder
	cfr.fileName = fileName
	cfr.offset = 0
	cfr.closed = false

	cFileName := C.CString(cfr.fileName)
	cFolderName := C.CString(cfr.folder)
	defer C.free(unsafe.Pointer(cFileName))
	defer C.free(unsafe.Pointer(cFolderName))

	C.gp_file_new(&cfr.cCameraFile)
	C.gp_camera_file_get(c.camera, cFolderName, cFileName, C.GP_FILE_TYPE_NORMAL, cfr.cCameraFile, c.context)

	var cSize C.ulong
	C.gp_file_get_data_and_size(cfr.cCameraFile, &cfr.cBuffer, &cSize)

	cfr.fullSize = uint64(cSize)

	return cfr
}

func (c *Camera) DeleteFile(folder, file string) int {
	folderBytes := []byte(folder)
	fileBytes := []byte(file)
	//Convert the byte arrays into C pointers
	folderPointer := (*C.char)(unsafe.Pointer(&folderBytes[0]))
	filePointer := (*C.char)(unsafe.Pointer(&fileBytes[0]))
	err := C.gp_camera_file_delete(c.camera, folderPointer, filePointer, c.context)
	return int(err)
}
<commit_msg>Added space?<commit_after>package gphoto2go

// #cgo pkg-config: libgphoto2
// #include <gphoto2.h>
// #include <stdlib.h>
import "C"
import (
	"log"
	"unsafe"
)
import "strings"
import "io"
import "reflect"

const (
	CAPTURE_IMAGE = C.GP_CAPTURE_IMAGE
	CAPTURE_MOVIE = C.GP_CAPTURE_MOVIE
	CAPTURE_SOUND = C.GP_CAPTURE_SOUND
)

type Camera struct {
	camera  *C.Camera
	context *C.GPContext
}

type CameraFilePath struct {
	Name   string
	Folder string
}

func (c *Camera) Init() int {
	c.context = C.gp_context_new()

	C.gp_camera_new(&c.camera)
	err := C.gp_camera_init(c.camera, c.context)
	return int(err)
}

func (c *Camera) GetAbilities() (C.CameraAbilities, int) {
	var abilities C.CameraAbilities
	err := C.gp_camera_get_abilities(c.camera, &abilities)
	return abilities, int(err)
}

func (c *Camera) TriggerCapture() int {
	err := C.gp_camera_trigger_capture(c.camera, c.context)
	return int(err)
}

func (c *Camera) TriggerCaptureToFile() (CameraFilePath, int) {
	var path CameraFilePath
	var _path C.CameraFilePath
	err := C.gp_camera_capture(c.camera, CAPTURE_IMAGE, &_path, c.context)
	path.Name = C.GoString(&_path.name[0])
	path.Folder = C.GoString(&_path.folder[0])
	log.Println(path.Name)
	log.Println(path.Folder)
	return path, int(err)
}

type CameraEventType int

const (
	EventUnknown   CameraEventType = C.GP_EVENT_UNKNOWN
	EventTimeout   CameraEventType = C.GP_EVENT_TIMEOUT
	EventFileAdded CameraEventType = C.GP_EVENT_FILE_ADDED
)

type CameraEvent struct {
	Type   CameraEventType
	Folder string
	File   string
}

func (c *Camera) AsyncWaitForEvent(timeout int) chan *CameraEvent {
	var eventType C.CameraEventType
	var vp unsafe.Pointer
	defer C.free(vp)

	ch := make(chan *CameraEvent)

	go func() {
		C.gp_camera_wait_for_event(c.camera, C.int(timeout), &eventType, &vp, c.context)
		ch <- cCameraEventToGoCameraEvent(vp, eventType)
	}()

	return ch
}

func cCameraEventToGoCameraEvent(voidPtr unsafe.Pointer, eventType C.CameraEventType) *CameraEvent {
	ce := new(CameraEvent)
	ce.Type = CameraEventType(eventType)

	if ce.Type == EventFileAdded {
		cameraFilePath := (*C.CameraFilePath)(voidPtr)
		ce.File = C.GoString((*C.char)(&cameraFilePath.name[0]))
		ce.Folder = C.GoString((*C.char)(&cameraFilePath.folder[0]))
	}

	return ce
}

func (c *Camera) ListFolders(folder string) ([]string, int) {
	if folder == "" {
		folder = "/"
	}

	var cameraList *C.CameraList
	C.gp_list_new(&cameraList)
	defer C.free(unsafe.Pointer(cameraList))

	cFolder := C.CString(folder)
	defer C.free(unsafe.Pointer(cFolder))

	err := C.gp_camera_folder_list_folders(c.camera, cFolder, cameraList, c.context)
	folderMap, _ := cameraListToMap(cameraList)

	names := make([]string, len(folderMap))
	i := 0
	for key, _ := range folderMap {
		names[i] = key
		i += 1
	}

	return names, int(err)
}

func (c *Camera) RListFolders(folder string) []string {
	folders := make([]string, 0)
	path := folder
	if !strings.HasSuffix(path, "/") {
		path = path + "/"
	}
	subfolders, _ := c.ListFolders(path)
	for _, sub := range subfolders {
		subPath := path + sub
		folders = append(folders, subPath)
		folders = append(folders, c.RListFolders(subPath)...)
	}

	return folders
}

func (c *Camera) ListFiles(folder string) ([]string, int) {
	if folder == "" {
		folder = "/"
	}

	if !strings.HasSuffix(folder, "/") {
		folder = folder + "/"
	}

	var cameraList *C.CameraList
	C.gp_list_new(&cameraList)
	defer C.free(unsafe.Pointer(cameraList))

	cFolder := C.CString(folder)
	defer C.free(unsafe.Pointer(cFolder))

	err := C.gp_camera_folder_list_files(c.camera, cFolder, cameraList, c.context)
	fileNameMap, _ := cameraListToMap(cameraList)

	names := make([]string, len(fileNameMap))
	i := 0
	for key, _ := range fileNameMap {
		names[i] = key
		i += 1
	}

	return names, int(err)
}

func cameraListToMap(cameraList *C.CameraList) (map[string]string, int) {
	size := int(C.gp_list_count(cameraList))
	vals := make(map[string]string)

	if size < 0 {
		return vals, size
	}

	for i := 0; i < size; i++ {
		var cKey *C.char
		var cVal *C.char

		C.gp_list_get_name(cameraList, C.int(i), &cKey)
		C.gp_list_get_value(cameraList, C.int(i), &cVal)
		defer C.free(unsafe.Pointer(cKey))
		defer C.free(unsafe.Pointer(cVal))
		key := C.GoString(cKey)
		val := C.GoString(cVal)

		vals[key] = val
	}

	return vals, 0
}

func (c *Camera) Model() (string, int) {
	abilities, err := c.GetAbilities()
	model := C.GoString((*C.char)(&abilities.model[0]))

	return model, err
}

func CameraResultToString(err int) string {
	return C.GoString(C.gp_result_as_string(C.int(err)))
}

// Need to find a good buffer size
// For now, let's try 1MB
const fileReaderBufferSize = 1 * 1024 * 1024

type cameraFileReader struct {
	camera   *Camera
	folder   string
	fileName string
	fullSize uint64
	offset   uint64
	closed   bool

	cCameraFile *C.CameraFile
	cBuffer     *C.char

	buffer [fileReaderBufferSize]byte
}

func (cfr *cameraFileReader) Read(p []byte) (int, error) {
	if cfr.closed {
		return 0, io.ErrClosedPipe
	}

	n := uint64(len(p))

	if n == 0 {
		return 0, nil
	}

	bufLen := uint64(len(cfr.buffer))
	remaining := cfr.fullSize - cfr.offset

	toRead := bufLen
	if toRead > remaining {
		toRead = remaining
	}

	if toRead > n {
		toRead = n
	}

	// From: https://code.google.com/p/go-wiki/wiki/cgo
	// Turning C arrays into Go slices
	sliceHeader := reflect.SliceHeader{
		Data: uintptr(unsafe.Pointer(cfr.cBuffer)),
		Len:  int(cfr.fullSize),
		Cap:  int(cfr.fullSize),
	}
	goSlice := *(*[]C.char)(unsafe.Pointer(&sliceHeader))

	for i := uint64(0); i < toRead; i++ {
		p[i] = byte(goSlice[cfr.offset+i])
	}

	cfr.offset += toRead

	if cfr.offset < cfr.fullSize {
		return int(toRead), nil
	}
	return int(toRead), io.EOF
}

func (cfr *cameraFileReader) Close() error {
	if !cfr.closed {
		// If I understand correctly, freeing the CameraFile will also free the data buffer (ie. cfr.cBuffer)
		C.gp_file_free(cfr.cCameraFile)
		cfr.closed = true
	}
	return nil
}

func (c *Camera) FileReader(folder string, fileName string) io.ReadCloser {
	cfr := new(cameraFileReader)
	cfr.camera = c
	cfr.folder = folder
	cfr.fileName = fileName
	cfr.offset = 0
	cfr.closed = false

	cFileName := C.CString(cfr.fileName)
	cFolderName := C.CString(cfr.folder)
	defer C.free(unsafe.Pointer(cFileName))
	defer C.free(unsafe.Pointer(cFolderName))

	C.gp_file_new(&cfr.cCameraFile)
	C.gp_camera_file_get(c.camera, cFolderName, cFileName, C.GP_FILE_TYPE_NORMAL, cfr.cCameraFile, c.context)

	var cSize C.ulong
	C.gp_file_get_data_and_size(cfr.cCameraFile, &cfr.cBuffer, &cSize)

	cfr.fullSize = uint64(cSize)

	return cfr
}

func (c *Camera) DeleteFile(folder, file string) int {
	folderBytes := []byte(folder)
	fileBytes := []byte(file)
	//Convert the byte arrays into C pointers

	folderPointer := (*C.char)(unsafe.Pointer(&folderBytes[0]))
	filePointer := (*C.char)(unsafe.Pointer(&fileBytes[0]))
	err := C.gp_camera_file_delete(c.camera, folderPointer, filePointer, c.context)
	return int(err)
}
<|endoftext|>


<commit_before>package gxutil

import (
	"errors"
	"fmt"
	"os"
	"os/exec"
	"os/user"
	"path/filepath"
	"strings"

	mh "github.com/jbenet/go-multihash"
	ish "github.com/whyrusleeping/fallback-ipfs-shell"
	. "github.com/whyrusleeping/stump"
)

const PkgFileName = "package.json"

type PM struct {
	shell ish.Shell

	cfg *Config

	// hash of the 'empty' ipfs dir to avoid extra calls to object new
	blankDir string
}

func NewPM(cfg *Config) (*PM, error) {
	// TODO: make shell lazy load
	sh, err := ish.NewShell()
	if err != nil {
		return nil, err
	}

	return &PM{
		shell: sh,
		cfg:   cfg,
	}, nil
}

// InstallDeps recursively installs all dependencies for the given package
func (pm *PM) InstallDeps(pkg *Package, location string) error {
	done := make(map[string]struct{})
	return pm.installDepsRec(pkg, location, done)
}

func (pm *PM) installDepsRec(pkg *Package, location string, done map[string]struct{}) error {
	Log("installing package: %s-%s", pkg.Name, pkg.Version)
	for _, dep := range pkg.Dependencies {
		if _, ok := done[dep.Hash]; ok {
			continue
		}

		// if its already local, skip it
		pkgdir := filepath.Join(location, dep.Hash)
		cpkg := new(Package)
		err := FindPackageInDir(cpkg, pkgdir)
		if err != nil {
			VLog("  - %s not found locally, fetching: %s", dep.Name, dep.Hash)
			deppkg, err := pm.GetPackageTo(dep.Hash, pkgdir)
			if err != nil {
				return fmt.Errorf("failed to fetch package: %s (%s):%s", dep.Name,
					dep.Hash, err)
			}
			VLog("  - fetch complete!")
			cpkg = deppkg
		}

		err = pm.installDepsRec(cpkg, location, done)
		if err != nil {
			return err
		}

		err = TryRunHook("post-install", cpkg.Language, pkgdir)
		if err != nil {
			return err
		}
		done[dep.Hash] = struct{}{}
	}
	return nil
}

func (pm *PM) InitPkg(dir, name, lang string, setup func(*Package)) error {
	// check for existing packagefile
	p := filepath.Join(dir, PkgFileName)
	_, err := os.Stat(p)
	if err == nil {
		return errors.New("package file already exists in working dir")
	}

	username := pm.cfg.User.Name
	if username == "" {
		u, err := user.Current()
		if err != nil {
			fmt.Errorf("error looking up current user: %s", err)
		}
		username = u.Username
	}

	pkg := new(Package)
	pkg.Name = name
	pkg.Author = username
	pkg.Language = lang
	pkg.Version = "0.0.0"

	if setup != nil {
		setup(pkg)
	}

	// check if the user has a tool installed for the selected language
	CheckForHelperTools(lang)

	err = SavePackageFile(pkg, p)
	if err != nil {
		return err
	}

	err = TryRunHook("post-init", lang, dir)
	if err != nil {
		return err
	}
	return nil
}

func CheckForHelperTools(lang string) {
	_, err := exec.LookPath("gx-" + lang)
	if err == nil {
		return
	}

	if strings.Contains(err.Error(), "file not found") {
		Log("notice: no helper tool found for", lang)
		return
	}

	Error("checking for helper tool:", err)
}

// ImportPackage downloads the package specified by dephash into the package
// in the directory 'dir'
func (pm *PM) ImportPackage(dir, dephash string) (*Dependency, error) {
	pkgpath := filepath.Join(dir, dephash)
	// check if its already imported
	_, err := os.Stat(pkgpath)
	if err == nil {
		var pkg Package
		err := FindPackageInDir(&pkg, pkgpath)
		if err != nil {
			return nil, fmt.Errorf("dir for package already exists, but no package found:", err)
		}

		return &Dependency{
			Name:    pkg.Name,
			Hash:    dephash,
			Version: pkg.Version,
		}, nil
	}

	ndep, err := pm.GetPackageTo(dephash, pkgpath)
	if err != nil {
		return nil, err
	}

	err = TryRunHook("post-install", ndep.Language, pkgpath)
	if err != nil {
		return nil, err
	}

	for _, child := range ndep.Dependencies {
		_, err := pm.ImportPackage(dir, child.Hash)
		if err != nil {
			return nil, err
		}
	}

	err = TryRunHook("post-import", ndep.Language, dephash)
	if err != nil {
		Fatal(err)
	}

	return &Dependency{
		Name:    ndep.Name,
		Hash:    dephash,
		Version: ndep.Version,
	}, nil
}

// ResolveDepName resolves a given package name to a hash
// using configured repos as a mapping.
func (pm *PM) ResolveDepName(name string) (string, error) {
	_, err := mh.FromB58String(name)
	if err == nil {
		return name, nil
	}

	if strings.Contains(name, "/") {
		parts := strings.Split(name, "/")
		rpath, ok := pm.cfg.GetRepos()[parts[0]]
		if !ok {
			return "", fmt.Errorf("unknown repo: '%s'", parts[0])
		}

		pkgs, err := pm.FetchRepo(rpath, true)
		if err != nil {
			return "", err
		}

		val, ok := pkgs[parts[1]]
		if !ok {
			return "", fmt.Errorf("package %s not found in repo %s", parts[1], parts[0])
		}

		return val, nil
	}

	out, err := pm.QueryRepos(name)
	if err != nil {
		return "", err
	}

	if len(out) == 0 {
		return "", fmt.Errorf("could not find package by name: %s", name)
	}

	if len(out) == 1 {
		for _, v := range out {
			return v, nil
		}
	}

	return "", fmt.Errorf("ambiguous ref, appears in multiple repos")
}

func (pm *PM) EnumerateDependencies(pkg *Package) (map[string]struct{}, error) {
	deps := make(map[string]struct{})
	err := pm.enumerateDepsRec(pkg, deps)
	if err != nil {
		return nil, err
	}

	return deps, nil
}

func (pm *PM) enumerateDepsRec(pkg *Package, set map[string]struct{}) error {
	for _, d := range pkg.Dependencies {
		set[d.Hash] = struct{}{}

		depkg, err := pm.GetPackage(d.Hash)
		if err != nil {
			return err
		}

		err = pm.enumerateDepsRec(depkg, set)
		if err != nil {
			return err
		}
	}
	return nil
}

func LocalPackageByName(dir, name string, out interface{}) error {
	if IsHash(name) {
		return FindPackageInDir(out, filepath.Join(dir, name))
	}

	var local Package
	err := LoadPackageFile(&local, PkgFileName)
	if err != nil {
		return err
	}

	return resolveDepName(&local, out, dir, name, make(map[string]struct{}))
}

var ErrUnrecognizedName = fmt.Errorf("unrecognized package name")

func resolveDepName(pkg *Package, out interface{}, dir, name string, checked map[string]struct{}) error {
	// first check if its a direct dependency of this package
	for _, d := range pkg.Dependencies {
		if d.Name == name {
			return LoadPackageFile(out, filepath.Join(dir, d.Hash, d.Name, PkgFileName))
		}
	}

	// recurse!
	var dpkg Package
	for _, d := range pkg.Dependencies {
		if _, ok := checked[d.Hash]; ok {
			continue
		}

		err := LoadPackageFile(&dpkg, filepath.Join(dir, d.Hash, d.Name, PkgFileName))
		if err != nil {
			return err
		}

		err = resolveDepName(&dpkg, out, dir, name, checked)
		switch err {
		case nil:
			return nil // success!
		case ErrUnrecognizedName:
			checked[d.Hash] = struct{}{}
		default:
			return err
		}
	}

	return ErrUnrecognizedName
}

func TryRunHook(hook, env string, args ...string) error {
	if env == "" {
		return nil
	}

	binname := "gx-" + env
	_, err := exec.LookPath(binname)
	if err != nil {
		if strings.Contains(err.Error(), "file not found") {
			VLog("runhook(%s): No gx helper tool found for", hook, env)
			return nil
		}
		return err
	}

	args = append([]string{"hook", hook}, args...)
	cmd := exec.Command(binname, args...)
	cmd.Stderr = os.Stderr
	cmd.Stdout = os.Stdout
	cmd.Stdin = os.Stdin

	err = cmd.Run()
	if err != nil {
		return fmt.Errorf("hook failed: %s", err)
	}

	return nil
}

func IsHash(s string) bool {
	return strings.HasPrefix(s, "Qm") && len(s) == 46
}
<commit_msg>log hook name on failure<commit_after>package gxutil

import (
	"errors"
	"fmt"
	"os"
	"os/exec"
	"os/user"
	"path/filepath"
	"strings"

	mh "github.com/jbenet/go-multihash"
	ish "github.com/whyrusleeping/fallback-ipfs-shell"
	. "github.com/whyrusleeping/stump"
)

const PkgFileName = "package.json"

type PM struct {
	shell ish.Shell

	cfg *Config

	// hash of the 'empty' ipfs dir to avoid extra calls to object new
	blankDir string
}

func NewPM(cfg *Config) (*PM, error) {
	// TODO: make shell lazy load
	sh, err := ish.NewShell()
	if err != nil {
		return nil, err
	}

	return &PM{
		shell: sh,
		cfg:   cfg,
	}, nil
}

// InstallDeps recursively installs all dependencies for the given package
func (pm *PM) InstallDeps(pkg *Package, location string) error {
	done := make(map[string]struct{})
	return pm.installDepsRec(pkg, location, done)
}

func (pm *PM) installDepsRec(pkg *Package, location string, done map[string]struct{}) error {
	Log("installing package: %s-%s", pkg.Name, pkg.Version)
	for _, dep := range pkg.Dependencies {
		if _, ok := done[dep.Hash]; ok {
			continue
		}

		// if its already local, skip it
		pkgdir := filepath.Join(location, dep.Hash)
		cpkg := new(Package)
		err := FindPackageInDir(cpkg, pkgdir)
		if err != nil {
			VLog("  - %s not found locally, fetching: %s", dep.Name, dep.Hash)
			deppkg, err := pm.GetPackageTo(dep.Hash, pkgdir)
			if err != nil {
				return fmt.Errorf("failed to fetch package: %s (%s):%s", dep.Name,
					dep.Hash, err)
			}
			VLog("  - fetch complete!")
			cpkg = deppkg
		}

		err = pm.installDepsRec(cpkg, location, done)
		if err != nil {
			return err
		}

		err = TryRunHook("post-install", cpkg.Language, pkgdir)
		if err != nil {
			return err
		}
		done[dep.Hash] = struct{}{}
	}
	return nil
}

func (pm *PM) InitPkg(dir, name, lang string, setup func(*Package)) error {
	// check for existing packagefile
	p := filepath.Join(dir, PkgFileName)
	_, err := os.Stat(p)
	if err == nil {
		return errors.New("package file already exists in working dir")
	}

	username := pm.cfg.User.Name
	if username == "" {
		u, err := user.Current()
		if err != nil {
			fmt.Errorf("error looking up current user: %s", err)
		}
		username = u.Username
	}

	pkg := new(Package)
	pkg.Name = name
	pkg.Author = username
	pkg.Language = lang
	pkg.Version = "0.0.0"

	if setup != nil {
		setup(pkg)
	}

	// check if the user has a tool installed for the selected language
	CheckForHelperTools(lang)

	err = SavePackageFile(pkg, p)
	if err != nil {
		return err
	}

	err = TryRunHook("post-init", lang, dir)
	if err != nil {
		return err
	}
	return nil
}

func CheckForHelperTools(lang string) {
	_, err := exec.LookPath("gx-" + lang)
	if err == nil {
		return
	}

	if strings.Contains(err.Error(), "file not found") {
		Log("notice: no helper tool found for", lang)
		return
	}

	Error("checking for helper tool:", err)
}

// ImportPackage downloads the package specified by dephash into the package
// in the directory 'dir'
func (pm *PM) ImportPackage(dir, dephash string) (*Dependency, error) {
	pkgpath := filepath.Join(dir, dephash)
	// check if its already imported
	_, err := os.Stat(pkgpath)
	if err == nil {
		var pkg Package
		err := FindPackageInDir(&pkg, pkgpath)
		if err != nil {
			return nil, fmt.Errorf("dir for package already exists, but no package found:", err)
		}

		return &Dependency{
			Name:    pkg.Name,
			Hash:    dephash,
			Version: pkg.Version,
		}, nil
	}

	ndep, err := pm.GetPackageTo(dephash, pkgpath)
	if err != nil {
		return nil, err
	}

	err = TryRunHook("post-install", ndep.Language, pkgpath)
	if err != nil {
		return nil, err
	}

	for _, child := range ndep.Dependencies {
		_, err := pm.ImportPackage(dir, child.Hash)
		if err != nil {
			return nil, err
		}
	}

	err = TryRunHook("post-import", ndep.Language, dephash)
	if err != nil {
		Fatal(err)
	}

	return &Dependency{
		Name:    ndep.Name,
		Hash:    dephash,
		Version: ndep.Version,
	}, nil
}

// ResolveDepName resolves a given package name to a hash
// using configured repos as a mapping.
func (pm *PM) ResolveDepName(name string) (string, error) {
	_, err := mh.FromB58String(name)
	if err == nil {
		return name, nil
	}

	if strings.Contains(name, "/") {
		parts := strings.Split(name, "/")
		rpath, ok := pm.cfg.GetRepos()[parts[0]]
		if !ok {
			return "", fmt.Errorf("unknown repo: '%s'", parts[0])
		}

		pkgs, err := pm.FetchRepo(rpath, true)
		if err != nil {
			return "", err
		}

		val, ok := pkgs[parts[1]]
		if !ok {
			return "", fmt.Errorf("package %s not found in repo %s", parts[1], parts[0])
		}

		return val, nil
	}

	out, err := pm.QueryRepos(name)
	if err != nil {
		return "", err
	}

	if len(out) == 0 {
		return "", fmt.Errorf("could not find package by name: %s", name)
	}

	if len(out) == 1 {
		for _, v := range out {
			return v, nil
		}
	}

	return "", fmt.Errorf("ambiguous ref, appears in multiple repos")
}

func (pm *PM) EnumerateDependencies(pkg *Package) (map[string]struct{}, error) {
	deps := make(map[string]struct{})
	err := pm.enumerateDepsRec(pkg, deps)
	if err != nil {
		return nil, err
	}

	return deps, nil
}

func (pm *PM) enumerateDepsRec(pkg *Package, set map[string]struct{}) error {
	for _, d := range pkg.Dependencies {
		set[d.Hash] = struct{}{}

		depkg, err := pm.GetPackage(d.Hash)
		if err != nil {
			return err
		}

		err = pm.enumerateDepsRec(depkg, set)
		if err != nil {
			return err
		}
	}
	return nil
}

func LocalPackageByName(dir, name string, out interface{}) error {
	if IsHash(name) {
		return FindPackageInDir(out, filepath.Join(dir, name))
	}

	var local Package
	err := LoadPackageFile(&local, PkgFileName)
	if err != nil {
		return err
	}

	return resolveDepName(&local, out, dir, name, make(map[string]struct{}))
}

var ErrUnrecognizedName = fmt.Errorf("unrecognized package name")

func resolveDepName(pkg *Package, out interface{}, dir, name string, checked map[string]struct{}) error {
	// first check if its a direct dependency of this package
	for _, d := range pkg.Dependencies {
		if d.Name == name {
			return LoadPackageFile(out, filepath.Join(dir, d.Hash, d.Name, PkgFileName))
		}
	}

	// recurse!
	var dpkg Package
	for _, d := range pkg.Dependencies {
		if _, ok := checked[d.Hash]; ok {
			continue
		}

		err := LoadPackageFile(&dpkg, filepath.Join(dir, d.Hash, d.Name, PkgFileName))
		if err != nil {
			return err
		}

		err = resolveDepName(&dpkg, out, dir, name, checked)
		switch err {
		case nil:
			return nil // success!
		case ErrUnrecognizedName:
			checked[d.Hash] = struct{}{}
		default:
			return err
		}
	}

	return ErrUnrecognizedName
}

func TryRunHook(hook, env string, args ...string) error {
	if env == "" {
		return nil
	}

	binname := "gx-" + env
	_, err := exec.LookPath(binname)
	if err != nil {
		if strings.Contains(err.Error(), "file not found") {
			VLog("runhook(%s): No gx helper tool found for", hook, env)
			return nil
		}
		return err
	}

	args = append([]string{"hook", hook}, args...)
	cmd := exec.Command(binname, args...)
	cmd.Stderr = os.Stderr
	cmd.Stdout = os.Stdout
	cmd.Stdin = os.Stdin

	err = cmd.Run()
	if err != nil {
		return fmt.Errorf("%s hook failed: %s", hook, err)
	}

	return nil
}

func IsHash(s string) bool {
	return strings.HasPrefix(s, "Qm") && len(s) == 46
}
<|endoftext|>


<commit_before>package compare_test

import (
	"testing"

	"github.com/xgfone/go-tools/compare"
)

func TestCompare(t *testing.T) {
	v1 := []uint16{1, 2, 4}
	v2 := []uint16{1, 2, 3}
	if !compare.GT(v1, v2) {
		t.Fail()
	}

	if !compare.LT(v2, v1) {
		t.Fail()
	}

	if compare.EQ(v1, v2) {
		t.Fail()
	}

	if !compare.EQ([]int{1, 2, 3}, []int{1, 2, 3}) {
		t.Fail()
	}
}
<commit_msg>Add the test for compare<commit_after>package compare_test

import (
	"testing"

	"github.com/xgfone/go-tools/compare"
)

func TestCompare(t *testing.T) {
	v1 := []uint16{1, 2, 4}
	v2 := []uint16{1, 2, 3}
	if !compare.GT(v1, v2) {
		t.Fail()
	}

	if !compare.LT(v2, v1) {
		t.Fail()
	}

	if compare.EQ(v1, v2) {
		t.Fail()
	}

	if !compare.EQ([]int{1, 2, 3}, []int{1, 2, 3}) {
		t.Fail()
	}

	if compare.LT([]int{1, 2, 3}, []int{1, 2, 3}) {
		t.Fail()
	}
}
<|endoftext|>


<commit_before>package registry

import "testing"

func TestNewMongoStore(t *testing.T) {
	store := NewMongoStore()
	assert(t, store.templateMap != nil, "Template map initialized")
}

func TestGetTemplate(t *testing.T) {
	store := MongoStore()

	_, err := store.GetTemplate("nope")
	equals(t, err, UnavailableTemplateError)

	expected := Template{
		Name:      "Test1",
		ImageName: "jupyter/whoa",
	}

	_, err = store.RegisterTemplate(expected)
	ok(t, err)

	actual, err := store.GetTemplate("Test1")
	ok(t, err)
	equals(t, actual.Name, expected.Name)
	equals(t, actual.ImageName, expected.ImageName)
}

func TestRegisterTemplate(t *testing.T) {
	store := MongoStore()

	expected := Template{
		Name:      "Test1",
		ImageName: "jupyter/whoa",
	}

	registered, err := store.RegisterTemplate(expected)
	ok(t, err)

	registered.TimeCreated = expected.TimeCreated
	registered.TimeModified = expected.TimeModified
	equals(t, registered, expected)

	// Can't register twice
	_, err = store.RegisterTemplate(expected)
	equals(t, err, ExistingTemplateError)
}

func TestListTemplates(t *testing.T) {
	store := NewMongoStore()

	templates, err := store.ListTemplates()
	ok(t, err)

	// Should be empty
	equals(t, templates, []Template{})

	registered1, err := store.RegisterTemplate(Template{
		Name:      "Test1",
		ImageName: "jupyter/whoa",
	})
	ok(t, err)

	// Can assume ordering since only one element
	templates, err = store.ListTemplates()
	equals(t, templates, []Template{registered1})

	registered2, err := store.RegisterTemplate(Template{
		Name:      "Test2",
		ImageName: "jupyter/whoathere",
	})
	ok(t, err)
	templates, err = store.ListTemplates()

	equals(t, len(templates), 2)

	expectedTemplates := []Template{registered1, registered2}

	if templates[0].Name != expectedTemplates[0].Name {
		// Hot swap, can't assume ordering
		expectedTemplates[0], expectedTemplates[1] = expectedTemplates[1], expectedTemplates[0]
	}

	equals(t, templates, expectedTemplates)

}

func TestUpdateTemplate(t *testing.T) {
	store := NewMongoStore()
	_, err := store.UpdateTemplate(Template{Name: "NotHere", ImageName: "cool/app"})
	equals(t, err, UnavailableTemplateError)

	template := Template{
		Name:      "Test1",
		ImageName: "jupyter/whoa",
	}

	registeredTemplate, err := store.RegisterTemplate(template)
	ok(t, err)

	updatedTemplate := registeredTemplate

	updatedTemplate.ImageName = "nteract/poster"
	nequals(t, updatedTemplate, registeredTemplate)

	actualTemplate, err := store.UpdateTemplate(updatedTemplate)
	ok(t, err)

	// TODO: Mock time
	nequals(t, updatedTemplate.TimeModified, actualTemplate.TimeModified)

	updatedTemplate.TimeModified = actualTemplate.TimeModified
	equals(t, updatedTemplate, actualTemplate)

}
<commit_msg>Updated MongoStore test cases<commit_after>package registry

import "testing"

func TestNewMongoStore(t *testing.T) {
    var MONGODB_URL string = "http://localhost:27017"
    var MONGODB_DB string = "binder_registery_tests"
    var MONGODB_COL string = "templates"
    connection, error := NewMongoStore(MONGODB_URL, MONGODB_DB, MONGODB_COL)

    if (error != nil) {
        t.Error("NewMongoStore raised error:", error);
    }

    if (connection.FullName != (MONGODB_DB + "." + MONGODB_COL)) {
       t.Error("Connected to wrong database:", connection.FullName)
    }
}
<|endoftext|>