<commit_before>package main

import (
	"context"
	"flag"
	"github.com/aws/aws-lambda-go/lambda"
	"github.com/whosonfirst/go-whosonfirst-aws/s3"
	"github.com/whosonfirst/go-whosonfirst-cli/flags"
	"github.com/whosonfirst/go-whosonfirst-uri"
	"log"
	"os"
	"strconv"
)

type DeleteOptions struct {
	DSN string `json:"dsn"`
	ID  int64  `json:"id"`
}

func delete(ctx context.Context, opts DeleteOptions) error {

	cfg, err := s3.NewS3ConfigFromString(opts.DSN)

	if err != nil {
		return err
	}

	conn, err := s3.NewS3Connection(cfg)

	if err != nil {
		return err
	}

	// add hooks for alternative paths (fullname, etc.)

	path, err := uri.Id2Path(opts.ID)

	if err != nil {
		return err
	}

	log.Println("DELETE", path)
	return nil
	return conn.DeleteRecursive(path)
}

func main() {

	do_lambda := flag.Bool("lambda", false, "...")
	do_invoke := flag.Bool("invoke", false, "...")

	dsn := flag.String("dsn", "", "...")

	flag.Parse()

	flags.SetFlagsFromEnvVars("WOF_DELETE")

	opts := DeleteOptions{
		DSN: *dsn,
	}

	if *do_lambda {
		lambda.Start(delete)
		os.Exit(0)
	}

	if *do_invoke {

		log.Fatal("please write me")

	} else {

		ctx, cancel := context.WithCancel(context.Background())
		defer cancel()

		for _, str_id := range flag.Args() {

			id, err := strconv.ParseInt(str_id, 10, 64)

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

			opts.ID = id
			err = delete(ctx, opts)

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

		os.Exit(0)
	}
}
<commit_msg>add a dryrun flag<commit_after>package main

import (
	"context"
	"errors"
	"flag"
	"github.com/aws/aws-lambda-go/lambda"
	"github.com/whosonfirst/go-whosonfirst-aws/s3"
	"github.com/whosonfirst/go-whosonfirst-uri"
	"log"
	"os"
	"strconv"
)

type DeleteOptions struct {
	DSN    string `json:"dsn"`
	Dryrun bool   `json:"dryrun"`
	ID     int64  `json:"id"`
}

func delete(ctx context.Context, opts DeleteOptions) error {

	if opts.DSN == "" {

		dsn, ok := os.LookupEnv("DSN")

		if !ok {
			return errors.New("Missing DSN")
		}

		opts.DSN = dsn
	}

	if opts.ID == 0 {
		return errors.New("Invalid ID")
	}

	cfg, err := s3.NewS3ConfigFromString(opts.DSN)

	if err != nil {
		return err
	}

	conn, err := s3.NewS3Connection(cfg)

	if err != nil {
		return err
	}

	// add hooks for alternative paths (fullname, etc.)

	path, err := uri.Id2Path(opts.ID)

	if err != nil {
		return err
	}

	if opts.Dryrun {
		log.Println("DELETE", path)
		return nil
	}

	return conn.DeleteRecursive(path)
}

func main() {

	do_invoke := flag.Bool("invoke", false, "...")
	dryrun := flag.Bool("dryrun", false, "...")

	dsn := flag.String("dsn", "", "...")

	flag.Parse()

	opts := DeleteOptions{
		DSN:    *dsn,
		Dryrun: *dryrun,
	}

	_, do_lambda := os.LookupEnv("LAMBDA")

	if do_lambda {
		lambda.Start(delete)
		os.Exit(0)
	}

	if *do_invoke {

		log.Fatal("please write me")

	} else {

		ctx, cancel := context.WithCancel(context.Background())
		defer cancel()

		for _, str_id := range flag.Args() {

			id, err := strconv.ParseInt(str_id, 10, 64)

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

			opts.ID = id
			err = delete(ctx, opts)

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

		os.Exit(0)
	}
}
<|endoftext|>


<commit_before>package archive

import (
	"archive/zip"
	"io"
	"log"
	"net/http"
	"strconv"

	"../utility/array"
)

var zipConf = install(&archConfig{
	name:         "zip",
	exts:         []string{"zip"},
	infoCallback: zipInfoCallback,
	dataCallback: zipDataCallback,
})

func zipInfoCallback(w http.ResponseWriter, path string) {
	r, err := zip.OpenReader(path)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	defer r.Close()

	paths := make([]string, len(r.File))
	for i, f := range r.File {
		paths[i] = f.Name
	}

	json := array.ToJson(paths)
	buff := []byte(json)

	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Content-Length", strconv.Itoa(len(buff)))
	if _, err := w.Write(buff); err != nil {
		log.Printf("ERR: zipInfoCallback: %v [%s]\n", err, path)
	}
}

func zipDataCallback(w http.ResponseWriter, path, page string) {
	r, err := zip.OpenReader(path)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	defer r.Close()

	paths := make([]string, len(r.File))
	for i, f := range r.File {
		paths[i] = f.Name
	}

	index := array.Search(paths, page)
	if index < 0 {
		http.Error(w, "Image file Not Found", http.StatusNotFound)
		return
	}

	size := r.File[index].FileInfo().Size()
	body, err := r.File[index].Open()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	defer body.Close()

	w.Header().Set("Content-Type", "image/jpeg")
	w.Header().Set("Content-Length", strconv.FormatInt(size, 10))
	if _, err := io.Copy(w, body); err != nil {
		log.Printf("ERR: zipDataCallback: %v [%s][%s]\n", err, path, page)
	}
}
<commit_msg>change image outputer<commit_after>package archive

import (
	"archive/zip"
	"log"
	"net/http"
	"strconv"

	"../image"
	"../utility/array"
)

var zipConf = install(&archConfig{
	name:         "zip",
	exts:         []string{"zip"},
	infoCallback: zipInfoCallback,
	dataCallback: zipDataCallback,
})

func zipInfoCallback(w http.ResponseWriter, path string) {
	r, err := zip.OpenReader(path)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	defer r.Close()

	paths := make([]string, len(r.File))
	for i, f := range r.File {
		paths[i] = f.Name
	}

	json := array.ToJson(paths)
	buff := []byte(json)

	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Content-Length", strconv.Itoa(len(buff)))
	if _, err := w.Write(buff); err != nil {
		log.Printf("ERR: zipInfoCallback: %v [%s]\n", err, path)
	}
}

func zipDataCallback(w http.ResponseWriter, path, page string) {
	r, err := zip.OpenReader(path)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	defer r.Close()

	paths := make([]string, len(r.File))
	for i, f := range r.File {
		paths[i] = f.Name
	}

	index := array.Search(paths, page)
	if index < 0 {
		http.Error(w, "Image file Not Found", http.StatusNotFound)
		return
	}

	size := r.File[index].FileInfo().Size()
	body, err := r.File[index].Open()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	defer body.Close()

	image.ResponseWrite(w, page, body, size)
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/hoisie/web"
	"github.com/xyproto/genericsite"
	"github.com/xyproto/instapage"
	"github.com/xyproto/permissions2"
	"github.com/xyproto/siteengines"
	"github.com/xyproto/webhandle"
)

const JQUERY_VERSION = "2.0.0"

func hello(val string) string {
	return instapage.Message("root page", "hello: "+val)
}

func helloHandle(ctx *web.Context, name string) string {
	return "Hello, " + name
}

func notFound2(ctx *web.Context, val string) {
	ctx.ResponseWriter.WriteHeader(404)
	ctx.ResponseWriter.Write([]byte(webhandle.NotFound(ctx, val)))
}

func ServeEngines(userState permissions.UserStateKeeper, mainMenuEntries genericsite.MenuEntries) {
	// The user engine
	userEngine := siteengines.NewUserEngine(userState)
	userEngine.ServePages("archlinux.no")

	// The admin engine
	adminEngine := siteengines.NewAdminEngine(userState)
	adminEngine.ServePages(ArchBaseCP, mainMenuEntries)

	// TODO: Move this one to roboticoverlords instead
	// The dynamic IP webpage (returns an *IPState)
	ipEngine := siteengines.NewIPEngine(userState)
	ipEngine.ServePages()

	// The chat system (see also the menu entry in ArchBaseCP)
	chatEngine := siteengines.NewChatEngine(userState)
	chatEngine.ServePages(ArchBaseCP, mainMenuEntries)

	// Wiki engine
	wikiEngine := siteengines.NewWikiEngine(userState)
	wikiEngine.ServePages(ArchBaseCP, mainMenuEntries)

	// Blog engine
	//blogEngine := NewBlogEngine(userState)
	//blogEngine.ServePages(ArchBaseCP, mainMenuEntries)
}

// TODO: One database per site
func main() {

	// UserState with a Redis Connection Pool
	userState := permissions.NewUserState(0, true, ":6379")
	//userState.SetPasswordAlgo("bcrypt")

	defer userState.Close()

	// The archlinux.no webpage,
	mainMenuEntries := ServeArchlinuxNo(userState, "/js/jquery-"+JQUERY_VERSION+".min.js")

	ServeEngines(userState, mainMenuEntries)

	// Compilation errors, vim-compatible filename
	web.Get("/error", webhandle.GenerateErrorHandle("errors.err"))
	web.Get("/errors", webhandle.GenerateErrorHandle("errors.err"))

	// Various .php and .asp urls that showed up in the log
	genericsite.ServeForFun()

	// TODO: Incorporate this check into web.go, to only return
	// stuff in the header when the HEAD method is requested:
	// if ctx.Request.Method == "HEAD" { return }
	// See also: curl -I

	// Serve on port 3009 for the Nginx instance to use
	web.Run("0.0.0.0:3009")
}
<commit_msg>Using permissions2<commit_after>package main

import (
	"github.com/hoisie/web"
	"github.com/xyproto/genericsite"
	"github.com/xyproto/instapage"
	"github.com/xyproto/permissions2"
	"github.com/xyproto/siteengines"
	"github.com/xyproto/webhandle"
)

const JQUERY_VERSION = "2.0.0"

func hello(val string) string {
	return instapage.Message("root page", "hello: "+val)
}

func helloHandle(ctx *web.Context, name string) string {
	return "Hello, " + name
}

func notFound2(ctx *web.Context, val string) {
	ctx.ResponseWriter.WriteHeader(404)
	ctx.ResponseWriter.Write([]byte(webhandle.NotFound(ctx, val)))
}

func ServeEngines(userState permissions.UserStateKeeper, mainMenuEntries genericsite.MenuEntries) {
	// The user engine
	userEngine := siteengines.NewUserEngine(userState)
	userEngine.ServePages("archlinux.no")

	// The admin engine
	adminEngine := siteengines.NewAdminEngine(userState)
	adminEngine.ServePages(ArchBaseCP, mainMenuEntries)

	// TODO: Move this one to roboticoverlords instead
	// The dynamic IP webpage (returns an *IPState)
	ipEngine := siteengines.NewIPEngine(userState)
	ipEngine.ServePages()

	// The chat system (see also the menu entry in ArchBaseCP)
	chatEngine := siteengines.NewChatEngine(userState)
	chatEngine.ServePages(ArchBaseCP, mainMenuEntries)

	// Wiki engine
	wikiEngine := siteengines.NewWikiEngine(userState)
	wikiEngine.ServePages(ArchBaseCP, mainMenuEntries)

	// Blog engine
	//blogEngine := NewBlogEngine(userState)
	//blogEngine.ServePages(ArchBaseCP, mainMenuEntries)
}

// TODO: One database per site
func main() {

	// UserState with a Redis Connection Pool
	userState := permissions.NewUserState(0, true, ":6379")

	defer userState.Close()

	// The archlinux.no webpage,
	mainMenuEntries := ServeArchlinuxNo(userState, "/js/jquery-"+JQUERY_VERSION+".min.js")

	ServeEngines(userState, mainMenuEntries)

	// Compilation errors, vim-compatible filename
	web.Get("/error", webhandle.GenerateErrorHandle("errors.err"))
	web.Get("/errors", webhandle.GenerateErrorHandle("errors.err"))

	// Various .php and .asp urls that showed up in the log
	genericsite.ServeForFun()

	// TODO: Incorporate this check into web.go, to only return
	// stuff in the header when the HEAD method is requested:
	// if ctx.Request.Method == "HEAD" { return }
	// See also: curl -I

	// Serve on port 3009 for the Nginx instance to use
	web.Run("0.0.0.0:3009")
}
<|endoftext|>


<commit_before>package console

import (
	"encoding/json"
	"errors"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"github.com/leancloud/lean-cli/lean/utils"
)

type filesPattern struct {
	Includes []string
	Excludes []string
}

// Runtime stands for a language runtime
type Runtime struct {
	Name       string
	Exec       string
	Args       []string
	WatchFiles []string
	Envs       []string
	// DeployFiles is the patterns for source code to deploy to the remote server
	DeployFiles filesPattern
}

// Run the project, and watch file changes
func (runtime *Runtime) Run() error {
	command := exec.Command(runtime.Exec, runtime.Args...)
	command.Stdout = os.Stdout
	command.Stderr = os.Stderr

	for _, env := range runtime.Envs {
		command.Env = append(command.Env, env)
	}

	return command.Run()
	// if err != nil {
	// 	return err
	// }

	// // watch file changes
	// watcher, err := fsnotify.NewWatcher()
	// if err != nil {
	// 	return err
	// }
	// defer watcher.Close()
	// go func() {
	// 	for {
	// 		select {
	// 		case event := <-watcher.Events:
	// 			fmt.Println("event:", event)
	// 			command.Process.Kill()
	// 		case err := <-watcher.Errors:
	// 			fmt.Println("error:", err)
	// 		}
	// 	}
	// }()
	// for _, file := range runtime.WatchFiles {
	// 	err = watcher.Add(file)
	// }

	// // start the command line
	// return command.Wait()
}

// DetectRuntime returns the project's runtime
func DetectRuntime(projectPath string) (*Runtime, error) {
	// order is importand
	if utils.IsFileExists(filepath.Join("cloud", "main.js")) {
		log.Println("> 检测到 cloudcode 运行时")
		return nil, nil
	}
	if utils.IsFileExists("server.js") && utils.IsFileExists("package.json") {
		log.Println("> 检测到 node.js 运行时")
		return newNodeRuntime(projectPath)
	}
	if utils.IsFileExists("requirements.txt") && utils.IsFileExists("wsgi.py") {
		log.Println("> 检测到 Python 运行时")
		return newPythonRuntime(projectPath)
	}
	if utils.IsFileExists("composer.json") && utils.IsFileExists(filepath.Join("public", "index.php")) {
		log.Println("> 检测到 PHP 运行时")
		return newPhpRuntime(projectPath)
	}
	return nil, errors.New("invalid runtime")
}

func newPythonRuntime(projectPath string) (*Runtime, error) {
	execName := "python2.7"

	if content, err := ioutil.ReadFile(filepath.Join(projectPath, "runtime.txt")); err == nil {
		if strings.HasPrefix(string(content), "python-2.7") {
			execName = "python2.7"
		} else if strings.HasPrefix(string(content), "python-3.5") {
			execName = "python3.5"
		} else {
			return nil, errors.New("invalid python runtime.txt format, only `python-2.7` and `python-3.5` were allowed")
		}
	}

	// for windows don't have a pythonx.x symbol link
	if _, err := exec.LookPath(execName); err != nil {
		log.Printf("`%s` command not found, fallback to `python`", execName)
	}

	return &Runtime{
		Name:       "python",
		Exec:       execName,
		Args:       []string{"wsgi.py"},
		WatchFiles: []string{"."},
		Envs:       os.Environ(),
		DeployFiles: filesPattern{
			Includes: []string{"**"},
			Excludes: []string{
				".git/**",
				".avoscloud/**",
				".leancloud/**",
				"*.pyc",
			},
		},
	}, nil
}

func newNodeRuntime(projectPath string) (*Runtime, error) {
	execName := "node"
	script := "server.js"
	pkgFile := filepath.Join(projectPath, "package.json")
	if content, err := ioutil.ReadFile(pkgFile); err == nil {
		pkg := new(struct {
			Scripts struct {
				Start string `json:"start"`
			} `json:"scripts"`
		})
		err = json.Unmarshal(content, pkg)
		if err != nil {
			return nil, err
		}
		if pkg.Scripts.Start != "" {
			execName = "npm"
			script = "start"
		}
	}

	return &Runtime{
		Name:       "node.js",
		Exec:       execName,
		Args:       []string{script},
		WatchFiles: []string{"."},
		Envs:       os.Environ(),
		DeployFiles: filesPattern{
			Includes: []string{"**"},
			Excludes: []string{
				".git/**",
				".avoscloud/**",
				".leancloud/**",
				"node_modules/**",
			},
		},
	}, nil
}

func newPhpRuntime(projectPath string) (*Runtime, error) {
	return &Runtime{
		Name:       "php",
		Exec:       "php",
		Args:       []string{"-S", "127.0.0.1:3000", "-t", "public"},
		WatchFiles: []string{"."},
		Envs:       os.Environ(),
		DeployFiles: filesPattern{
			Includes: []string{"**"},
			Excludes: []string{
				".git/**",
				".avoscloud/**",
				".leancloud/**",
				"vendor/**",
			},
		},
	}, nil
}
<commit_msg>fix: pass current shell's env to development server<commit_after>package console

import (
	"encoding/json"
	"errors"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"github.com/leancloud/lean-cli/lean/utils"
)

type filesPattern struct {
	Includes []string
	Excludes []string
}

// Runtime stands for a language runtime
type Runtime struct {
	Name       string
	Exec       string
	Args       []string
	WatchFiles []string
	Envs       []string
	// DeployFiles is the patterns for source code to deploy to the remote server
	DeployFiles filesPattern
}

// Run the project, and watch file changes
func (runtime *Runtime) Run() error {
	command := exec.Command(runtime.Exec, runtime.Args...)
	command.Env = os.Environ()
	command.Stdout = os.Stdout
	command.Stderr = os.Stderr

	for _, env := range runtime.Envs {
		command.Env = append(command.Env, env)
	}

	return command.Run()
	// if err != nil {
	// 	return err
	// }

	// // watch file changes
	// watcher, err := fsnotify.NewWatcher()
	// if err != nil {
	// 	return err
	// }
	// defer watcher.Close()
	// go func() {
	// 	for {
	// 		select {
	// 		case event := <-watcher.Events:
	// 			fmt.Println("event:", event)
	// 			command.Process.Kill()
	// 		case err := <-watcher.Errors:
	// 			fmt.Println("error:", err)
	// 		}
	// 	}
	// }()
	// for _, file := range runtime.WatchFiles {
	// 	err = watcher.Add(file)
	// }

	// // start the command line
	// return command.Wait()
}

// DetectRuntime returns the project's runtime
func DetectRuntime(projectPath string) (*Runtime, error) {
	// order is importand
	if utils.IsFileExists(filepath.Join("cloud", "main.js")) {
		log.Println("> 检测到 cloudcode 运行时")
		return nil, nil
	}
	if utils.IsFileExists("server.js") && utils.IsFileExists("package.json") {
		log.Println("> 检测到 node.js 运行时")
		return newNodeRuntime(projectPath)
	}
	if utils.IsFileExists("requirements.txt") && utils.IsFileExists("wsgi.py") {
		log.Println("> 检测到 Python 运行时")
		return newPythonRuntime(projectPath)
	}
	if utils.IsFileExists("composer.json") && utils.IsFileExists(filepath.Join("public", "index.php")) {
		log.Println("> 检测到 PHP 运行时")
		return newPhpRuntime(projectPath)
	}
	return nil, errors.New("invalid runtime")
}

func newPythonRuntime(projectPath string) (*Runtime, error) {
	execName := "python2.7"

	if content, err := ioutil.ReadFile(filepath.Join(projectPath, "runtime.txt")); err == nil {
		if strings.HasPrefix(string(content), "python-2.7") {
			execName = "python2.7"
		} else if strings.HasPrefix(string(content), "python-3.5") {
			execName = "python3.5"
		} else {
			return nil, errors.New("invalid python runtime.txt format, only `python-2.7` and `python-3.5` were allowed")
		}
	}

	// for windows don't have a pythonx.x symbol link
	if _, err := exec.LookPath(execName); err != nil {
		log.Printf("`%s` command not found, fallback to `python`", execName)
	}

	return &Runtime{
		Name:       "python",
		Exec:       execName,
		Args:       []string{"wsgi.py"},
		WatchFiles: []string{"."},
		Envs:       os.Environ(),
		DeployFiles: filesPattern{
			Includes: []string{"**"},
			Excludes: []string{
				".git/**",
				".avoscloud/**",
				".leancloud/**",
				"*.pyc",
			},
		},
	}, nil
}

func newNodeRuntime(projectPath string) (*Runtime, error) {
	execName := "node"
	script := "server.js"
	pkgFile := filepath.Join(projectPath, "package.json")
	if content, err := ioutil.ReadFile(pkgFile); err == nil {
		pkg := new(struct {
			Scripts struct {
				Start string `json:"start"`
			} `json:"scripts"`
		})
		err = json.Unmarshal(content, pkg)
		if err != nil {
			return nil, err
		}
		if pkg.Scripts.Start != "" {
			execName = "npm"
			script = "start"
		}
	}

	return &Runtime{
		Name:       "node.js",
		Exec:       execName,
		Args:       []string{script},
		WatchFiles: []string{"."},
		Envs:       os.Environ(),
		DeployFiles: filesPattern{
			Includes: []string{"**"},
			Excludes: []string{
				".git/**",
				".avoscloud/**",
				".leancloud/**",
				"node_modules/**",
			},
		},
	}, nil
}

func newPhpRuntime(projectPath string) (*Runtime, error) {
	return &Runtime{
		Name:       "php",
		Exec:       "php",
		Args:       []string{"-S", "127.0.0.1:3000", "-t", "public"},
		WatchFiles: []string{"."},
		Envs:       os.Environ(),
		DeployFiles: filesPattern{
			Includes: []string{"**"},
			Excludes: []string{
				".git/**",
				".avoscloud/**",
				".leancloud/**",
				"vendor/**",
			},
		},
	}, nil
}
<|endoftext|>


<commit_before>package swagger

import (
	"bytes"
	"encoding/json"
	"fmt"
	"path"
	"strings"
	"testing"
	"text/template"

	"github.com/alecthomas/jsonschema"
)

var swg = `{"swagger":"2.0","info":{"version":"3.0","title":"EverythingAPI","description":"EverythingMe's context aware API"},"host":"localhost:9944","basePath":"/evme/3.0","schemes":["http","https"],"consumes":["text/json"],"produces":["text/json"],"paths":{"/Context":{"get":{"description":"Get the extended context from the server","parameters":[{"name":"apiKey","description":"","required":false,"type":"string","in":"query"},{"name":"X-Evme-Ctx","description":"","required":false,"type":"string","in":"header"}],"responses":{"default":{"description":"context.ExtendedContext","schema":{"$ref":"#/definitions/ExtendedContext"}}},"tags":["Context"]}},"/Echo":{"get":{"description":"Echo the request data and context for debugging","parameters":[{"name":"apiKey","description":"","required":false,"type":"string","in":"query"},{"name":"X-Evme-Ctx","description":"","required":false,"type":"string","in":"header"}],"responses":{"default":{"description":"context.Context","schema":{"$ref":"#/definitions/Context"}}},"tags":["Echo"]}},"/ping":{"get":{"description":"test ping","responses":{"default":{"description":"string","schema":{"type":"string"}}},"tags":["Ping"]}}},"definitions":{"APIKey":{"type":"object","properties":{"enabled":{"type":"boolean"},"key":{"type":"string"},"name":{"type":"string"}},"additionalProperties":false,"required":["key","name","enabled"]},"Client":{"type":"object","properties":{"deviceId":{"type":"string"},"locale":{"type":"string"},"os":{"type":"string"},"version":{"type":"string"}},"additionalProperties":false,"required":["os","version","deviceId","locale"]},"ClientContext":{"type":"object","properties":{"activeInsights":{"type":"array","items":{"$ref":"#/definitions/Insight"}},"activeScenarios":{"type":"array","items":{"type":"string"}},"device":{"$ref":"#/definitions/DeviceContext"},"location":{"$ref":"#/definitions/GeoContext"},"motionState":{"$ref":"#/definitions/MotionState"},"network":{"$ref":"#/definitions/NetworkContext"},"phone":{"$ref":"#/definitions/PhoneContext"},"time":{"$ref":"#/definitions/TimeContext"}},"additionalProperties":false},"Context":{"type":"object","properties":{"client":{"$ref":"#/definitions/ClientContext"},"ext":{"$ref":"#/definitions/ExtendedContext"},"request":{"$ref":"#/definitions/RequestContext"}},"additionalProperties":false,"required":["client","request"]},"DeviceContext":{"type":"object","properties":{"battery":{"type":"integer"},"batteryPercent":{"type":"integer"},"deviceName":{"type":"string"},"dockType":{"type":"integer"},"headphonesConnected":{"type":"boolean"},"locale":{"type":"string"},"manufacturer":{"type":"string"},"os":{"type":"string"},"osVersion":{"type":"string"},"screenActive":{"type":"boolean"},"screenHeight":{"type":"integer"},"screenWidth":{"type":"integer"},"yearClass":{"type":"integer"}},"additionalProperties":false,"required":["battery","batteryPercent","headphonesConnected","screenActive","dockType","deviceName","manufacturer","os","osVersion","screenWidth","screenHeight","locale","yearClass"]},"ExtendedContext":{"type":"object","properties":{"insights":{"type":"array","items":{"$ref":"#/definitions/ServerInsight"}},"scenartios":{"type":"array","items":{"type":"string"}}},"additionalProperties":false,"required":["insights","scenartios"]},"GeoContext":{"type":"object","properties":{"accuracy":{"type":"number"},"homeCountry":{"type":"string"},"isRoaming":{"type":"boolean"},"isTravelling":{"type":"boolean"},"knownLocationCertainty":{"type":"number"},"knownLocationId":{"type":"string"},"lat":{"type":"number"},"lon":{"type":"number"},"simCountry":{"type":"string"}},"additionalProperties":false,"required":["lat","lon","accuracy","knownLocationCertainty","simCountry","homeCountry","isTravelling","isRoaming","knownLocationId"]},"Insight":{"type":"object","properties":{"confidence":{"type":"number"},"lastUpdatePeriod":{"type":"integer"},"params":{"type":"object","patternProperties":{".*":{"type":"string"}}},"type":{"type":"string"},"values":{"type":"array","items":{"type":"string"}}},"additionalProperties":false,"required":["type","confidence","lastUpdatePeriod"]},"MotionState":{"type":"object","properties":{"activity":{"type":"integer"},"confidence":{"type":"integer"}},"additionalProperties":false,"required":["activity","confidence"]},"NetworkContext":{"type":"object","properties":{"BTConnectedDevices":{"type":"array","items":{"type":"string"}},"BTEnabled":{"type":"boolean"},"activeNetwork":{"type":"string"},"availableWifiNetworks":{"type":"array","items":{"type":"string"}},"carrier":{"type":"string"},"mobileCountryCode":{"type":"integer"},"mobileNetworkCode":{"type":"integer"},"networkStrength":{"type":"integer"},"wifiName":{"type":"string"}},"additionalProperties":false,"required":["activeNetwork","networkStrength","wifiName","availableWifiNetworks","carrier","mobileNetworkCode","mobileCountryCode","BTEnabled","BTConnectedDevices"]},"PhoneContext":{"type":"object","properties":{"missedCall":{"type":"string"}},"additionalProperties":false,"required":["missedCall"]},"RequestContext":{"type":"object","properties":{"api":{"$ref":"#/definitions/APIKey"},"client":{"$ref":"#/definitions/Client"},"featureFlags":{"type":"array","items":{"type":"string"}},"homeCountryLocale":{"type":"string"},"ip":{"type":"string"},"requestId":{"type":"string"},"resolvedLocation":{"$ref":"#/definitions/TGeoLocation"},"trace":{"type":"array","items":{"$ref":"#/definitions/ServerHit"}},"user":{"$ref":"#/definitions/User"}},"additionalProperties":false,"required":["ip","requestId","featureFlags","homeCountryLocale"]},"ServerHit":{"type":"object","properties":{"cluster":{"type":"string"},"hostName":{"type":"string"},"timestamp":{"type":"integer"}},"additionalProperties":false,"required":["hostName","cluster","timestamp"]},"ServerInsight":{"type":"object","properties":{"TTL":{"type":"integer"},"confidence":{"type":"number"},"goefenceRadius":{"type":"number"},"jsonValue":{"type":"string"},"type":{"type":"string"}},"additionalProperties":false,"required":["type","jsonValue","confidence","TTL","goefenceRadius"]},"TGeoLocation":{"type":"object","properties":{"city":{"type":"string"},"country":{"type":"string"},"countryCode":{"type":"string"},"countryId":{"type":"integer"},"lat":{"type":"number"},"lon":{"type":"number"},"name":{"type":"string"},"state":{"type":"string"},"type":{"type":"string"},"zip":{"type":"string"}},"additionalProperties":false,"required":["lat","lon","name","type","city","zip","state","country","countryCode","countryId"]},"TimeContext":{"type":"object","properties":{"isWeekend":{"type":"boolean"},"localTime":{"type":"integer"},"timeOfDay":{"type":"integer"},"timeZone":{"type":"integer"}},"additionalProperties":false,"required":["localTime","timeZone","timeOfDay","isWeekend"]},"User":{"type":"object","properties":{"allowAdultContent":{"type":"boolean"},"credentials":{"type":"string"},"id":{"type":"string"},"internal":{"type":"boolean"}},"additionalProperties":false,"required":["id","credentials","internal","allowAdultContent"]}}}`

func render(templateString string, api *JavaAPI) ([]byte, error) {
	//	tpl, err := template.New("schema").Funcs(template.FuncMap{
	//		"getDefault": preprocessDefault,
	//	}).Parse(templateString)

	templateString = strings.Replace(
		strings.Replace(
			strings.Replace(
				strings.Replace(templateString, "\\\n", "", -1),
				"\\n", "\n", -1),
			"~", "`", -1),
		"\\ ", "", -1)

	tpl, err := template.New("schema").Parse(templateString)
	if err != nil {
		return nil, fmt.Errorf("Could not parse template: %s", err)
	}

	buf := bytes.NewBuffer(nil)

	if err = tpl.Execute(buf, api); err != nil {
		return nil, fmt.Errorf("Could not execute template: %s", err)
	}

	return buf.Bytes(), nil

}

func TestSwagger(t *testing.T) {

	var api API

	if err := json.Unmarshal([]byte(swg), &api); err != nil {
		t.Fatal(err)
	}

	japi := NewJavaAPI(&api)

	fmt.Printf("%#v\n", japi)

	b, err := render(tpl, &japi)
	if err != nil {
		t.Fatal(err)
	}

	fmt.Println(string(b))

}

/*
SwaggerVersion string            `json:"swagger"`
	Info           Info              `json:"info,omitempty"`
	Host           string            `json:"host"`
	Basepath       string            `json:"basePath"`
	Schemes        []string          `json:"schemes"`
	Consumes       []string          `json:"consumes"`
	Produces       []string          `json:"produces"`
	Paths          map[string]Path   `json:"paths"`
	Definitions    map[string]Schema `json:"definitions,omitempty"`
*/

func javaType(t *jsonschema.Type, namespace string) string {

	switch Type(t.Type) {
	case String:
		return "String"
	case Number:
		return "float"
	case Boolean:
		return "boolean"
	case Integer:
		return "int"
	case Array:
		return fmt.Sprintf("List<%s>", javaType(t.Items, namespace))
	case Object:
		return "Object"
	default:
		if t.Ref != "" {
			if namespace != "" {
				return namespace + "." + path.Base(t.Ref)
			}
			return path.Base(t.Ref)
		}
		if namespace != "" {
			return namespace + "." + t.Type
		}
		return t.Type

	}
}

func methodName(path, method string) string {

	return method + strings.Title(strings.Replace(path, "/", "", -1))
}

type JavaClass struct {
	Name       string
	Members    []JavaMember
	Extends    string
	Implements string
}

type JavaMember struct {
	Name string
	Type JavaTypeRef
}
type JavaTypeRef struct {
	Namespace string
	Type      string
	Contained []JavaTypeRef
}

func (t JavaTypeRef) String() string {

	ret := ""
	if t.Namespace != "" {
		ret = t.Namespace + "."
	}
	ret += t.Type
	if t.Contained != nil && len(t.Contained) > 0 {
		ret += "<"
		for _, sub := range t.Contained {
			ret += sub.String() + ","
		}

		ret = strings.TrimRight(ret, ",") + ">"
	}

	return ret
}

type JavaMethod struct {
	Name     string
	Returns  JavaTypeRef
	Params   []JavaParam
	HttpVerb string
	Doc      string
	Path     string
}

type JavaParam struct {
	Name string
	Doc  string
	Type JavaTypeRef
}

type JavaAPI struct {
	Name    string
	Doc     string
	Root    string
	Types   []JavaClass
	Methods []JavaMethod
}

func newJavaTypeRef(t *jsonschema.Type) JavaTypeRef {
	ret := JavaTypeRef{}
	switch Type(t.Type) {
	case String:
		ret.Type = "String"
	case Number:
		ret.Type = "Float"
	case Boolean:
		ret.Type = "Boolean"
	case Integer:
		ret.Type = "Integer"
	case Array:
		ret.Type = "List"
		ret.Contained = []JavaTypeRef{newJavaTypeRef(t.Items)}
	case Object:
		ret.Type = "Object"
	default:
		ret.Namespace = "Types"
		if t.Ref != "" {
			ret.Type = path.Base(t.Ref)
		} else {
			ret.Type = t.Type
		}
	}
	return ret
}

func newJavaClass(name string, t *jsonschema.Type) JavaClass {
	ret := JavaClass{
		Name:    name,
		Members: []JavaMember{},
	}

	for k, prop := range t.Properties {
		ret.Members = append(ret.Members, JavaMember{
			Name: k,
			Type: newJavaTypeRef(prop),
		})
	}
	return ret
}

func newJavaTypeSwagger(t Type) JavaTypeRef {
	ret := JavaTypeRef{}
	switch t {

	case Number:
		ret.Type = "Float"
	case Boolean:
		ret.Type = "Boolean"
	case Integer:
		ret.Type = "Integer"
		//	case Array:
		//		ret.Type = "List"
		//		ret.Contained = []JavaType{newJavaType(t.Items)}
	case Object:

		ret.Type = "Object"
	case String:
		fallthrough
	default:
		ret.Type = "String"
	}
	return ret
}

func formatMethodName(path, verb string) string {
	return strings.ToLower(verb) + strings.Title(strings.Replace(path, "/", "", -1))
}
func newJavaMethod(path, verb string, method Method) JavaMethod {

	ret := JavaMethod{
		Name:     formatMethodName(path, verb),
		Returns:  newJavaTypeRef(method.Responses["default"].Schema.Type),
		Params:   make([]JavaParam, 0, len(method.Parameters)),
		HttpVerb: strings.ToUpper(verb),
		Path:     path,
		Doc:      method.Description,
	}

	for _, param := range method.Parameters {

		jparm := JavaParam{
			Name: param.Name,
			Type: newJavaTypeSwagger(param.Type),
			Doc:  param.Description,
		}

		ret.Params = append(ret.Params, jparm)

	}
	return ret
}

func NewJavaAPI(swapi *API) JavaAPI {

	api := JavaAPI{
		Name:    swapi.Info.Title,
		Doc:     swapi.Info.Description,
		Root:    swapi.Basepath,
		Types:   make([]JavaClass, 0, len(swapi.Definitions)),
		Methods: make([]JavaMethod, 0, len(swapi.Paths)),
	}

	for name, tp := range swapi.Definitions {
		api.Types = append(api.Types, newJavaClass(name, tp.Type))
	}

	for path, methods := range swapi.Paths {
		for verb, method := range methods {

			api.Methods = append(api.Methods, newJavaMethod(path, verb, method))
		}
	}

	return api
}

var tpl = `
/**
* Autogenerated Class {{.Name}}
*
* {{.Doc}}
*/
public class {{.Name}} extends BaseAPI {

    static final public String ROOT = "{{.Root}}";

    public static class Types {
        {{ range .Types }}
        public static class {{ .Name }} {\
            {{ range .Members }}\
               public {{ .Type.Type }} {{ .Name }};\
            {{ end }}
        }
        {{ end }}
    }

    public {{.Name}}(boolean secure, String host, Decoder decoder, Client client) {
        super(secure, host, decoder, client);
    }

    {{ range .Methods }}
        / **
        * {{ .Name }}
        * {{ .Doc }}\
        {{ range .Params }}\
        * @param {{ .Name }}
        {{ end }}\
        **/
        public CompletableFuture<{{ .Returns }}> {{ .Name }}() {
            return perform(Request.Method.{{ .HttpVerb }}, ROOT, "{{.Path}}", new Request.ParamMap(),
                    parser({{ .Returns }}.class));
        }
    {{ end }}
}
`
<commit_msg>removed swagger test which wasnt really a test<commit_after><|endoftext|>


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

import (
	"reflect"
	"testing"

	"google.golang.org/appengine/datastore"
)

func ptrToInt(x int) *int {
	return &x
}

func TestStructEncoding(t *testing.T) {
	testCases := []struct {
		in      interface{}
		want    []datastore.Property
		wantErr error
	}{
		{
			in: struct{ X bool }{X: true},
			want: []datastore.Property{{
				Name:  "X",
				Value: bool(true),
			}},
		},
		{
			in: struct{ X int }{X: -15},
			want: []datastore.Property{{
				Name:  "X",
				Value: int64(-15),
			}},
		},
		{
			in: struct{ X uint }{X: 15},
			want: []datastore.Property{{
				Name:  "X",
				Value: uint64(15),
			}},
		},
		{
			in: struct{ X float32 }{X: 1.5},
			want: []datastore.Property{{
				Name:  "X",
				Value: float64(1.5),
			}},
		},
		{
			in: struct{ X string }{X: "abc"},
			want: []datastore.Property{{
				Name:  "X",
				Value: string("abc"),
			}},
		},
		{
			in: struct{ X []bool }{X: []bool{true, false, true}},
			want: []datastore.Property{{
				Name:  "X",
				Value: []bool{true, false, true},
			}},
		},
		{
			in: struct{ X []int }{X: []int{1, 2, 3}},
			want: []datastore.Property{{
				Name:  "X",
				Value: []int64{1, 2, 3},
			}},
		},
		{
			in: struct{ X []string }{X: []string{"a", "b", "c"}},
			want: []datastore.Property{{
				Name:  "X",
				Value: []string{"a", "b", "c"},
			}},
		},
		{
			in: struct {
				X int
				Y string
			}{X: 15, Y: "a"},
			want: []datastore.Property{{
				Name:  "X",
				Value: int64(15),
			}, {
				Name:  "Y",
				Value: string("a"),
			}},
		},
		{
			in: struct {
				X int
				Y []string
			}{X: 15, Y: []string{"a"}},
			want: []datastore.Property{{
				Name:  "X",
				Value: int64(15),
			}, {
				Name:  "Y",
				Value: []string{"a"},
			}},
		},
		{
			in: struct {
				X int
				Y []string
			}{X: 15, Y: []string{"a", "b", "c"}},
			want: []datastore.Property{{
				Name:  "X",
				Value: int64(15),
			}, {
				Name:  "Y",
				Value: []string{"a", "b", "c"},
			}},
		},
		{
			in: struct {
				X *int
			}{X: ptrToInt(15)},
			want: []datastore.Property{{
				Name:  "X",
				Value: int64(15),
			}},
		},
	}
	for _, tc := range testCases {
		got, gotErr := SaveStruct(tc.in)
		if !reflect.DeepEqual(got, tc.want) {
			t.Errorf("SaveStruct(%v): got (%v, %v), want (%v, %v)", tc.in, got, gotErr, tc.want, tc.wantErr)
		}
	}
}
<commit_msg>Expand unit testing to test aliasing and struct pointers<commit_after>// Copyright 2010 The Go Authors. All rights reserved.
// Copyright 2016 Morgan Conbere.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package datastore

import (
	"reflect"
	"testing"

	"google.golang.org/appengine/datastore"
)

func ptrToInt(x int) *int {
	return &x
}

type base struct {
	X int
	Y string
	Z []int
	W *int
}

func TestStructEncoding(t *testing.T) {
	testCases := []struct {
		in      interface{}
		want    []datastore.Property
		wantErr error
	}{
		{
			in: struct{ X bool }{X: true},
			want: []datastore.Property{{
				Name:  "X",
				Value: bool(true),
			}},
		},
		{
			in: struct{ X int }{X: -15},
			want: []datastore.Property{{
				Name:  "X",
				Value: int64(-15),
			}},
		},
		{
			in: struct{ X uint }{X: 15},
			want: []datastore.Property{{
				Name:  "X",
				Value: uint64(15),
			}},
		},
		{
			in: struct{ X float32 }{X: 1.5},
			want: []datastore.Property{{
				Name:  "X",
				Value: float64(1.5),
			}},
		},
		{
			in: struct{ X string }{X: "abc"},
			want: []datastore.Property{{
				Name:  "X",
				Value: string("abc"),
			}},
		},
		{
			in: struct{ X []bool }{X: []bool{true, false, true}},
			want: []datastore.Property{{
				Name:  "X",
				Value: []bool{true, false, true},
			}},
		},
		{
			in: struct{ X []int }{X: []int{1, 2, 3}},
			want: []datastore.Property{{
				Name:  "X",
				Value: []int64{1, 2, 3},
			}},
		},
		{
			in: struct{ X []string }{X: []string{"a", "b", "c"}},
			want: []datastore.Property{{
				Name:  "X",
				Value: []string{"a", "b", "c"},
			}},
		},
		{
			in: struct {
				X int
				Y string
			}{X: 15, Y: "a"},
			want: []datastore.Property{{
				Name:  "X",
				Value: int64(15),
			}, {
				Name:  "Y",
				Value: string("a"),
			}},
		},
		{
			in: struct {
				X int
				Y []string
			}{X: 15, Y: []string{"a"}},
			want: []datastore.Property{{
				Name:  "X",
				Value: int64(15),
			}, {
				Name:  "Y",
				Value: []string{"a"},
			}},
		},
		{
			in: struct {
				X int
				Y []string
			}{X: 15, Y: []string{"a", "b", "c"}},
			want: []datastore.Property{{
				Name:  "X",
				Value: int64(15),
			}, {
				Name:  "Y",
				Value: []string{"a", "b", "c"},
			}},
		},
		{
			in: struct {
				X *int
			}{X: ptrToInt(15)},
			want: []datastore.Property{{
				Name:  "X",
				Value: int64(15),
			}},
		},
		{
			in: struct {
				base
				X int
			}{base: base{X: int(3)}, X: int(15)},
			want: []datastore.Property{{
				Name:  "X",
				Value: int64(15),
			}},
		},
		{
			in: struct {
				*base
				X string
			}{base: &base{X: int(3), W: ptrToInt(12)}, X: "abc"},
			want: []datastore.Property{{
				Name:  "W",
				Value: int64(12),
			}, {
				Name:  "X",
				Value: "abc",
			}},
		},
	}
	for _, tc := range testCases {
		got, gotErr := SaveStruct(tc.in)
		if !reflect.DeepEqual(got, tc.want) {
			t.Errorf("SaveStruct(%v): got (%v, %v), want (%v, %v)", tc.in, got, gotErr, tc.want, tc.wantErr)
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2013 The lime Authors.
// Use of this source code is governed by a 2-clause
// BSD-style license that can be found in the LICENSE file.

package backend

import (
	"code.google.com/p/log4go"
	"fmt"
	"github.com/howeyc/fsnotify"
	"github.com/limetext/lime/backend/loaders"
	. "github.com/limetext/lime/backend/util"
	. "github.com/quarnster/util/text"
	"runtime"
	"runtime/debug"
	"sync"
)

func init() {
	runtime.GOMAXPROCS(runtime.NumCPU())
	GetEditor()
}

type (
	Editor struct {
		HasSettings
		windows       []*Window
		active_window *Window
		loginput      bool
		cmdhandler    commandHandler
		keyBindings   KeyBindings
		console       *View
		frontend      Frontend
		clipboard     string
		keyInput      chan (KeyPress)
		watcher       *fsnotify.Watcher
		watchedFiles  map[string]Watched
		watchLock     sync.Mutex
	}

	// The Frontend interface defines the API
	// for functionality that is frontend specific.
	Frontend interface {
		// Probe the frontend for the currently
		// visible region of the given view.
		VisibleRegion(v *View) Region

		// Make the frontend show the specified region of the
		// given view.
		Show(v *View, r Region)

		// Sets the status message shown in the status bar
		StatusMessage(string)

		// Displays an error message to the usser
		ErrorMessage(string)

		// Displays a message dialog to the user
		MessageDialog(string)

		// Displays an ok / cancel dialog to the user.
		// "okname" if provided will be used as the text
		// instead of "Ok" for the ok button.
		// Returns true when ok was pressed, and false when
		// cancel was pressed.
		OkCancelDialog(msg string, okname string) bool
	}
	myLogWriter struct {
		log chan string
	}
	DummyFrontend struct {
		m sync.Mutex
		// Default return value for OkCancelDialog
		defaultAction bool
	}
)

const (
	LIME_USER_PACKAGES_PATH = "../../3rdparty/bundles/"
	LIME_USER_PACKETS_PATH  = "../../3rdparty/bundles/User/"
	LIME_DEFAULTS_PATH      = "../../backend/packages/Default/"
)

func (h *DummyFrontend) SetDefaultAction(action bool) {
	h.m.Lock()
	defer h.m.Unlock()
	h.defaultAction = action
}
func (h *DummyFrontend) StatusMessage(msg string) { log4go.Info(msg) }
func (h *DummyFrontend) ErrorMessage(msg string)  { log4go.Error(msg) }
func (h *DummyFrontend) MessageDialog(msg string) { log4go.Info(msg) }
func (h *DummyFrontend) OkCancelDialog(msg string, button string) bool {
	log4go.Info(msg)
	h.m.Lock()
	defer h.m.Unlock()
	return h.defaultAction
}
func (h *DummyFrontend) Show(v *View, r Region)       {}
func (h *DummyFrontend) VisibleRegion(v *View) Region { return Region{} }

func newMyLogWriter() *myLogWriter {
	ret := &myLogWriter{make(chan string, 100)}
	go ret.handle()
	return ret
}

func (m *myLogWriter) handle() {
	for fl := range m.log {
		c := GetEditor().Console()
		f := fmt.Sprintf("%08d %d %s", c.Buffer().Size(), len(fl), fl)
		e := c.BeginEdit()
		c.Insert(e, c.Buffer().Size(), f)
		c.EndEdit(e)
	}
}

func (m *myLogWriter) LogWrite(rec *log4go.LogRecord) {
	p := Prof.Enter("log")
	defer p.Exit()
	fl := log4go.FormatLogRecord(log4go.FORMAT_DEFAULT, rec)
	m.log <- fl
}

func (m *myLogWriter) Close() {
	fmt.Println("Closing...")
	close(m.log)
}

var (
	ed  *Editor
	edl sync.Mutex
)

func GetEditor() *Editor {
	edl.Lock()
	defer edl.Unlock()
	if ed == nil {
		ed = &Editor{
			cmdhandler: commandHandler{
				ApplicationCommands: make(appcmd),
				TextCommands:        make(textcmd),
				WindowCommands:      make(wndcmd),
				verbose:             true,
			},
			frontend: &DummyFrontend{},
			console: &View{
				buffer:  NewBuffer(),
				scratch: true,
			},
			keyInput:     make(chan KeyPress, 32),
			watcher:      newWatcher(),
			watchedFiles: make(map[string]Watched),
		}
		ed.console.Settings().Set("is_widget", true)
		ed.Settings() // Just to initialize it
		log4go.Global.Close()
		log4go.Global.AddFilter("console", log4go.DEBUG, newMyLogWriter())
		go ed.inputthread()
		go ed.observeFiles()
	}
	return ed
}

func (e *Editor) Frontend() Frontend {
	return e.frontend
}

func (e *Editor) SetFrontend(f Frontend) {
	e.frontend = f
}

func (e *Editor) Init() {
	ed.loadKeybindings()
	ed.loadSettings()
}

func (e *Editor) Keybindings() *KeyBindings {
	return &e.keyBindings
}

func (e *Editor) loadKeybinding(pkg *packet) {
	var bindings KeyBindings
	if err := loaders.LoadJSON(pkg.Get().([]byte), &bindings); err != nil {
		log4go.Error(err)
	} else {
		log4go.Info("Loaded %s", pkg.Name())
		e.Watch(NewWatchedPackage(pkg))
	}
	e.keyBindings.merge(&bindings)
}

func (e *Editor) loadKeybindings() {
	for _, p := range packets.filter("keymap") {
		e.loadKeybinding(p)
	}
}

func (e *Editor) loadSetting(pkg *packet) {
	if err := loaders.LoadJSON(pkg.Get().([]byte), e.Settings()); err != nil {
		log4go.Error(err)
	} else {
		log4go.Info("Loaded %s", pkg.Name())
		e.Watch(NewWatchedPackage(pkg))
	}
}

func (e *Editor) loadSettings() {
	for _, p := range packets.filter("setting") {
		e.loadSetting(p)
	}
}

func (e *Editor) PackagesPath() string {
	return "../../3rdparty/bundles/"
}

func (e *Editor) Console() *View {
	return e.console
}

func (e *Editor) Windows() []*Window {
	edl.Lock()
	defer edl.Unlock()
	ret := make([]*Window, len(e.windows))
	copy(ret, e.windows)
	return ret
}

func (e *Editor) SetActiveWindow(w *Window) {
	e.active_window = w
}

func (e *Editor) ActiveWindow() *Window {
	return e.active_window
}

func (e *Editor) Watcher() *fsnotify.Watcher {
	return e.watcher
}

func (e *Editor) NewWindow() *Window {
	edl.Lock()
	e.windows = append(e.windows, &Window{})
	w := e.windows[len(e.windows)-1]
	edl.Unlock()
	w.Settings().SetParent(e)
	ed.SetActiveWindow(w)
	OnNewWindow.Call(w)
	return w
}

func (e *Editor) remove(w *Window) {
	edl.Lock()
	defer edl.Unlock()
	for i, ww := range e.windows {
		if w == ww {
			end := len(e.windows) - 1
			if i != end {
				copy(e.windows[i:], e.windows[i+1:])
			}
			e.windows = e.windows[:end]
			return
		}
	}
	log4go.Error("Wanted to remove window %+v, but it doesn't appear to be a child of this editor", w)
}

func (e *Editor) Arch() string {
	return runtime.GOARCH
}

func (e *Editor) Platform() string {
	return runtime.GOOS
}

func (e *Editor) Version() string {
	return "0"
}

func (e *Editor) CommandHandler() CommandHandler {
	return &e.cmdhandler
}

func (e *Editor) HandleInput(kp KeyPress) {
	e.keyInput <- kp
}

func (e *Editor) inputthread() {
	pc := 0
	var lastBindings KeyBindings
	doinput := func(kp KeyPress) {
		defer func() {
			if r := recover(); r != nil {
				log4go.Error("Panic in inputthread: %v\n%s", r, string(debug.Stack()))
				if pc > 0 {
					panic(r)
				}
				pc++
			}
		}()
		p := Prof.Enter("hi")
		defer p.Exit()

		lvl := log4go.FINE
		if e.loginput {
			lvl++
		}
		log4go.Logf(lvl, "Key: %v", kp)
		if lastBindings.keyOff == 0 {
			lastBindings = e.keyBindings
		}
	try_again:
		possible_actions := lastBindings.Filter(kp)
		lastBindings = possible_actions

		// TODO?
		var (
			wnd *Window
			v   *View
		)
		if wnd = e.ActiveWindow(); wnd != nil {
			v = wnd.ActiveView()
		}

		if action := possible_actions.Action(v); action != nil {
			p2 := Prof.Enter("hi.perform")
			e.RunCommand(action.Command, action.Args)
			p2.Exit()
		} else if possible_actions.keyOff > 1 {
			lastBindings = e.keyBindings
			goto try_again
		} else if kp.IsCharacter() {
			p2 := Prof.Enter("hi.character")
			log4go.Finest("kp: %v, pos: %v", kp, possible_actions)
			if err := e.CommandHandler().RunTextCommand(v, "insert", Args{"characters": string(rune(kp.Key))}); err != nil {
				log4go.Debug("Couldn't run textcommand: %s", err)
			}
			p2.Exit()
		}
	}
	for kp := range e.keyInput {
		doinput(kp)
	}
}

func (e *Editor) LogInput(l bool) {
	e.loginput = l
}

func (e *Editor) LogCommands(l bool) {
	e.cmdhandler.log = l
}

func (e *Editor) RunCommand(name string, args Args) {
	// TODO?
	var (
		wnd *Window
		v   *View
	)
	if wnd = e.ActiveWindow(); wnd != nil {
		v = wnd.ActiveView()
	}

	// TODO: what's the command precedence?
	if c := e.cmdhandler.TextCommands[name]; c != nil {
		if err := e.CommandHandler().RunTextCommand(v, name, args); err != nil {
			log4go.Debug("Couldn't run textcommand: %s", err)
		}
	} else if c := e.cmdhandler.WindowCommands[name]; c != nil {
		if err := e.CommandHandler().RunWindowCommand(wnd, name, args); err != nil {
			log4go.Debug("Couldn't run windowcommand: %s", err)
		}
	} else if err := e.CommandHandler().RunApplicationCommand(name, args); err != nil {
		log4go.Debug("Couldn't run applicationcommand: %s", err)
	}
}

func (e *Editor) SetClipboard(n string) {
	e.clipboard = n
}

func (e *Editor) GetClipboard() string {
	return e.clipboard
}

func (e *Editor) Watch(file Watched) {
	log4go.Finest("Watch(%v)", file)
	if err := e.watcher.Watch(file.Name()); err != nil {
		log4go.Error("Could not watch file: %v", err)
	} else {
		e.watchLock.Lock()
		defer e.watchLock.Unlock()
		e.watchedFiles[file.Name()] = file
	}
}

func (e *Editor) UnWatch(name string) {
	e.watchLock.Lock()
	defer e.watchLock.Unlock()
	if err := e.watcher.RemoveWatch(name); err != nil {
		log4go.Error("Couldn't unwatch file: %v", err)
	}
	log4go.Finest("UnWatch(%s)", name)
	delete(e.watchedFiles, name)
}

func (e *Editor) observeFiles() {
	for {
		select {
		case ev := <-e.watcher.Event:
			if ev.IsModify() {
				func() {
					e.watchLock.Lock()
					defer e.watchLock.Unlock()
					f, exist := e.watchedFiles[ev.Name]
					if exist {
						f.Reload()
					}
				}()
			}
		case err := <-e.watcher.Error:
			log4go.Error("error:", err)
		}
	}
}

func newWatcher() (w *fsnotify.Watcher) {
	w, err := fsnotify.NewWatcher()
	if err != nil {
		log4go.Error("Could not create watcher due to: %v", err)
	}
	return
}
<commit_msg>Don't fallback to running as an application command.<commit_after>// Copyright 2013 The lime Authors.
// Use of this source code is governed by a 2-clause
// BSD-style license that can be found in the LICENSE file.

package backend

import (
	"code.google.com/p/log4go"
	"fmt"
	"github.com/howeyc/fsnotify"
	"github.com/limetext/lime/backend/loaders"
	. "github.com/limetext/lime/backend/util"
	. "github.com/quarnster/util/text"
	"runtime"
	"runtime/debug"
	"sync"
)

func init() {
	runtime.GOMAXPROCS(runtime.NumCPU())
	GetEditor()
}

type (
	Editor struct {
		HasSettings
		windows       []*Window
		active_window *Window
		loginput      bool
		cmdhandler    commandHandler
		keyBindings   KeyBindings
		console       *View
		frontend      Frontend
		clipboard     string
		keyInput      chan (KeyPress)
		watcher       *fsnotify.Watcher
		watchedFiles  map[string]Watched
		watchLock     sync.Mutex
	}

	// The Frontend interface defines the API
	// for functionality that is frontend specific.
	Frontend interface {
		// Probe the frontend for the currently
		// visible region of the given view.
		VisibleRegion(v *View) Region

		// Make the frontend show the specified region of the
		// given view.
		Show(v *View, r Region)

		// Sets the status message shown in the status bar
		StatusMessage(string)

		// Displays an error message to the usser
		ErrorMessage(string)

		// Displays a message dialog to the user
		MessageDialog(string)

		// Displays an ok / cancel dialog to the user.
		// "okname" if provided will be used as the text
		// instead of "Ok" for the ok button.
		// Returns true when ok was pressed, and false when
		// cancel was pressed.
		OkCancelDialog(msg string, okname string) bool
	}
	myLogWriter struct {
		log chan string
	}
	DummyFrontend struct {
		m sync.Mutex
		// Default return value for OkCancelDialog
		defaultAction bool
	}
)

const (
	LIME_USER_PACKAGES_PATH = "../../3rdparty/bundles/"
	LIME_USER_PACKETS_PATH  = "../../3rdparty/bundles/User/"
	LIME_DEFAULTS_PATH      = "../../backend/packages/Default/"
)

func (h *DummyFrontend) SetDefaultAction(action bool) {
	h.m.Lock()
	defer h.m.Unlock()
	h.defaultAction = action
}
func (h *DummyFrontend) StatusMessage(msg string) { log4go.Info(msg) }
func (h *DummyFrontend) ErrorMessage(msg string)  { log4go.Error(msg) }
func (h *DummyFrontend) MessageDialog(msg string) { log4go.Info(msg) }
func (h *DummyFrontend) OkCancelDialog(msg string, button string) bool {
	log4go.Info(msg)
	h.m.Lock()
	defer h.m.Unlock()
	return h.defaultAction
}
func (h *DummyFrontend) Show(v *View, r Region)       {}
func (h *DummyFrontend) VisibleRegion(v *View) Region { return Region{} }

func newMyLogWriter() *myLogWriter {
	ret := &myLogWriter{make(chan string, 100)}
	go ret.handle()
	return ret
}

func (m *myLogWriter) handle() {
	for fl := range m.log {
		c := GetEditor().Console()
		f := fmt.Sprintf("%08d %d %s", c.Buffer().Size(), len(fl), fl)
		e := c.BeginEdit()
		c.Insert(e, c.Buffer().Size(), f)
		c.EndEdit(e)
	}
}

func (m *myLogWriter) LogWrite(rec *log4go.LogRecord) {
	p := Prof.Enter("log")
	defer p.Exit()
	fl := log4go.FormatLogRecord(log4go.FORMAT_DEFAULT, rec)
	m.log <- fl
}

func (m *myLogWriter) Close() {
	fmt.Println("Closing...")
	close(m.log)
}

var (
	ed  *Editor
	edl sync.Mutex
)

func GetEditor() *Editor {
	edl.Lock()
	defer edl.Unlock()
	if ed == nil {
		ed = &Editor{
			cmdhandler: commandHandler{
				ApplicationCommands: make(appcmd),
				TextCommands:        make(textcmd),
				WindowCommands:      make(wndcmd),
				verbose:             true,
			},
			frontend: &DummyFrontend{},
			console: &View{
				buffer:  NewBuffer(),
				scratch: true,
			},
			keyInput:     make(chan KeyPress, 32),
			watcher:      newWatcher(),
			watchedFiles: make(map[string]Watched),
		}
		ed.console.Settings().Set("is_widget", true)
		ed.Settings() // Just to initialize it
		log4go.Global.Close()
		log4go.Global.AddFilter("console", log4go.DEBUG, newMyLogWriter())
		go ed.inputthread()
		go ed.observeFiles()
	}
	return ed
}

func (e *Editor) Frontend() Frontend {
	return e.frontend
}

func (e *Editor) SetFrontend(f Frontend) {
	e.frontend = f
}

func (e *Editor) Init() {
	ed.loadKeybindings()
	ed.loadSettings()
}

func (e *Editor) Keybindings() *KeyBindings {
	return &e.keyBindings
}

func (e *Editor) loadKeybinding(pkg *packet) {
	var bindings KeyBindings
	if err := loaders.LoadJSON(pkg.Get().([]byte), &bindings); err != nil {
		log4go.Error(err)
	} else {
		log4go.Info("Loaded %s", pkg.Name())
		e.Watch(NewWatchedPackage(pkg))
	}
	e.keyBindings.merge(&bindings)
}

func (e *Editor) loadKeybindings() {
	for _, p := range packets.filter("keymap") {
		e.loadKeybinding(p)
	}
}

func (e *Editor) loadSetting(pkg *packet) {
	if err := loaders.LoadJSON(pkg.Get().([]byte), e.Settings()); err != nil {
		log4go.Error(err)
	} else {
		log4go.Info("Loaded %s", pkg.Name())
		e.Watch(NewWatchedPackage(pkg))
	}
}

func (e *Editor) loadSettings() {
	for _, p := range packets.filter("setting") {
		e.loadSetting(p)
	}
}

func (e *Editor) PackagesPath() string {
	return "../../3rdparty/bundles/"
}

func (e *Editor) Console() *View {
	return e.console
}

func (e *Editor) Windows() []*Window {
	edl.Lock()
	defer edl.Unlock()
	ret := make([]*Window, len(e.windows))
	copy(ret, e.windows)
	return ret
}

func (e *Editor) SetActiveWindow(w *Window) {
	e.active_window = w
}

func (e *Editor) ActiveWindow() *Window {
	return e.active_window
}

func (e *Editor) Watcher() *fsnotify.Watcher {
	return e.watcher
}

func (e *Editor) NewWindow() *Window {
	edl.Lock()
	e.windows = append(e.windows, &Window{})
	w := e.windows[len(e.windows)-1]
	edl.Unlock()
	w.Settings().SetParent(e)
	ed.SetActiveWindow(w)
	OnNewWindow.Call(w)
	return w
}

func (e *Editor) remove(w *Window) {
	edl.Lock()
	defer edl.Unlock()
	for i, ww := range e.windows {
		if w == ww {
			end := len(e.windows) - 1
			if i != end {
				copy(e.windows[i:], e.windows[i+1:])
			}
			e.windows = e.windows[:end]
			return
		}
	}
	log4go.Error("Wanted to remove window %+v, but it doesn't appear to be a child of this editor", w)
}

func (e *Editor) Arch() string {
	return runtime.GOARCH
}

func (e *Editor) Platform() string {
	return runtime.GOOS
}

func (e *Editor) Version() string {
	return "0"
}

func (e *Editor) CommandHandler() CommandHandler {
	return &e.cmdhandler
}

func (e *Editor) HandleInput(kp KeyPress) {
	e.keyInput <- kp
}

func (e *Editor) inputthread() {
	pc := 0
	var lastBindings KeyBindings
	doinput := func(kp KeyPress) {
		defer func() {
			if r := recover(); r != nil {
				log4go.Error("Panic in inputthread: %v\n%s", r, string(debug.Stack()))
				if pc > 0 {
					panic(r)
				}
				pc++
			}
		}()
		p := Prof.Enter("hi")
		defer p.Exit()

		lvl := log4go.FINE
		if e.loginput {
			lvl++
		}
		log4go.Logf(lvl, "Key: %v", kp)
		if lastBindings.keyOff == 0 {
			lastBindings = e.keyBindings
		}
	try_again:
		possible_actions := lastBindings.Filter(kp)
		lastBindings = possible_actions

		// TODO?
		var (
			wnd *Window
			v   *View
		)
		if wnd = e.ActiveWindow(); wnd != nil {
			v = wnd.ActiveView()
		}

		if action := possible_actions.Action(v); action != nil {
			p2 := Prof.Enter("hi.perform")
			e.RunCommand(action.Command, action.Args)
			p2.Exit()
		} else if possible_actions.keyOff > 1 {
			lastBindings = e.keyBindings
			goto try_again
		} else if kp.IsCharacter() {
			p2 := Prof.Enter("hi.character")
			log4go.Finest("kp: %v, pos: %v", kp, possible_actions)
			if err := e.CommandHandler().RunTextCommand(v, "insert", Args{"characters": string(rune(kp.Key))}); err != nil {
				log4go.Debug("Couldn't run textcommand: %s", err)
			}
			p2.Exit()
		}
	}
	for kp := range e.keyInput {
		doinput(kp)
	}
}

func (e *Editor) LogInput(l bool) {
	e.loginput = l
}

func (e *Editor) LogCommands(l bool) {
	e.cmdhandler.log = l
}

func (e *Editor) RunCommand(name string, args Args) {
	// TODO?
	var (
		wnd *Window
		v   *View
	)
	if wnd = e.ActiveWindow(); wnd != nil {
		v = wnd.ActiveView()
	}

	// TODO: what's the command precedence?
	if c := e.cmdhandler.TextCommands[name]; c != nil {
		if err := e.CommandHandler().RunTextCommand(v, name, args); err != nil {
			log4go.Debug("Couldn't run textcommand: %s", err)
		}
	} else if c := e.cmdhandler.WindowCommands[name]; c != nil {
		if err := e.CommandHandler().RunWindowCommand(wnd, name, args); err != nil {
			log4go.Debug("Couldn't run windowcommand: %s", err)
		}
	} else if c := e.cmdhandler.ApplicationCommands[name]; c != nil {
		if err := e.CommandHandler().RunApplicationCommand(name, args); err != nil {
			log4go.Debug("Couldn't run applicationcommand: %s", err)
		}
	} else {
		log4go.Debug("Couldn't find command to run")
	}
}

func (e *Editor) SetClipboard(n string) {
	e.clipboard = n
}

func (e *Editor) GetClipboard() string {
	return e.clipboard
}

func (e *Editor) Watch(file Watched) {
	log4go.Finest("Watch(%v)", file)
	if err := e.watcher.Watch(file.Name()); err != nil {
		log4go.Error("Could not watch file: %v", err)
	} else {
		e.watchLock.Lock()
		defer e.watchLock.Unlock()
		e.watchedFiles[file.Name()] = file
	}
}

func (e *Editor) UnWatch(name string) {
	e.watchLock.Lock()
	defer e.watchLock.Unlock()
	if err := e.watcher.RemoveWatch(name); err != nil {
		log4go.Error("Couldn't unwatch file: %v", err)
	}
	log4go.Finest("UnWatch(%s)", name)
	delete(e.watchedFiles, name)
}

func (e *Editor) observeFiles() {
	for {
		select {
		case ev := <-e.watcher.Event:
			if ev.IsModify() {
				func() {
					e.watchLock.Lock()
					defer e.watchLock.Unlock()
					f, exist := e.watchedFiles[ev.Name]
					if exist {
						f.Reload()
					}
				}()
			}
		case err := <-e.watcher.Error:
			log4go.Error("error:", err)
		}
	}
}

func newWatcher() (w *fsnotify.Watcher) {
	w, err := fsnotify.NewWatcher()
	if err != nil {
		log4go.Error("Could not create watcher due to: %v", err)
	}
	return
}
<|endoftext|>


<commit_before>package mpb

import (
	"io"

	"github.com/vbauerster/mpb/v8/decor"
)

// NopStyle provides BarFillerBuilder which builds NOP BarFiller.
func NopStyle() BarFillerBuilder {
	return BarFillerBuilderFunc(func() BarFiller {
		return BarFillerFunc(func(io.Writer, decor.Statistics) {})
	})
}
<commit_msg>refactoring: nop filler<commit_after>package mpb

import (
	"io"

	"github.com/vbauerster/mpb/v8/decor"
)

// NopStyle provides BarFillerBuilder which builds NOP BarFiller.
func NopStyle() BarFillerBuilder {
	return BarFillerBuilderFunc(func() BarFiller {
		return BarFillerFunc(func(io.Writer, decor.Statistics) error {
			return nil
		})
	})
}
<|endoftext|>


<commit_before>/*

Package behaviors defines a handful of convenient behaviors that can be embedded
into your SubState (e.g. gameState and playerState) structs.

A behavior is a combination of persistable properties, as well as methods that
mutate those properties. They encapsulate commonly required behavior, like
setting current player or round robin properties. Think of them like lego bricks
you can add to your game and player states.

Behaviors often require access to the struct they're embedded within, so their
ConnectBehavior should always be called within the subState's
ConnectContainingState, like so:

    func (g *gameState) ConnectContainingState(state boardgame.State, ref boardgame.StatePropertyRef, containingStruct boardgame.SubState) {
        g.RoundRobinBehavior.ConnectBehavior(containingStruct)

        //If you didn't have any embedded behaviors, your gameState would use ConnectContainingState
        //on SubState directly. But because we need to override that to connect up RoundRobinBehavior,
        //we need to explicitly call it.
        g.SubState.ConnectContainingState(state, ref)
    }

*/
package behaviors

import "github.com/jkomoros/boardgame"

//Interface is the interface that all behaviors must implement
type Interface interface {
	ConnectBehavior(containgSubState boardgame.SubState)
}
<commit_msg>Changed the example of how to pass the containingStruct to a behavior, to instead just pass self.<commit_after>/*

Package behaviors defines a handful of convenient behaviors that can be embedded
into your SubState (e.g. gameState and playerState) structs.

A behavior is a combination of persistable properties, as well as methods that
mutate those properties. They encapsulate commonly required behavior, like
setting current player or round robin properties. Think of them like lego bricks
you can add to your game and player states.

Behaviors often require access to the struct they're embedded within, so their
ConnectBehavior should always be called within the subState's
ConnectContainingState, like so:

    func (g *gameState) ConnectContainingState(state boardgame.State, ref boardgame.StatePropertyRef) {
        g.RoundRobin.ConnectBehavior(g)

        //If you didn't have any embedded behaviors, your gameState would use ConnectContainingState
        //on SubState directly. But because we need to override that to connect up RoundRobinBehavior,
        //we need to explicitly call it.
        g.SubState.ConnectContainingState(state, ref)
    }

*/
package behaviors

import "github.com/jkomoros/boardgame"

//Interface is the interface that all behaviors must implement
type Interface interface {
	//ConnectBehavior lets the behavior have a reference to the struct its
	//embedded in, as some behaviors need access to the broader state.
	ConnectBehavior(containgSubState boardgame.SubState)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"html/template"
	"net/http"
	"path/filepath"

	"github.com/gorilla/mux"
	"github.com/libgit2/git2go"
)

type SuchGit struct {
	RepoRoot string
	Tpl      *template.Template
	Router   *mux.Router
}

func NewSuchGit(repoRoot string) *SuchGit {
	sg := new(SuchGit)
	sg.RepoRoot = repoRoot
	sg.Setup()
	return sg
}

func (sg *SuchGit) Setup() {
	var err error
	sg.Tpl, err = template.ParseFiles(
		"_templates/header.html",
		"_templates/footer.html",
		"_templates/error.html",
		"_templates/blob.html",
		"_templates/tree.html",
		"_templates/repos.html",
		"_templates/repo.html")
	if err != nil {
		panic(err)
	}

	sg.Router = mux.NewRouter()
	sg.Router.HandleFunc("/", sg.HandleIndex)
	sg.Router.HandleFunc("/{repo}/blob/{ref}/{file}", sg.HandleBlob)
	sg.Router.HandleFunc("/{repo}/blob/{file}", sg.HandleBlob) // defaults to ref=head
	sg.Router.HandleFunc("/{repo}/tree/{ref}/{folder}", sg.HandleTree)
	sg.Router.HandleFunc("/{repo}/tree/{ref}", sg.HandleTree) // defaults to tree=/
	sg.Router.HandleFunc("/{repo}/tree/", sg.HandleTree)      // defaults to ref=head
	sg.Router.HandleFunc("/{repo}", sg.HandleTree)            // same as above
	sg.Router.HandleFunc("/{repo}/blob/{ref}/{file}", sg.HandleBlob)
	sg.Router.HandleFunc("/{repo}/blob/{file}", sg.HandleBlob) // defaults to ref=head
	sg.Router.HandleFunc("/{repo}/commits/{ref}", sg.HandleCommits)
	sg.Router.HandleFunc("/{repo}/commits", sg.HandleCommits) // defaults to ref=head
	sg.Router.HandleFunc("/{repo}/commit/{ref}", sg.HandleCommit)
	sg.Router.HandleFunc("/{repo}/commit", sg.HandleCommit) // defaults to ref=head
	// --- TESTING ---
	sg.Router.HandleFunc("/test/{repo}/file/{commit}/{filename}", sg.TestFileHandler)
	sg.Router.HandleFunc("/test/{repo}/diff/{id1}/{id2}", sg.TestDiffHandler)
	sg.Router.HandleFunc("/test/{repo}/{ref}", sg.TestHandler)
	sg.Router.HandleFunc("/test/{repo}", sg.TestHandler)
}

func (sg *SuchGit) ShowError(w http.ResponseWriter, err error) {
	err_ := sg.Tpl.ExecuteTemplate(w, "error.html", err)
	if err_ != nil {
		fmt.Fprintf(w, "Error: %s", err_)
		fmt.Fprintf(w, "From Error: %s", err)
	}
}

func (sg *SuchGit) ListRepositories() []string {
	repos, err := filepath.Glob(filepath.Join(sg.RepoRoot, "*.git"))
	if err != nil {
		return make([]string, 0)
	}
	for i, repo := range repos {
		repos[i] = filepath.Base(repo)
	}
	return repos
}

func (sg *SuchGit) HandleIndex(w http.ResponseWriter, r *http.Request) {
	repos := sg.ListRepositories()
	err := sg.Tpl.ExecuteTemplate(w, "repos.html", repos)
	if err != nil {
		fmt.Fprintf(w, "Error: %s", err)
	}
}

func (sg *SuchGit) HandleBlob(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	repoName := vars["repo"]
	repo, err := git.OpenRepository(filepath.Join(sg.RepoRoot, repoName))
	if err != nil {
		sg.ShowError(w, err)
		return
	}
	var oid *git.Oid
	refName, set := vars["ref"]
	if set {
		oid, err = git.NewOid(refName)
		if err != nil { // It's a reference!
			ref, err := repo.DwimReference(refName)
			if err != nil {
				sg.ShowError(w, err)
				return
			}
			oid = ref.Target()
		}
	} else {
		ref, err := repo.Head()
		if err != nil {
			sg.ShowError(w, err)
			return
		}
		oid = ref.Target()
	}
	commit, err := repo.LookupCommit(oid)
	if err != nil {
		sg.ShowError(w, err)
		return
	}
	tree, err := commit.Tree()
	if err != nil {
		sg.ShowError(w, err)
		return
	}
	fileEntry, err := tree.EntryByPath(vars["file"])
	if err != nil {
		sg.ShowError(w, err)
		return
	}
	if fileEntry.Type != git.ObjectBlob {
		fmt.Fprintf(w, "File has to be blob!\n")
		return
	}
	oid = fileEntry.Id
	file, err := repo.LookupBlob(oid)
	if err != nil {
		fmt.Fprintf(w, "326 Error: %s\n", err)
		return
	}
	sg.Tpl.ExecuteTemplate(w, "blob.html", string(file.Contents()))
}

func (sg *SuchGit) HandleTree(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	repoName := vars["repo"]
	refName, set := vars["ref"]
	if !set {
		refName = "master"
	}
	folderName, set := vars["folder"]
	if !set {
		folderName = ""
	}

	repo, err := git.OpenRepository(filepath.Join(sg.RepoRoot, repoName))
	if err != nil {
		sg.ShowError(w, err)
		return
	}

	ref, err := repo.DwimReference(refName)
	if err != nil {
		sg.ShowError(w, err)
		return
	}

	oid := ref.Target()
	commit, err := repo.LookupCommit(oid)
	if err != nil {
		sg.ShowError(w, err)
		return
	}

	folder, err := commit.Tree()
	if err != nil {
		sg.ShowError(w, err)
		return
	}

	if folderName != "" {
		folderEntry, err := folder.EntryByPath(folderName)
		if err != nil {
			sg.ShowError(w, err)
			return
		}
		oid = folderEntry.Id
		folder, err = repo.LookupTree(oid)
		if err != nil {
			sg.ShowError(w, err)
			return
		}
	}

	count := folder.EntryCount()
	files := make([]string, 0, count)
	for i := uint64(0); i < count; i++ {
		files = append(files, folder.EntryByIndex(i).Name)
	}

	resp := TreeResponse{RepositoryResponse{repoName, refName, make([]string, 0), commit}, folderName, files}
	err = sg.Tpl.ExecuteTemplate(w, "tree.html", resp)
	if err != nil {
		sg.ShowError(w, err)
	}
}

func (sg *SuchGit) HandleCommits(w http.ResponseWriter, r *http.Request) {}

func (sg *SuchGit) HandleCommit(w http.ResponseWriter, r *http.Request) {}

func (sg *SuchGit) TestHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	repoName := vars["repo"]
	repo, err := git.OpenRepository(filepath.Join(sg.RepoRoot, repoName+".git"))
	if err != nil {
		fmt.Fprintf(w, "Error: %s\n", err)
		return
	}

	refName, refSet := vars["ref"]
	if refSet {
		ref, err := repo.DwimReference(refName)
		if err != nil {
			fmt.Fprintf(w, "Error: %s\n", err)
			return
		}
		fmt.Fprintf(w, "%s (%s)\n", ref.Shorthand(), ref.Name())
		oid := ref.Target()
		commit, err := repo.LookupCommit(oid)
		if err != nil {
			fmt.Fprintf(w, "Error: %s\n", err)
			return
		}
		for ; commit.ParentCount() > 0; commit = commit.Parent(0) {
			fmt.Fprintf(w, "[%s]\n%s\n\n", commit.Id().String(), commit.Message())
		}
	} else {
		refit, err := repo.NewReferenceIterator()
		if err != nil {
			fmt.Fprintf(w, "Error: %s\n", err)
			return
		}
		head, err := repo.Head()
		if err != nil {
			fmt.Fprintf(w, "Error: %s\n", err)
			return
		}
		for {
			ref, err := refit.Next()
			if err != nil {
				break // end of iterator
			}
			if ref.Name() == head.Name() {
				fmt.Fprintf(w, "*")
			} else {
				fmt.Fprintf(w, " ")
			}
			if ref.IsBranch() {
				fmt.Fprintf(w, "[Branch]")
			} else if ref.IsTag() {
				fmt.Fprintf(w, "[Tag]   ")
			} else if ref.IsRemote() {
				fmt.Fprintf(w, "[Remote]")
			} else {
				fmt.Fprintf(w, "--------")
			}
			fmt.Fprintf(w, " %25s (%s)\n", ref.Shorthand(), ref.Name())
		}

	}
}

func (sg *SuchGit) TestDiffHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	repoName := vars["repo"]
	repo, err := git.OpenRepository(filepath.Join(sg.RepoRoot, repoName+".git"))
	if err != nil {
		fmt.Fprintf(w, "Error: %s\n", err)
		return
	}

	id1, err := git.NewOid(vars["id1"])
	if err != nil {
		fmt.Fprintf(w, "Error: %s\n", err)
		return
	}
	commit1, err := repo.LookupCommit(id1)
	if err != nil {
		fmt.Fprintf(w, "Error: %s\n", err)
		return
	}
	tree1, err := commit1.Tree()
	if err != nil {
		fmt.Fprintf(w, "Error: %s\n", err)
		return
	}
	//id2, err := git.NewOid(vars["id2"])
	//if err != nil {
	//	fmt.Fprintf(w, "Error: %s\n", err)
	//	return
	//}
	//commit2, err := repo.LookupCommit(id2)
	//if err != nil {
	//	fmt.Fprintf(w, "Error: %s\n", err)
	//	return
	//}
	//tree2, err := commit2.Tree()
	//if err != nil {
	//	fmt.Fprintf(w, "Error: %s\n", err)
	//	return
	//}
	defaultDiffOptions, err := git.DefaultDiffOptions()
	if err != nil {
		fmt.Fprintf(w, "Error: %s\n", err)
		return
	}
	diff, err := repo.DiffTreeToTree(nil, tree1, &defaultDiffOptions)
	if err != nil {
		fmt.Fprintf(w, "Error: %s\n", err)
		return
	}
	deltas, err := diff.NumDeltas()
	if err != nil {
		fmt.Fprintf(w, "Error: %s\n", err)
		return
	}
	for i := 0; i < deltas; i++ {
		patch, err := diff.Patch(i)
		if err != nil {
			fmt.Fprintf(w, "Error: %s\n", err)
			return
		}
		patchString, err := patch.String()
		if err != nil {
			fmt.Fprintf(w, "Error: %s\n", err)
			return
		}
		fmt.Fprintf(w, "%s\n", patchString)
	}
}

func (sg *SuchGit) TestFileHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	repoName := vars["repo"]
	repo, err := git.OpenRepository(filepath.Join(sg.RepoRoot, repoName+".git"))
	if err != nil {
		fmt.Fprintf(w, "Error: %s\n", err)
		return
	}

	id1, err := git.NewOid(vars["commit"])
	if err != nil {
		fmt.Fprintf(w, "Error: %s\n", err)
		return
	}
	commit1, err := repo.LookupCommit(id1)
	if err != nil {
		fmt.Fprintf(w, "Error: %s\n", err)
		return
	}
	tree1, err := commit1.Tree()
	if err != nil {
		fmt.Fprintf(w, "Error: %s\n", err)
		return
	}
	fileEntry, err := tree1.EntryByPath(vars["filename"])
	if err != nil {
		fmt.Fprintf(w, "Error: %s\n", err)
		return
	}
	if fileEntry.Type != git.ObjectBlob {
		fmt.Fprintf(w, "File has to be blob!\n")
		return
	}
	oid := fileEntry.Id
	file, err := repo.LookupBlob(oid)
	if err != nil {
		fmt.Fprintf(w, "326 Error: %s\n", err)
		return
	}
	fmt.Fprintf(w, "
%s
\n", file.Contents())
}
<commit_msg>Add ability to have file paths to arbitrary depth.<commit_after>package main

import (
	"fmt"
	"html/template"
	"net/http"
	"path/filepath"

	"github.com/gorilla/mux"
	"github.com/libgit2/git2go"
)

type SuchGit struct {
	RepoRoot string
	Tpl      *template.Template
	Router   *mux.Router
}

func NewSuchGit(repoRoot string) *SuchGit {
	sg := new(SuchGit)
	sg.RepoRoot = repoRoot
	sg.Setup()
	return sg
}

func (sg *SuchGit) Setup() {
	var err error
	sg.Tpl, err = template.ParseFiles(
		"_templates/header.html",
		"_templates/footer.html",
		"_templates/error.html",
		"_templates/blob.html",
		"_templates/tree.html",
		"_templates/repos.html",
		"_templates/repo.html")
	if err != nil {
		panic(err)
	}

	sg.Router = mux.NewRouter()
	sg.Router.HandleFunc("/", sg.HandleIndex)
	sg.Router.HandleFunc("/{repo}/blob/{ref}/{file:.*}", sg.HandleBlob)
	sg.Router.HandleFunc("/{repo}/blob/{file:.*}", sg.HandleBlob) // defaults to ref=head
	sg.Router.HandleFunc("/{repo}/tree/{ref}/{folder:.*}", sg.HandleTree)
	sg.Router.HandleFunc("/{repo}/tree/{ref}", sg.HandleTree) // defaults to tree=/
	sg.Router.HandleFunc("/{repo}/tree/", sg.HandleTree)      // defaults to ref=head
	sg.Router.HandleFunc("/{repo}", sg.HandleTree)            // same as above
	sg.Router.HandleFunc("/{repo}/blob/{ref}/{file}", sg.HandleBlob)
	sg.Router.HandleFunc("/{repo}/blob/{file}", sg.HandleBlob) // defaults to ref=head
	sg.Router.HandleFunc("/{repo}/commits/{ref}", sg.HandleCommits)
	sg.Router.HandleFunc("/{repo}/commits", sg.HandleCommits) // defaults to ref=head
	sg.Router.HandleFunc("/{repo}/commit/{ref}", sg.HandleCommit)
	sg.Router.HandleFunc("/{repo}/commit", sg.HandleCommit) // defaults to ref=head
	// --- TESTING ---
	sg.Router.HandleFunc("/test/{repo}/file/{commit}/{filename}", sg.TestFileHandler)
	sg.Router.HandleFunc("/test/{repo}/diff/{id1}/{id2}", sg.TestDiffHandler)
	sg.Router.HandleFunc("/test/{repo}/{ref}", sg.TestHandler)
	sg.Router.HandleFunc("/test/{repo}", sg.TestHandler)
}

func (sg *SuchGit) ShowError(w http.ResponseWriter, err error) {
	err_ := sg.Tpl.ExecuteTemplate(w, "error.html", err)
	if err_ != nil {
		fmt.Fprintf(w, "Error: %s", err_)
		fmt.Fprintf(w, "From Error: %s", err)
	}
}

func (sg *SuchGit) ListRepositories() []string {
	repos, err := filepath.Glob(filepath.Join(sg.RepoRoot, "*.git"))
	if err != nil {
		return make([]string, 0)
	}
	for i, repo := range repos {
		repos[i] = filepath.Base(repo)
	}
	return repos
}

func (sg *SuchGit) HandleIndex(w http.ResponseWriter, r *http.Request) {
	repos := sg.ListRepositories()
	err := sg.Tpl.ExecuteTemplate(w, "repos.html", repos)
	if err != nil {
		fmt.Fprintf(w, "Error: %s", err)
	}
}

func (sg *SuchGit) HandleBlob(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	repoName := vars["repo"]
	repo, err := git.OpenRepository(filepath.Join(sg.RepoRoot, repoName))
	if err != nil {
		sg.ShowError(w, err)
		return
	}
	var oid *git.Oid
	refName, set := vars["ref"]
	if set {
		oid, err = git.NewOid(refName)
		if err != nil { // It's a reference!
			ref, err := repo.DwimReference(refName)
			if err != nil {
				sg.ShowError(w, err)
				return
			}
			oid = ref.Target()
		}
	} else {
		ref, err := repo.Head()
		if err != nil {
			sg.ShowError(w, err)
			return
		}
		oid = ref.Target()
	}
	commit, err := repo.LookupCommit(oid)
	if err != nil {
		sg.ShowError(w, err)
		return
	}
	tree, err := commit.Tree()
	if err != nil {
		sg.ShowError(w, err)
		return
	}
	fileEntry, err := tree.EntryByPath(vars["file"])
	if err != nil {
		sg.ShowError(w, err)
		return
	}
	if fileEntry.Type != git.ObjectBlob {
		fmt.Fprintf(w, "File has to be blob!\n")
		return
	}
	oid = fileEntry.Id
	file, err := repo.LookupBlob(oid)
	if err != nil {
		fmt.Fprintf(w, "326 Error: %s\n", err)
		return
	}
	sg.Tpl.ExecuteTemplate(w, "blob.html", string(file.Contents()))
}

func (sg *SuchGit) HandleTree(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	repoName := vars["repo"]
	refName, set := vars["ref"]
	if !set {
		refName = "master"
	}
	folderName, set := vars["folder"]
	if !set {
		folderName = ""
	}

	repo, err := git.OpenRepository(filepath.Join(sg.RepoRoot, repoName))
	if err != nil {
		sg.ShowError(w, err)
		return
	}

	ref, err := repo.DwimReference(refName)
	if err != nil {
		sg.ShowError(w, err)
		return
	}

	oid := ref.Target()
	commit, err := repo.LookupCommit(oid)
	if err != nil {
		sg.ShowError(w, err)
		return
	}

	folder, err := commit.Tree()
	if err != nil {
		sg.ShowError(w, err)
		return
	}

	if folderName != "" {
		folderEntry, err := folder.EntryByPath(folderName)
		if err != nil {
			sg.ShowError(w, err)
			return
		}
		oid = folderEntry.Id
		folder, err = repo.LookupTree(oid)
		if err != nil {
			sg.ShowError(w, err)
			return
		}
	}

	count := folder.EntryCount()
	files := make([]string, 0, count)
	for i := uint64(0); i < count; i++ {
		files = append(files, folder.EntryByIndex(i).Name)
	}

	resp := TreeResponse{RepositoryResponse{repoName, refName, make([]string, 0), commit}, folderName, files}
	err = sg.Tpl.ExecuteTemplate(w, "tree.html", resp)
	if err != nil {
		sg.ShowError(w, err)
	}
}

func (sg *SuchGit) HandleCommits(w http.ResponseWriter, r *http.Request) {}

func (sg *SuchGit) HandleCommit(w http.ResponseWriter, r *http.Request) {}

func (sg *SuchGit) TestHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	repoName := vars["repo"]
	repo, err := git.OpenRepository(filepath.Join(sg.RepoRoot, repoName+".git"))
	if err != nil {
		fmt.Fprintf(w, "Error: %s\n", err)
		return
	}

	refName, refSet := vars["ref"]
	if refSet {
		ref, err := repo.DwimReference(refName)
		if err != nil {
			fmt.Fprintf(w, "Error: %s\n", err)
			return
		}
		fmt.Fprintf(w, "%s (%s)\n", ref.Shorthand(), ref.Name())
		oid := ref.Target()
		commit, err := repo.LookupCommit(oid)
		if err != nil {
			fmt.Fprintf(w, "Error: %s\n", err)
			return
		}
		for ; commit.ParentCount() > 0; commit = commit.Parent(0) {
			fmt.Fprintf(w, "[%s]\n%s\n\n", commit.Id().String(), commit.Message())
		}
	} else {
		refit, err := repo.NewReferenceIterator()
		if err != nil {
			fmt.Fprintf(w, "Error: %s\n", err)
			return
		}
		head, err := repo.Head()
		if err != nil {
			fmt.Fprintf(w, "Error: %s\n", err)
			return
		}
		for {
			ref, err := refit.Next()
			if err != nil {
				break // end of iterator
			}
			if ref.Name() == head.Name() {
				fmt.Fprintf(w, "*")
			} else {
				fmt.Fprintf(w, " ")
			}
			if ref.IsBranch() {
				fmt.Fprintf(w, "[Branch]")
			} else if ref.IsTag() {
				fmt.Fprintf(w, "[Tag]   ")
			} else if ref.IsRemote() {
				fmt.Fprintf(w, "[Remote]")
			} else {
				fmt.Fprintf(w, "--------")
			}
			fmt.Fprintf(w, " %25s (%s)\n", ref.Shorthand(), ref.Name())
		}

	}
}

func (sg *SuchGit) TestDiffHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	repoName := vars["repo"]
	repo, err := git.OpenRepository(filepath.Join(sg.RepoRoot, repoName+".git"))
	if err != nil {
		fmt.Fprintf(w, "Error: %s\n", err)
		return
	}

	id1, err := git.NewOid(vars["id1"])
	if err != nil {
		fmt.Fprintf(w, "Error: %s\n", err)
		return
	}
	commit1, err := repo.LookupCommit(id1)
	if err != nil {
		fmt.Fprintf(w, "Error: %s\n", err)
		return
	}
	tree1, err := commit1.Tree()
	if err != nil {
		fmt.Fprintf(w, "Error: %s\n", err)
		return
	}
	//id2, err := git.NewOid(vars["id2"])
	//if err != nil {
	//	fmt.Fprintf(w, "Error: %s\n", err)
	//	return
	//}
	//commit2, err := repo.LookupCommit(id2)
	//if err != nil {
	//	fmt.Fprintf(w, "Error: %s\n", err)
	//	return
	//}
	//tree2, err := commit2.Tree()
	//if err != nil {
	//	fmt.Fprintf(w, "Error: %s\n", err)
	//	return
	//}
	defaultDiffOptions, err := git.DefaultDiffOptions()
	if err != nil {
		fmt.Fprintf(w, "Error: %s\n", err)
		return
	}
	diff, err := repo.DiffTreeToTree(nil, tree1, &defaultDiffOptions)
	if err != nil {
		fmt.Fprintf(w, "Error: %s\n", err)
		return
	}
	deltas, err := diff.NumDeltas()
	if err != nil {
		fmt.Fprintf(w, "Error: %s\n", err)
		return
	}
	for i := 0; i < deltas; i++ {
		patch, err := diff.Patch(i)
		if err != nil {
			fmt.Fprintf(w, "Error: %s\n", err)
			return
		}
		patchString, err := patch.String()
		if err != nil {
			fmt.Fprintf(w, "Error: %s\n", err)
			return
		}
		fmt.Fprintf(w, "%s\n", patchString)
	}
}

func (sg *SuchGit) TestFileHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	repoName := vars["repo"]
	repo, err := git.OpenRepository(filepath.Join(sg.RepoRoot, repoName+".git"))
	if err != nil {
		fmt.Fprintf(w, "Error: %s\n", err)
		return
	}

	id1, err := git.NewOid(vars["commit"])
	if err != nil {
		fmt.Fprintf(w, "Error: %s\n", err)
		return
	}
	commit1, err := repo.LookupCommit(id1)
	if err != nil {
		fmt.Fprintf(w, "Error: %s\n", err)
		return
	}
	tree1, err := commit1.Tree()
	if err != nil {
		fmt.Fprintf(w, "Error: %s\n", err)
		return
	}
	fileEntry, err := tree1.EntryByPath(vars["filename"])
	if err != nil {
		fmt.Fprintf(w, "Error: %s\n", err)
		return
	}
	if fileEntry.Type != git.ObjectBlob {
		fmt.Fprintf(w, "File has to be blob!\n")
		return
	}
	oid := fileEntry.Id
	file, err := repo.LookupBlob(oid)
	if err != nil {
		fmt.Fprintf(w, "326 Error: %s\n", err)
		return
	}
	fmt.Fprintf(w, "
%s
\n", file.Contents())
}
<|endoftext|>


<commit_before>// Copyright (c) 2014 Datacratic. All rights reserved.

package metric

import (
	"reflect"
	"time"
)

// Metrics represents the aggregation of a set of metrics over a period of time.
type Metrics struct {
	// Keys contains the current set of metrics.
	Keys map[string]Metric
	// Hits contains the number of accumulated samples.
	Hits int
}

// Summary represents multiple aggregations of metrics over a period of time.
type Summary struct {
	// Name contains a friendly identifier for this set of metrics.
	Name string
	// Data contains a collection of named metrics.
	Data map[string]*Metrics
	// Send contains a sequential number of that summary based on the number of times it was published by the monitor.
	Send int
	// Time contains the time stamp of the summary publication.
	Time time.Time
	// Step contains the duration of the aggreation period.
	Step time.Duration
}

// Record uses reflection to create and aggregate metrics based on their data type.
func (summary *Summary) Record(name string, data interface{}) {
	item, ok := summary.Data[name]
	if !ok {
		item = new(Metrics)
		item.Keys = make(map[string]Metric)
		summary.Data[name] = item
	}

	item.Hits++
	recordMembers(reflect.ValueOf(data).Elem(), item.Keys)
}

func recordMembers(value reflect.Value, keys map[string]Metric) {
	t := value.Type()

	for i := 0; i < t.NumField(); i++ {
		f := t.Field(i)
		v := value.Field(i)
		k := v.Kind()

		m, ok := keys[f.Name]
		if !ok {
			switch v.Interface().(type) {
			case bool:
				m = new(Bool)
			case int:
				m = new(Int)
			case float64:
				m = new(Float)
			case time.Duration:
				m = new(Duration)
			case string:
				m = &String{
					Items: make(map[string]int),
				}
			default:
				switch {
				case k == reflect.Map:
					m = &Map{
						Items: make(map[string]map[string]Metric),
					}
				default:
					continue
				}
			}

			keys[f.Name] = m
		}

		m.Record(v.Interface())
	}
}
<commit_msg>summary now properly dereferences ptrs when processing metrics.<commit_after>// Copyright (c) 2014 Datacratic. All rights reserved.

package metric

import (
	"reflect"
	"time"
)

// Metrics represents the aggregation of a set of metrics over a period of time.
type Metrics struct {
	// Keys contains the current set of metrics.
	Keys map[string]Metric
	// Hits contains the number of accumulated samples.
	Hits int
}

// Summary represents multiple aggregations of metrics over a period of time.
type Summary struct {
	// Name contains a friendly identifier for this set of metrics.
	Name string
	// Data contains a collection of named metrics.
	Data map[string]*Metrics
	// Send contains a sequential number of that summary based on the number of times it was published by the monitor.
	Send int
	// Time contains the time stamp of the summary publication.
	Time time.Time
	// Step contains the duration of the aggreation period.
	Step time.Duration
}

// Record uses reflection to create and aggregate metrics based on their data type.
func (summary *Summary) Record(name string, data interface{}) {
	item, ok := summary.Data[name]
	if !ok {
		item = new(Metrics)
		item.Keys = make(map[string]Metric)
		summary.Data[name] = item
	}

	item.Hits++
	recordMembers(reflect.ValueOf(data).Elem(), item.Keys)
}

func recordMembers(value reflect.Value, keys map[string]Metric) {
	t := value.Type()

	if t.Kind() == reflect.Ptr {
		recordMembers(value.Elem(), keys)
		return
	}

	for i := 0; i < t.NumField(); i++ {
		f := t.Field(i)
		v := value.Field(i)
		k := v.Kind()

		m, ok := keys[f.Name]
		if !ok {
			switch v.Interface().(type) {
			case bool:
				m = new(Bool)
			case int:
				m = new(Int)
			case float64:
				m = new(Float)
			case time.Duration:
				m = new(Duration)
			case string:
				m = &String{
					Items: make(map[string]int),
				}
			default:
				switch {
				case k == reflect.Map:
					m = &Map{
						Items: make(map[string]map[string]Metric),
					}
				default:
					continue
				}
			}

			keys[f.Name] = m
		}

		m.Record(v.Interface())
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"crypto/md5"
	"encoding/hex"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"mime/multipart"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/julienschmidt/httprouter"
)

type config struct {
	ApiKey               string
	UploadUnknownSamples bool
	HTTPBinding          string
}

type VTResponse struct {
	ResponseCode int    `json:"response_code"`
	ScanId       string `json:"scan_id"`
	VerboseMsg   string `json:"verbose_msg"`
}

var (
	conf   = &config{}
	client = &http.Client{}
	info   *log.Logger
)

func main() {
	var (
		err      error
		confPath string
	)

	// setup logging
	info = log.New(os.Stdout, "", log.Ltime|log.Lshortfile)

	// load config
	flag.StringVar(&confPath, "config", "", "Path to the config file")
	flag.Parse()

	if confPath == "" {
		confPath, _ = filepath.Abs(filepath.Dir(os.Args[0]))
		confPath += "/service.conf"
	}

	conf := &config{}
	cfile, _ := os.Open(confPath)
	if err = json.NewDecoder(cfile).Decode(&conf); err != nil {
		log.Println("Couldn't decode config file without errors!", err.Error())
		return
	}

	// validate ApiKey
	_, err = hex.DecodeString(conf.ApiKey)
	if len(conf.ApiKey) != 64 || err != nil {
		log.Println("Apikey seems to be invalid! Please supply a valid key!")
		return
	}

	info.Println("Start listening", conf.HTTPBinding)

	router := httprouter.New()
	router.GET("/:file", handler)
	log.Fatal(http.ListenAndServe(conf.HTTPBinding, router))
}

func NotFound(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	info.Println("NotFound")
	http.NotFound(w, r)
}

func InternalServerError(w http.ResponseWriter, r *http.Request, err error) {
	info.Println("Error: ", err.Error())

	w.WriteHeader(http.StatusInternalServerError)
	fmt.Fprint(w, "500 - "+err.Error())
}

func handler(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	f := "/tmp/" + ps.ByName("file")
	if _, err := os.Stat(f); os.IsNotExist(err) {
		http.NotFound(w, r)
		return
	}

	info.Println("Handling", f)

	hash, err := CalculateMD5(f)
	if err != nil {
		InternalServerError(w, r, err)
		return
	}

	result, err := vtWork(fmt.Sprintf("%x", hash), f)
	if err != nil {
		InternalServerError(w, r, err)
		return
	}

	info.Println("Done!")
	fmt.Fprint(w, result)
}

func vtWork(hash, fPath string) (string, error) {
	report, err := getReport(hash)
	if err != nil {
		return "", err
	}

	vtr := &VTResponse{}
	if err := json.Unmarshal(report, vtr); err != nil {
		return "", err
	}

	// 0 = unknwon
	// 1 = found
	// 2 = processing
	if vtr.ResponseCode == 0 && conf.UploadUnknownSamples {
		hash, err = uploadSample(fPath)
		if err != nil {
			return "", err
		}

		vtr.ResponseCode = 2
	}

	if vtr.ResponseCode == 2 {
		info.Println("Not done, sleep for 5min")
		time.Sleep(time.Minute * 5)
		return vtWork(hash, fPath)
	}

	return string(report), nil
}

func CalculateMD5(filePath string) ([]byte, error) {
	var result []byte
	file, err := os.Open(filePath)
	if err != nil {
		return result, err
	}
	defer file.Close()

	hash := md5.New()
	if _, err := io.Copy(hash, file); err != nil {
		return result, err
	}

	return hash.Sum(result), nil
}

func getReport(md5 string) ([]byte, error) {
	info.Println("getReport")

	var respBody []byte

	form := url.Values{}
	form.Add("resource", md5)
	form.Add("apikey", conf.ApiKey)

	req, err := http.NewRequest("POST", "https://www.virustotal.com/vtapi/v2/file/report", strings.NewReader(form.Encode()))
	req.PostForm = form
	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")

	resp, err := client.Do(req)
	if err != nil {
		return respBody, err
	}
	defer resp.Body.Close()

	respBody, err = ioutil.ReadAll(resp.Body)
	if err != nil {
		return respBody, err
	}

	info.Println(string(respBody))

	return respBody, nil
}

func uploadSample(fPath string) (string, error) {
	info.Println("uploadSample")

	file, err := os.Open(fPath)
	if err != nil {
		return "", err
	}
	defer file.Close()

	body := new(bytes.Buffer)
	writer := multipart.NewWriter(body)
	part, err := writer.CreateFormFile("file", filepath.Base(fPath))
	if err != nil {
		return "", err
	}
	_, err = io.Copy(part, file)

	err = writer.WriteField("apikey", conf.ApiKey)
	if err != nil {
		return "", err
	}

	err = writer.Close()
	if err != nil {
		return "", err
	}

	request, err := http.NewRequest("POST", "https://www.virustotal.com/vtapi/v2/file/scan", body)
	if err != nil {
		return "", err
	}
	request.Header.Add("Content-Type", writer.FormDataContentType())

	resp, err := client.Do(request)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()

	if resp.StatusCode != 200 {
		return "", err
	}

	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}

	vtr := &VTResponse{}
	if err := json.Unmarshal(respBody, vtr); err != nil {
		return "", err
	}

	if vtr.ResponseCode != 1 {
		return "", errors.New(vtr.VerboseMsg)
	}

	info.Println(string(respBody))

	return vtr.ScanId, nil
}
<commit_msg>added more debug output<commit_after>package main

import (
	"bytes"
	"crypto/md5"
	"encoding/hex"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"mime/multipart"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/julienschmidt/httprouter"
)

type config struct {
	ApiKey               string
	UploadUnknownSamples bool
	HTTPBinding          string
}

type VTResponse struct {
	ResponseCode int    `json:"response_code"`
	ScanId       string `json:"scan_id"`
	VerboseMsg   string `json:"verbose_msg"`
}

var (
	conf   = &config{}
	client = &http.Client{}
	info   *log.Logger
)

func main() {
	var (
		err      error
		confPath string
	)

	// setup logging
	info = log.New(os.Stdout, "", log.Ltime|log.Lshortfile)

	// load config
	flag.StringVar(&confPath, "config", "", "Path to the config file")
	flag.Parse()

	if confPath == "" {
		confPath, _ = filepath.Abs(filepath.Dir(os.Args[0]))
		confPath += "/service.conf"
	}

	conf := &config{}
	cfile, _ := os.Open(confPath)
	if err = json.NewDecoder(cfile).Decode(&conf); err != nil {
		log.Println("Couldn't decode config file without errors!", err.Error())
		return
	}

	// validate ApiKey
	_, err = hex.DecodeString(conf.ApiKey)
	if len(conf.ApiKey) != 64 || err != nil {
		log.Println("Apikey seems to be invalid! Please supply a valid key!")
		return
	}

	info.Println("Start listening", conf.HTTPBinding)

	router := httprouter.New()
	router.GET("/:file", handler)
	log.Fatal(http.ListenAndServe(conf.HTTPBinding, router))
}

func NotFound(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	info.Println("NotFound")
	http.NotFound(w, r)
}

func InternalServerError(w http.ResponseWriter, r *http.Request, err error) {
	info.Println("Error: ", err.Error())

	w.WriteHeader(http.StatusInternalServerError)
	fmt.Fprint(w, "500 - "+err.Error())
}

func handler(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	f := "/tmp/" + ps.ByName("file")
	if _, err := os.Stat(f); os.IsNotExist(err) {
		http.NotFound(w, r)
		return
	}

	info.Println("Handling", f)

	hash, err := CalculateMD5(f)
	if err != nil {
		InternalServerError(w, r, err)
		return
	}

	result, err := vtWork(fmt.Sprintf("%x", hash), f)
	if err != nil {
		InternalServerError(w, r, err)
		return
	}

	info.Println("Done!")
	fmt.Fprint(w, result)
}

func vtWork(hash, fPath string) (string, error) {
	report, err := getReport(hash)
	if err != nil {
		return "", err
	}

	vtr := &VTResponse{}
	if err := json.Unmarshal(report, vtr); err != nil {
		return "", err
	}

	// 0 = unknwon
	// 1 = found
	// 2 = processing
	if vtr.ResponseCode == 0 && conf.UploadUnknownSamples {
		hash, err = uploadSample(fPath)
		if err != nil {
			return "", err
		}

		vtr.ResponseCode = 2
	}

	if vtr.ResponseCode == 2 {
		info.Println("Not done, sleep for 5min")
		time.Sleep(time.Minute * 5)
		return vtWork(hash, fPath)
	}

	return string(report), nil
}

func CalculateMD5(filePath string) ([]byte, error) {
	var result []byte
	file, err := os.Open(filePath)
	if err != nil {
		return result, err
	}
	defer file.Close()

	hash := md5.New()
	if _, err := io.Copy(hash, file); err != nil {
		return result, err
	}

	return hash.Sum(result), nil
}

func getReport(md5 string) ([]byte, error) {
	info.Println("getReport")

	var respBody []byte

	form := url.Values{}
	form.Add("resource", md5)
	form.Add("apikey", conf.ApiKey)

	req, err := http.NewRequest("POST", "https://www.virustotal.com/vtapi/v2/file/report", strings.NewReader(form.Encode()))
	req.PostForm = form
	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")

	resp, err := client.Do(req)
	if err != nil {
		return respBody, err
	}
	defer resp.Body.Close()

	respBody, err = ioutil.ReadAll(resp.Body)
	if err != nil {
		return respBody, err
	}

	info.Println(resp.Status)
	info.Println(string(respBody))

	if string(respBody) == "" {
		return respBody, errors.New("VT Get Report Response is empty! " + resp.Status)
	}

	return respBody, nil
}

func uploadSample(fPath string) (string, error) {
	info.Println("uploadSample")

	file, err := os.Open(fPath)
	if err != nil {
		return "", err
	}
	defer file.Close()

	body := new(bytes.Buffer)
	writer := multipart.NewWriter(body)
	part, err := writer.CreateFormFile("file", filepath.Base(fPath))
	if err != nil {
		return "", err
	}
	_, err = io.Copy(part, file)

	err = writer.WriteField("apikey", conf.ApiKey)
	if err != nil {
		return "", err
	}

	err = writer.Close()
	if err != nil {
		return "", err
	}

	request, err := http.NewRequest("POST", "https://www.virustotal.com/vtapi/v2/file/scan", body)
	if err != nil {
		return "", err
	}
	request.Header.Add("Content-Type", writer.FormDataContentType())

	resp, err := client.Do(request)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()

	if resp.StatusCode != 200 {
		return "", err
	}

	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}

	info.Println(resp.Status)
	info.Println(string(respBody))

	if string(respBody) == "" {
		return "", errors.New("VT Upload Response is empty! " + resp.Status)
	}

	vtr := &VTResponse{}
	if err := json.Unmarshal(respBody, vtr); err != nil {
		return "", err
	}

	if vtr.ResponseCode != 1 {
		return "", errors.New(vtr.VerboseMsg)
	}

	info.Println(string(respBody))

	return vtr.ScanId, nil
}
<|endoftext|>