<commit_before>/**
 * @file game_test.go
 * @author Mikhail Klementyev jollheef<AT>riseup.net
 * @license GNU GPLv3
 * @date September, 2015
 * @brief test game struct
 */

package pulse_test

import (
	"database/sql"
	"fmt"
	"log"
	"math/rand"
	"os/exec"
	"testing"
	"time"
)

import (
	"github.com/jollheef/tin_foil_hat/pulse"
	"github.com/jollheef/tin_foil_hat/steward"
	"github.com/jollheef/tin_foil_hat/vexillary"
)

type testDB struct {
	db *sql.DB
}

const db_path string = "user=postgres dbname=tinfoilhat_test sslmode=disable"

func openDB() (t testDB, err error) {

	t.db, err = steward.OpenDatabase(db_path)

	t.Close()

	t.db, err = steward.OpenDatabase(db_path)

	return
}

func (t testDB) Close() {

	t.db.Exec("DROP TABLE team")
	t.db.Exec("DROP TABLE advisory")
	t.db.Exec("DROP TABLE captured_flag")
	t.db.Exec("DROP TABLE flag")
	t.db.Exec("DROP TABLE service")
	t.db.Exec("DROP TABLE status")
	t.db.Exec("DROP TABLE round")
	t.db.Exec("DROP TABLE round_result")

	t.db.Close()
}

type dummyService struct {
	path string
	port int
}

func newDummyService(path string, port int) (svc dummyService) {
	svc.path = path
	svc.port = port
	return
}

func (svc dummyService) Start() {
	port := fmt.Sprintf("%d", svc.port)
	exec.Command(svc.path, port).Start()
}

func (svc dummyService) Stop() {
	exec.Command("pkill", "-f", svc.path).Run()
}

func TestRandomizeTimeout(*testing.T) {

	rand.Seed(time.Now().UnixNano())

	if pulse.RandomizeTimeout(0, 0) != time.Second {
		log.Fatalln("Invalid value for invalid parameters")
	}

	timeout := 10 * time.Second
	deviation := timeout / 3

	for i := 0; i < 100; i++ {
		val := pulse.RandomizeTimeout(timeout, deviation)
		if val > timeout+deviation || val < timeout-deviation {
			log.Fatalln("Value is not within the expected range")
		}
	}
}

func TestGame(*testing.T) {

	db, err := openDB()
	if err != nil {
		log.Fatalln("Open database fail:", err)
	}

	min_port_num := 1024
	max_port_num := 65535

	rand.Seed(time.Now().UnixNano())

	port := min_port_num + rand.Intn(max_port_num-min_port_num)

	log.Println("Use port", port)

	service_path := "../checker/python-api/dummy_service.py"

	svc := newDummyService(service_path, port)
	svc.Stop() // kill
	svc.Start()
	defer svc.Stop()

	priv, err := vexillary.GenerateKey()
	if err != nil {
		log.Fatalln("Generate key fail:", err)
	}

	for index, team := range []string{"FooTeam", "BarTeam", "BazTeam"} {

		// just trick for bypass UNIQUE team subnet
		subnet := fmt.Sprintf("127.%d.0.1/24", index)

		vulnbox := fmt.Sprintf("127.0.%d.3", index)

		t := steward.Team{-1, team, subnet, vulnbox}

		_, err = steward.AddTeam(db.db, t)
		if err != nil {
			log.Fatalln("Add team failed:", err)
		}
	}

	checker_path := "../checker/python-api/dummy_checker.py"

	for _, service := range []string{"Foo", "Bar", "Baz"} {

		err = steward.AddService(db.db,
			steward.Service{-1, service, port, checker_path, false})
		if err != nil {
			log.Fatalln("Add service failed:", err)
		}
	}

	round_len := 30 * time.Second
	timeout_between_check := 10 * time.Second

	game, err := pulse.NewGame(db.db, priv, round_len, timeout_between_check)

	defer game.Over()

	end_time := time.Now().Add(time.Minute + 10*time.Second)

	err = game.Run(end_time)

	if err != nil {
		log.Fatalln("Game error:", err)
	}

	for round := 1; round <= 2; round++ {

		for team_id := 1; team_id <= 3; team_id++ {

			res, err := steward.GetRoundResult(db.db, team_id, round)
			if err != nil {
				log.Fatalf("Get round %d result fail: %s",
					round, err)
			}

			if res.DefenceScore != float64(round*2) {
				log.Fatalln("Invalid defence score")
			}

			if res.AttackScore != 0 {
				log.Fatalln("Invalid attack score")
			}
		}
	}
}
<commit_msg>Wait test service init<commit_after>/**
 * @file game_test.go
 * @author Mikhail Klementyev jollheef<AT>riseup.net
 * @license GNU GPLv3
 * @date September, 2015
 * @brief test game struct
 */

package pulse_test

import (
	"database/sql"
	"fmt"
	"log"
	"math/rand"
	"os/exec"
	"testing"
	"time"
)

import (
	"github.com/jollheef/tin_foil_hat/pulse"
	"github.com/jollheef/tin_foil_hat/steward"
	"github.com/jollheef/tin_foil_hat/vexillary"
)

type testDB struct {
	db *sql.DB
}

const db_path string = "user=postgres dbname=tinfoilhat_test sslmode=disable"

func openDB() (t testDB, err error) {

	t.db, err = steward.OpenDatabase(db_path)

	t.Close()

	t.db, err = steward.OpenDatabase(db_path)

	return
}

func (t testDB) Close() {

	t.db.Exec("DROP TABLE team")
	t.db.Exec("DROP TABLE advisory")
	t.db.Exec("DROP TABLE captured_flag")
	t.db.Exec("DROP TABLE flag")
	t.db.Exec("DROP TABLE service")
	t.db.Exec("DROP TABLE status")
	t.db.Exec("DROP TABLE round")
	t.db.Exec("DROP TABLE round_result")

	t.db.Close()
}

type dummyService struct {
	path string
	port int
}

func newDummyService(path string, port int) (svc dummyService) {
	svc.path = path
	svc.port = port
	return
}

func (svc dummyService) Start() {
	port := fmt.Sprintf("%d", svc.port)
	exec.Command(svc.path, port).Start()
}

func (svc dummyService) Stop() {
	exec.Command("pkill", "-f", svc.path).Run()
}

func TestRandomizeTimeout(*testing.T) {

	rand.Seed(time.Now().UnixNano())

	if pulse.RandomizeTimeout(0, 0) != time.Second {
		log.Fatalln("Invalid value for invalid parameters")
	}

	timeout := 10 * time.Second
	deviation := timeout / 3

	for i := 0; i < 100; i++ {
		val := pulse.RandomizeTimeout(timeout, deviation)
		if val > timeout+deviation || val < timeout-deviation {
			log.Fatalln("Value is not within the expected range")
		}
	}
}

func TestGame(*testing.T) {

	db, err := openDB()
	if err != nil {
		log.Fatalln("Open database fail:", err)
	}

	min_port_num := 1024
	max_port_num := 65535

	rand.Seed(time.Now().UnixNano())

	port := min_port_num + rand.Intn(max_port_num-min_port_num)

	log.Println("Use port", port)

	service_path := "../checker/python-api/dummy_service.py"

	svc := newDummyService(service_path, port)
	svc.Stop() // kill
	svc.Start()

	time.Sleep(time.Second) // wait for service init

	defer svc.Stop()

	priv, err := vexillary.GenerateKey()
	if err != nil {
		log.Fatalln("Generate key fail:", err)
	}

	for index, team := range []string{"FooTeam", "BarTeam", "BazTeam"} {

		// just trick for bypass UNIQUE team subnet
		subnet := fmt.Sprintf("127.%d.0.1/24", index)

		vulnbox := fmt.Sprintf("127.0.%d.3", index)

		t := steward.Team{-1, team, subnet, vulnbox}

		_, err = steward.AddTeam(db.db, t)
		if err != nil {
			log.Fatalln("Add team failed:", err)
		}
	}

	checker_path := "../checker/python-api/dummy_checker.py"

	for _, service := range []string{"Foo", "Bar", "Baz"} {

		err = steward.AddService(db.db,
			steward.Service{-1, service, port, checker_path, false})
		if err != nil {
			log.Fatalln("Add service failed:", err)
		}
	}

	round_len := 30 * time.Second
	timeout_between_check := 10 * time.Second

	game, err := pulse.NewGame(db.db, priv, round_len, timeout_between_check)

	defer game.Over()

	end_time := time.Now().Add(time.Minute + 10*time.Second)

	err = game.Run(end_time)

	if err != nil {
		log.Fatalln("Game error:", err)
	}

	for round := 1; round <= 2; round++ {

		for team_id := 1; team_id <= 3; team_id++ {

			res, err := steward.GetRoundResult(db.db, team_id, round)
			if err != nil {
				log.Fatalf("Get round %d result fail: %s",
					round, err)
			}

			if res.DefenceScore != float64(round*2) {
				log.Fatalln("Invalid defence score")
			}

			if res.AttackScore != 0 {
				log.Fatalln("Invalid attack score")
			}
		}
	}
}
<|endoftext|>


<commit_before>package internal

import (
	"bytes"
	"fmt"
	"io"
	"strings"
)

// ErrorWithLog returns an error which includes logs from the kernel verifier.
//
// The default error output is a summary of the full log. The latter can be
// accessed via VerifierError.Log or by formatting the error, see Format.
//
// A set of heuristics is used to determine whether the log has been truncated.
func ErrorWithLog(err error, log []byte) *VerifierError {
	const whitespace = "\t\r\v\n "

	// Convert verifier log C string by truncating it on the first 0 byte
	// and trimming trailing whitespace before interpreting as a Go string.
	truncated := false
	if i := bytes.IndexByte(log, 0); i != -1 {
		if i == len(log)-1 && !bytes.HasSuffix(log[:i], []byte{'\n'}) {
			// The null byte is at the end of the buffer and it's not preceded
			// by a newline character. Most likely the buffer was too short.
			truncated = true
		}

		log = log[:i]
	} else if len(log) > 0 {
		// No null byte? Dodgy!
		truncated = true
	}

	log = bytes.Trim(log, whitespace)
	logLines := bytes.Split(log, []byte{'\n'})
	lines := make([]string, 0, len(logLines))
	for _, line := range logLines {
		// Don't remove leading white space on individual lines. We rely on it
		// when outputting logs.
		lines = append(lines, string(bytes.TrimRight(line, whitespace)))
	}

	return &VerifierError{err, lines, truncated}
}

// VerifierError includes information from the eBPF verifier.
//
// It summarises the log output, see Format if you want to output the full contents.
type VerifierError struct {
	// The error which caused this error.
	Cause error
	// The verifier output split into lines.
	Log []string
	// Whether the log output is truncated, based on several heuristics.
	Truncated bool
}

func (le *VerifierError) Unwrap() error {
	return le.Cause
}

func (le *VerifierError) Error() string {
	log := le.Log
	if n := len(log); n > 0 && strings.HasPrefix(log[n-1], "processed ") {
		// Get rid of "processed 39 insns (limit 1000000) ..." from summary.
		log = log[:n-1]
	}

	output := 0
	switch n := len(log); n {
	case 0:
		return le.Cause.Error()

	case 1, 2:
		output = n

	default:
		output = 1
		if strings.HasPrefix(log[n-1], "\t") || le.Truncated {
			// Add one more line of context if the last line starts with a tab,
			// or if it has been truncated.
			// For example:
			//     [13] STRUCT drm_rect size=16 vlen=4
			//     \tx1 type_id=2
			output++
		}
	}

	var b strings.Builder
	fmt.Fprintf(&b, "%s: ", le.Cause.Error())

	lines := log[len(log)-output:]
	for i, line := range lines {
		b.WriteString(strings.TrimSpace(line))
		if i != len(lines)-1 {
			b.WriteString(": ")
		}
	}

	omitted := len(le.Log) - len(lines)
	if omitted == 0 && !le.Truncated {
		return b.String()
	}

	b.WriteString(" (")
	if le.Truncated {
		b.WriteString("truncated")
	}

	if omitted > 0 {
		if le.Truncated {
			b.WriteString(", ")
		}
		fmt.Fprintf(&b, "%d line(s) omitted", omitted)
	}
	b.WriteString(")")

	return b.String()
}

// Format the error.
//
// Understood verbs are %s and %v, which are equivalent to calling Error(). %v
// allows outputting additional information using the following flags:
//
//     +   Output the first <width> lines, or all lines if no width is given.
//     -   Output the last <width> lines, or all lines if no width is given.
//
// Use width to specify how many lines to output. Use the '-' flag to output
// lines from the end of the log instead of the beginning.
func (le *VerifierError) Format(f fmt.State, verb rune) {
	switch verb {
	case 's':
		_, _ = io.WriteString(f, le.Error())

	case 'v':
		n, haveWidth := f.Width()
		if !haveWidth || n > len(le.Log) {
			n = len(le.Log)
		}

		if !f.Flag('+') && !f.Flag('-') {
			if haveWidth {
				_, _ = io.WriteString(f, "%!v(BADWIDTH)")
				return
			}

			_, _ = io.WriteString(f, le.Error())
			return
		}

		if f.Flag('+') && f.Flag('-') {
			_, _ = io.WriteString(f, "%!v(BADFLAG)")
			return
		}

		fmt.Fprintf(f, "%s:", le.Cause.Error())

		omitted := len(le.Log) - n
		lines := le.Log[:n]
		if f.Flag('-') {
			// Print last instead of first lines.
			lines = le.Log[len(le.Log)-n:]
			if omitted > 0 {
				fmt.Fprintf(f, "\n\t(%d line(s) omitted)", omitted)
			}
		}

		for _, line := range lines {
			fmt.Fprintf(f, "\n\t%s", line)
		}

		if !f.Flag('-') {
			if omitted > 0 {
				fmt.Fprintf(f, "\n\t(%d line(s) omitted)", omitted)
			}
		}

		if le.Truncated {
			fmt.Fprintf(f, "\n\t(truncated)")
		}

	default:
		fmt.Fprintf(f, "%%!%c(BADVERB)", verb)
	}
}
<commit_msg>internal: remove arbitrary <=2 line heuristic in VerifierError.Error()<commit_after>package internal

import (
	"bytes"
	"fmt"
	"io"
	"strings"
)

// ErrorWithLog returns an error which includes logs from the kernel verifier.
//
// The default error output is a summary of the full log. The latter can be
// accessed via VerifierError.Log or by formatting the error, see Format.
//
// A set of heuristics is used to determine whether the log has been truncated.
func ErrorWithLog(err error, log []byte) *VerifierError {
	const whitespace = "\t\r\v\n "

	// Convert verifier log C string by truncating it on the first 0 byte
	// and trimming trailing whitespace before interpreting as a Go string.
	truncated := false
	if i := bytes.IndexByte(log, 0); i != -1 {
		if i == len(log)-1 && !bytes.HasSuffix(log[:i], []byte{'\n'}) {
			// The null byte is at the end of the buffer and it's not preceded
			// by a newline character. Most likely the buffer was too short.
			truncated = true
		}

		log = log[:i]
	} else if len(log) > 0 {
		// No null byte? Dodgy!
		truncated = true
	}

	log = bytes.Trim(log, whitespace)
	logLines := bytes.Split(log, []byte{'\n'})
	lines := make([]string, 0, len(logLines))
	for _, line := range logLines {
		// Don't remove leading white space on individual lines. We rely on it
		// when outputting logs.
		lines = append(lines, string(bytes.TrimRight(line, whitespace)))
	}

	return &VerifierError{err, lines, truncated}
}

// VerifierError includes information from the eBPF verifier.
//
// It summarises the log output, see Format if you want to output the full contents.
type VerifierError struct {
	// The error which caused this error.
	Cause error
	// The verifier output split into lines.
	Log []string
	// Whether the log output is truncated, based on several heuristics.
	Truncated bool
}

func (le *VerifierError) Unwrap() error {
	return le.Cause
}

func (le *VerifierError) Error() string {
	log := le.Log
	if n := len(log); n > 0 && strings.HasPrefix(log[n-1], "processed ") {
		// Get rid of "processed 39 insns (limit 1000000) ..." from summary.
		log = log[:n-1]
	}

	n := len(log)
	if n == 0 {
		return le.Cause.Error()
	}

	lines := log[n-1:]
	if n >= 2 && (strings.HasPrefix(log[n-1], "\t") || le.Truncated) {
		// Add one more line of context if the last line starts with a tab,
		// or if it has been truncated.
		// For example:
		//     [13] STRUCT drm_rect size=16 vlen=4
		//     \tx1 type_id=2
		lines = log[n-2:]
	}

	var b strings.Builder
	fmt.Fprintf(&b, "%s: ", le.Cause.Error())

	for i, line := range lines {
		b.WriteString(strings.TrimSpace(line))
		if i != len(lines)-1 {
			b.WriteString(": ")
		}
	}

	omitted := len(le.Log) - len(lines)
	if omitted == 0 && !le.Truncated {
		return b.String()
	}

	b.WriteString(" (")
	if le.Truncated {
		b.WriteString("truncated")
	}

	if omitted > 0 {
		if le.Truncated {
			b.WriteString(", ")
		}
		fmt.Fprintf(&b, "%d line(s) omitted", omitted)
	}
	b.WriteString(")")

	return b.String()
}

// Format the error.
//
// Understood verbs are %s and %v, which are equivalent to calling Error(). %v
// allows outputting additional information using the following flags:
//
//     +   Output the first <width> lines, or all lines if no width is given.
//     -   Output the last <width> lines, or all lines if no width is given.
//
// Use width to specify how many lines to output. Use the '-' flag to output
// lines from the end of the log instead of the beginning.
func (le *VerifierError) Format(f fmt.State, verb rune) {
	switch verb {
	case 's':
		_, _ = io.WriteString(f, le.Error())

	case 'v':
		n, haveWidth := f.Width()
		if !haveWidth || n > len(le.Log) {
			n = len(le.Log)
		}

		if !f.Flag('+') && !f.Flag('-') {
			if haveWidth {
				_, _ = io.WriteString(f, "%!v(BADWIDTH)")
				return
			}

			_, _ = io.WriteString(f, le.Error())
			return
		}

		if f.Flag('+') && f.Flag('-') {
			_, _ = io.WriteString(f, "%!v(BADFLAG)")
			return
		}

		fmt.Fprintf(f, "%s:", le.Cause.Error())

		omitted := len(le.Log) - n
		lines := le.Log[:n]
		if f.Flag('-') {
			// Print last instead of first lines.
			lines = le.Log[len(le.Log)-n:]
			if omitted > 0 {
				fmt.Fprintf(f, "\n\t(%d line(s) omitted)", omitted)
			}
		}

		for _, line := range lines {
			fmt.Fprintf(f, "\n\t%s", line)
		}

		if !f.Flag('-') {
			if omitted > 0 {
				fmt.Fprintf(f, "\n\t(%d line(s) omitted)", omitted)
			}
		}

		if le.Truncated {
			fmt.Fprintf(f, "\n\t(truncated)")
		}

	default:
		fmt.Fprintf(f, "%%!%c(BADVERB)", verb)
	}
}
<|endoftext|>


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

package gt

import (
	"bytes"
	"fmt"
	"net"
	"net/http"
	"os"
	"os/exec"
	"runtime"
	"strings"
	"time"
)

type vcsNewer func(h *HttpHandler) VcsHandle

type HttpHandler struct {
	runner
	httpAddr string
	vcsAddr  string
	vcsName  string
	pkg      string
	l        net.Listener
	g        *GopathTest
	newer    vcsNewer

	handles map[string]VcsHandle
}

func (h *HttpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	out := w

	const templ = `<meta name="go-import" content="%s %s %s">
`
	p := strings.TrimPrefix(r.URL.Path, "/")
	var handle VcsHandle
	for _, try := range h.handles {
		if strings.HasPrefix(p, try.pkg()) {
			handle = try
			break
		}
	}
	if handle == nil {
		http.Error(w, "repo not found", http.StatusNotFound)
		return
	}

	fmt.Fprintf(out, templ, h.httpAddr+"/"+handle.pkg(), h.vcsName, h.vcsAddr+handle.pkg()+"/.git")
}

func (h *HttpHandler) Close() error {
	return h.l.Close()
}
func (h *HttpHandler) HttpAddr() string {
	return h.httpAddr
}

// Setup returns type with Remove function that can be defer'ed.
func (h *HttpHandler) Setup() VcsHandle {
	vcs := h.newer(h)
	vcs.create()
	h.g.onClean(vcs.remove)

	h.handles[vcs.pkg()] = vcs
	return vcs
}

func NewHttpHandler(g *GopathTest, vcsName string) *HttpHandler {
	// Test if git is installed. If it is, enable the git test.
	// If enabled, start the http server and accept git server registrations.
	l, err := net.Listen("tcp", "localhost:0")
	if err != nil {
		return nil
	}

	h := &HttpHandler{
		runner: runner{
			cwd: g.Current(),
			t:   g,
		},
		pkg:      g.pkg,
		vcsName:  vcsName,
		httpAddr: l.Addr().String(),
		l:        l,
		g:        g,

		handles: make(map[string]VcsHandle, 6),
	}
	go func() {
		err = http.Serve(l, h)
		if err != nil {
			fmt.Printf("Error serving HTTP server %v\n", err)
			os.Exit(1)
		}
	}()

	execPath, _ := exec.LookPath(vcsName)
	if len(execPath) == 0 {
		g.Skip("unsupported vcs")
	}
	h.execPath = execPath
	switch vcsName {
	default:
		panic("unknown vcs type")
	case "git":
		port := h.freePort()
		h.vcsAddr = fmt.Sprintf("git://localhost:%d/", port)

		h.runAsync(" Ready ", "daemon",
			"--listen=localhost", fmt.Sprintf("--port=%d", port),
			"--export-all", "--verbose", "--informative-errors",
			"--base-path="+g.Path(""), h.cwd,
		)
		fmt.Printf("base-path %q, serve %q\n", g.Path(""), h.cwd)

		h.newer = func(h *HttpHandler) VcsHandle {
			return &gitVcsHandle{
				vcsCommon: vcsCommon{
					runner: runner{
						execPath: execPath,
						cwd:      h.g.Current(),
						t:        h.g,
					},
					h:          h,
					importPath: h.g.pkg,
				},
			}
		}
	}
	return h
}

type vcsCommon struct {
	runner
	importPath string

	h *HttpHandler
}

func (vcs *vcsCommon) pkg() string {
	return vcs.importPath
}

type VcsHandle interface {
	remove()
	pkg() string
	create()
	Commit() (rev string, commitTime string)
}

type gitVcsHandle struct {
	vcsCommon
}

func (vcs *gitVcsHandle) remove() {
	delete(vcs.h.handles, vcs.pkg())
}
func (vcs *gitVcsHandle) create() {
	vcs.run("init")
	vcs.run("config", "user.name", "tests")
	vcs.run("config", "user.email", "tests@govendor.io")
}

func (vcs *gitVcsHandle) Commit() (rev string, commitTime string) {
	vcs.run("add", "-A")
	vcs.run("commit", "-a", "-m", "msg")
	out := vcs.run("show", "--pretty=format:%H@%ai", "-s")

	line := strings.TrimSpace(string(out))
	ss := strings.Split(line, "@")
	rev = ss[0]
	tm, err := time.Parse("2006-01-02 15:04:05 -0700", ss[1])
	if err != nil {
		panic("Failed to parse time: " + ss[1] + " : " + err.Error())
	}

	return rev, tm.UTC().Format(time.RFC3339)
}

type runner struct {
	execPath string
	cwd      string
	t        *GopathTest
}

func (r *runner) run(args ...string) []byte {
	cmd := exec.Command(r.execPath, args...)
	cmd.Dir = r.cwd
	out, err := cmd.CombinedOutput()
	if err != nil {
		r.t.Fatalf("Failed to run %q %q: %v", r.execPath, args, err)
	}
	return out
}

func (r *runner) freePort() int {
	l, err := net.Listen("tcp", "localhost:0")
	if err != nil {
		r.t.Fatalf("Failed to find free port %v", err)
	}
	port := l.Addr().(*net.TCPAddr).Port
	l.Close()
	if runtime.GOOS == "windows" {
		time.Sleep(time.Millisecond * 300) // Wait for OS to release port.
	}
	return port
}

func (r *runner) runAsync(checkFor string, args ...string) *exec.Cmd {
	cmd := exec.Command(r.execPath, args...)
	cmd.Dir = r.t.Current()

	var buf *bytes.Buffer
	var bufErr *bytes.Buffer
	if checkFor != "" {
		buf = &bytes.Buffer{}
		bufErr = &bytes.Buffer{}
		cmd.Stdout = buf
		cmd.Stderr = bufErr
	}
	err := cmd.Start()
	if err != nil {
		r.t.Fatalf("Failed to start %q %q: %v", r.execPath, args)
	}
	r.t.onClean(func() {
		if cmd.Process == nil {
			return
		}
		cmd.Process.Signal(os.Interrupt)

		done := make(chan struct{}, 3)
		go func() {
			cmd.Process.Wait()
			done <- struct{}{}
		}()
		select {
		case <-time.After(time.Millisecond * 300):
			cmd.Process.Kill()
		case <-done:
		}
		r.t.Logf("%q StdOut: %s\n", cmd.Path, buf.Bytes())
		r.t.Logf("%q StdErr: %s\n", cmd.Path, bufErr.Bytes())
	})
	if checkFor != "" {
		for i := 0; i < 100; i++ {
			if cmd.ProcessState != nil && cmd.ProcessState.Exited() {
				r.t.Fatalf("unexpected stop %q %q\n%s\n%s\n", r.execPath, args, buf.Bytes(), bufErr.Bytes())
			}
			if strings.Contains(buf.String(), checkFor) {
				return cmd
			}
			if strings.Contains(bufErr.String(), checkFor) {
				return cmd
			}
			time.Sleep(time.Millisecond * 10)
		}
		r.t.Fatalf("failed to read expected output %q from %q %q\n%s\n", checkFor, r.execPath, args, bufErr.Bytes())
	}
	return cmd
}
<commit_msg>internal/gt: prevent race condition in testing exec method<commit_after>// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package gt

import (
	"bytes"
	"fmt"
	"net"
	"net/http"
	"os"
	"os/exec"
	"runtime"
	"strings"
	"sync"
	"time"
)

type vcsNewer func(h *HttpHandler) VcsHandle

type HttpHandler struct {
	runner
	httpAddr string
	vcsAddr  string
	vcsName  string
	pkg      string
	l        net.Listener
	g        *GopathTest
	newer    vcsNewer

	handles map[string]VcsHandle
}

func (h *HttpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	out := w

	const templ = `<meta name="go-import" content="%s %s %s">
`
	p := strings.TrimPrefix(r.URL.Path, "/")
	var handle VcsHandle
	for _, try := range h.handles {
		if strings.HasPrefix(p, try.pkg()) {
			handle = try
			break
		}
	}
	if handle == nil {
		http.Error(w, "repo not found", http.StatusNotFound)
		return
	}

	fmt.Fprintf(out, templ, h.httpAddr+"/"+handle.pkg(), h.vcsName, h.vcsAddr+handle.pkg()+"/.git")
}

func (h *HttpHandler) Close() error {
	return h.l.Close()
}
func (h *HttpHandler) HttpAddr() string {
	return h.httpAddr
}

// Setup returns type with Remove function that can be defer'ed.
func (h *HttpHandler) Setup() VcsHandle {
	vcs := h.newer(h)
	vcs.create()
	h.g.onClean(vcs.remove)

	h.handles[vcs.pkg()] = vcs
	return vcs
}

func NewHttpHandler(g *GopathTest, vcsName string) *HttpHandler {
	// Test if git is installed. If it is, enable the git test.
	// If enabled, start the http server and accept git server registrations.
	l, err := net.Listen("tcp", "localhost:0")
	if err != nil {
		return nil
	}

	h := &HttpHandler{
		runner: runner{
			cwd: g.Current(),
			t:   g,
		},
		pkg:      g.pkg,
		vcsName:  vcsName,
		httpAddr: l.Addr().String(),
		l:        l,
		g:        g,

		handles: make(map[string]VcsHandle, 6),
	}
	go func() {
		err = http.Serve(l, h)
		if err != nil {
			fmt.Printf("Error serving HTTP server %v\n", err)
			os.Exit(1)
		}
	}()

	execPath, _ := exec.LookPath(vcsName)
	if len(execPath) == 0 {
		g.Skip("unsupported vcs")
	}
	h.execPath = execPath
	switch vcsName {
	default:
		panic("unknown vcs type")
	case "git":
		port := h.freePort()
		h.vcsAddr = fmt.Sprintf("git://localhost:%d/", port)

		h.runAsync(" Ready ", "daemon",
			"--listen=localhost", fmt.Sprintf("--port=%d", port),
			"--export-all", "--verbose", "--informative-errors",
			"--base-path="+g.Path(""), h.cwd,
		)
		fmt.Printf("base-path %q, serve %q\n", g.Path(""), h.cwd)

		h.newer = func(h *HttpHandler) VcsHandle {
			return &gitVcsHandle{
				vcsCommon: vcsCommon{
					runner: runner{
						execPath: execPath,
						cwd:      h.g.Current(),
						t:        h.g,
					},
					h:          h,
					importPath: h.g.pkg,
				},
			}
		}
	}
	return h
}

type vcsCommon struct {
	runner
	importPath string

	h *HttpHandler
}

func (vcs *vcsCommon) pkg() string {
	return vcs.importPath
}

type VcsHandle interface {
	remove()
	pkg() string
	create()
	Commit() (rev string, commitTime string)
}

type gitVcsHandle struct {
	vcsCommon
}

func (vcs *gitVcsHandle) remove() {
	delete(vcs.h.handles, vcs.pkg())
}
func (vcs *gitVcsHandle) create() {
	vcs.run("init")
	vcs.run("config", "user.name", "tests")
	vcs.run("config", "user.email", "tests@govendor.io")
}

func (vcs *gitVcsHandle) Commit() (rev string, commitTime string) {
	vcs.run("add", "-A")
	vcs.run("commit", "-a", "-m", "msg")
	out := vcs.run("show", "--pretty=format:%H@%ai", "-s")

	line := strings.TrimSpace(string(out))
	ss := strings.Split(line, "@")
	rev = ss[0]
	tm, err := time.Parse("2006-01-02 15:04:05 -0700", ss[1])
	if err != nil {
		panic("Failed to parse time: " + ss[1] + " : " + err.Error())
	}

	return rev, tm.UTC().Format(time.RFC3339)
}

type runner struct {
	execPath string
	cwd      string
	t        *GopathTest
}

func (r *runner) run(args ...string) []byte {
	cmd := exec.Command(r.execPath, args...)
	cmd.Dir = r.cwd
	out, err := cmd.CombinedOutput()
	if err != nil {
		r.t.Fatalf("Failed to run %q %q: %v", r.execPath, args, err)
	}
	return out
}

func (r *runner) freePort() int {
	l, err := net.Listen("tcp", "localhost:0")
	if err != nil {
		r.t.Fatalf("Failed to find free port %v", err)
	}
	port := l.Addr().(*net.TCPAddr).Port
	l.Close()
	if runtime.GOOS == "windows" {
		time.Sleep(time.Millisecond * 300) // Wait for OS to release port.
	}
	return port
}

// Prevents a race condition in runAsync.
type safeBuf struct {
	sync.Mutex
	buf bytes.Buffer
}

func (s *safeBuf) Write(b []byte) (int, error) {
	s.Lock()
	defer s.Unlock()
	return s.buf.Write(b)
}
func (s *safeBuf) String() string {
	s.Lock()
	defer s.Unlock()
	return s.buf.String()
}

func (r *runner) runAsync(checkFor string, args ...string) *exec.Cmd {
	cmd := exec.Command(r.execPath, args...)
	cmd.Dir = r.t.Current()

	var buf *safeBuf
	var bufErr *safeBuf
	if checkFor != "" {
		buf = &safeBuf{}
		bufErr = &safeBuf{}
		cmd.Stdout = buf
		cmd.Stderr = bufErr
	}
	err := cmd.Start()
	if err != nil {
		r.t.Fatalf("Failed to start %q %q: %v", r.execPath, args)
	}
	r.t.onClean(func() {
		if cmd.Process == nil {
			return
		}
		cmd.Process.Signal(os.Interrupt)

		done := make(chan struct{}, 3)
		go func() {
			cmd.Process.Wait()
			done <- struct{}{}
		}()
		select {
		case <-time.After(time.Millisecond * 300):
			cmd.Process.Kill()
		case <-done:
		}

		r.t.Logf("%q StdOut: %s\n", cmd.Path, buf.String())
		r.t.Logf("%q StdErr: %s\n", cmd.Path, bufErr.String())
	})
	if checkFor != "" {
		for i := 0; i < 100; i++ {
			if cmd.ProcessState != nil && cmd.ProcessState.Exited() {
				r.t.Fatalf("unexpected stop %q %q\n%s\n%s\n", r.execPath, args, buf.String(), bufErr.String())
			}
			if strings.Contains(buf.String(), checkFor) {
				return cmd
			}
			if strings.Contains(bufErr.String(), checkFor) {
				return cmd
			}
			time.Sleep(time.Millisecond * 10)
		}
		r.t.Fatalf("failed to read expected output %q from %q %q\n%s\n", checkFor, r.execPath, args, bufErr.String())
	}
	return cmd
}
<|endoftext|>


<commit_before>/*******************************************************************************
* Copyright (C) Zenoss, Inc. 2013, 2014 all rights reserved.
*
* This content is made available according to terms specified in
* License.zenoss under the directory where your Zenoss product is installed.
*
*******************************************************************************/

package isvcs

import (
	"github.com/fsouza/go-dockerclient"
	"github.com/zenoss/glog"

	"errors"
	"fmt"
	"os"
	"os/exec"
	"os/user"
	"path"
	"strings"
	"time"
)

type containerOp int

const (
	containerOpStart containerOp = iota
	containerOpStop
)

type containerOpRequest struct {
	op       containerOp
	response chan error
}

var ErrNotRunning error
var ErrRunning error
var ErrBadContainerSpec error

func init() {
	ErrNotRunning = errors.New("container: not running")
	ErrRunning = errors.New("container: already running")
	ErrBadContainerSpec = errors.New("container: bad container specification")
}

type ContainerDescription struct {
	Name          string                              // name of the container (used for docker named containers)
	Repo          string                              // the repository the image for this container uses
	Tag           string                              // the repository tag this container uses
	Command       string                              // the actual command to run inside the container
	Volumes       map[string]string                   // Volumes to bind mount in to the containers
	Ports         []int                               // Ports to expose to the host
	HealthCheck   func() error                        // A function to verify that the service is healthy
	Configuration interface{}                         // A container specific configuration
	Notify        func(*Container, interface{}) error // A function to run when notified of a data event
	VolumesDir    string                              // directory to store volume data
}

type Container struct {
	ContainerDescription
	ops chan containerOpRequest // channel for communicating to the container's loop
}

func NewContainer(cd ContainerDescription) (*Container, error) {
	if len(cd.Name) == 0 || len(cd.Repo) == 0 || len(cd.Tag) == 0 || len(cd.Command) == 0 {
		return nil, ErrBadContainerSpec
	}
	c := Container{
		ContainerDescription: cd,
		ops:                  make(chan containerOpRequest),
	}
	go c.loop()
	return &c, nil
}

func (c *Container) SetVolumesDir(volumesDir string) {
	c.VolumesDir = volumesDir
}

func (c *Container) getVolumesDir() string {
	if len(c.VolumesDir) > 0 {
		return c.VolumesDir
	}
	if user, err := user.Current(); err == nil {
		return fmt.Sprintf("/tmp/serviced-%s/isvcs_volumes", user.Username)
	}
	return "/tmp/serviced/isvcs_volumes"
}

// loop maintains the state of the container; it handles requests to start() &
// stop() containers as well as detect container failures.
func (c *Container) loop() {

	var exitChan chan error
	var cmd *exec.Cmd

	for {
		select {
		case req := <-c.ops:
			switch req.op {
			case containerOpStop:
				glog.Infof("containerOpStop(): %s", c.Name)
				if exitChan == nil {
					req.response <- ErrNotRunning
					continue
				}
				oldCmd := cmd
				cmd = nil
				exitChan = nil        // setting extChan to nil will disable reading from it in the select()
				oldCmd.Process.Kill() // kill the docker run() wrapper
				c.stop()              // stop the container if it's not already stopped
				c.rm()                // remove the container if it's not already gone
				req.response <- nil

			case containerOpStart:
				glog.Infof("containerOpStart(): %s", c.Name)
				if cmd != nil {
					req.response <- ErrRunning
					continue
				}
				c.stop()                // stop the container, if it's not stoppped
				c.rm()                  // remove it if it was not already removed
				cmd, exitChan = c.run() // run the actual container
				if c.HealthCheck != nil {
					req.response <- c.HealthCheck() // run the HealthCheck if it exists
				} else {
					req.response <- nil
				}

			}
		case exitErr := <-exitChan:
			glog.Errorf("Unexpected failure of %s, got %s", c.Name, exitErr)
			c.stop()                // stop the container, if it's not stoppped
			c.rm()                  // remove it if it was not already removed
			cmd, exitChan = c.run() // run the actual container
		}
	}
}

// getMatchingContainersIds
func (c *Container) getMatchingContainersIds(client *docker.Client) (*[]string, error) {
	containers, err := client.ListContainers(docker.ListContainersOptions{All: true})
	if err != nil {
		return nil, err
	}
	matching := make([]string, 0)
	for _, container := range containers {
		for _, name := range container.Names {
			if strings.HasPrefix(name, "/"+c.Name) {
				matching = append(matching, container.ID)
			}
		}
	}
	return &matching, nil
}

// attempt to stop all matching containers
func (c *Container) stop() error {
	client, err := newDockerClient("unix:///var/run/docker.sock")
	if err != nil {
		glog.Errorf("Could not create docker client: %s", err)
		return err
	}
	if ids, err := c.getMatchingContainersIds(client); err != nil {
		return err
	} else {
		for _, id := range *ids {
			client.StopContainer(id, 20)
		}
	}
	return nil
}

// attempt to remove all matching containers
func (c *Container) rm() error {
	client, err := newDockerClient("unix:///var/run/docker.sock")
	if err != nil {
		glog.Errorf("Could not create docker client: %s", err)
		return err
	}
	if ids, err := c.getMatchingContainersIds(client); err != nil {
		return err
	} else {
		for _, id := range *ids {
			client.RemoveContainer(id)
		}
	}
	return nil
}

// Run() an instance of this container and return it's exec.Command reference and a
// channel that sends the exit code, when the container exits
func (c *Container) run() (*exec.Cmd, chan error) {

	// the container name is semi random because containers can get wedged
	// in docker and can not be removed until a reboot (or aufs trickery)
	containerName := c.Name + "-" + uuid()

	exitChan := make(chan error, 1)
	args := make([]string, 0)
	args = append(args, "run", "-rm", "-name", containerName)

	// attach all exported ports
	for _, port := range c.Ports {
		args = append(args, "-p", fmt.Sprintf("%d:%d", port, port))
	}

	// attach resources directory to all containers
	args = append(args, "-v", resourcesDir()+":"+"/usr/local/serviced/resources")

	// attach all exported volumes
	for name, volume := range c.Volumes {
		hostDir := path.Join(c.getVolumesDir(), c.Name, name)
		if exists, _ := isDir(hostDir); !exists {
			if err := os.MkdirAll(hostDir, 0777); err != nil {
				glog.Errorf("could not create %s on host: %s", hostDir, err)
				exitChan <- err
				return nil, exitChan
			}
		}
		args = append(args, "-v", hostDir+":"+volume)
	}

	// set the image and command to run
	args = append(args, c.Repo+":"+c.Tag, "/bin/sh", "-c", c.Command)

	glog.V(1).Infof("Executing docker %s", args)
	var cmd *exec.Cmd
	tries := 5
	for {
		var err error
		if tries > 0 {
			cmd = exec.Command("docker", args...)
			if err := cmd.Start(); err != nil {
				glog.Errorf("Could not start: %s", c.Name)
				c.stop()
				c.rm()
				time.Sleep(time.Second * 1)
			} else {
				break
			}
		} else {
			exitChan <- err
			return cmd, exitChan
		}
		tries = -1
	}
	go func() {
		exitChan <- cmd.Wait()
	}()
	return cmd, exitChan
}

// Start() a container by sending the loop() a request
func (c *Container) Start() error {
	req := containerOpRequest{
		op:       containerOpStart,
		response: make(chan error),
	}
	c.ops <- req
	return <-req.response
}

// Stop() a container by sending the loop() a request
func (c *Container) Stop() error {
	req := containerOpRequest{
		op:       containerOpStop,
		response: make(chan error),
	}
	c.ops <- req
	return <-req.response
}
<commit_msg>fix volumesDir interface on container<commit_after>/*******************************************************************************
* Copyright (C) Zenoss, Inc. 2013, 2014 all rights reserved.
*
* This content is made available according to terms specified in
* License.zenoss under the directory where your Zenoss product is installed.
*
*******************************************************************************/

package isvcs

import (
	"github.com/fsouza/go-dockerclient"
	"github.com/zenoss/glog"

	"errors"
	"fmt"
	"os"
	"os/exec"
	"os/user"
	"path"
	"strings"
	"time"
)

type containerOp int

const (
	containerOpStart containerOp = iota
	containerOpStop
)

type containerOpRequest struct {
	op       containerOp
	response chan error
}

var ErrNotRunning error
var ErrRunning error
var ErrBadContainerSpec error

func init() {
	ErrNotRunning = errors.New("container: not running")
	ErrRunning = errors.New("container: already running")
	ErrBadContainerSpec = errors.New("container: bad container specification")
}

type ContainerDescription struct {
	Name          string                              // name of the container (used for docker named containers)
	Repo          string                              // the repository the image for this container uses
	Tag           string                              // the repository tag this container uses
	Command       string                              // the actual command to run inside the container
	Volumes       map[string]string                   // Volumes to bind mount in to the containers
	Ports         []int                               // Ports to expose to the host
	HealthCheck   func() error                        // A function to verify that the service is healthy
	Configuration interface{}                         // A container specific configuration
	Notify        func(*Container, interface{}) error // A function to run when notified of a data event
	volumesDir    string                              // directory to store volume data
}

type Container struct {
	ContainerDescription
	ops chan containerOpRequest // channel for communicating to the container's loop
}

func NewContainer(cd ContainerDescription) (*Container, error) {
	if len(cd.Name) == 0 || len(cd.Repo) == 0 || len(cd.Tag) == 0 || len(cd.Command) == 0 {
		return nil, ErrBadContainerSpec
	}
	c := Container{
		ContainerDescription: cd,
		ops:                  make(chan containerOpRequest),
	}
	go c.loop()
	return &c, nil
}

func (c *Container) SetVolumesDir(volumesDir string) {
	c.volumesDir = volumesDir
}

func (c *Container) VolumesDir() string {
	if len(c.volumesDir) > 0 {
		return c.volumesDir
	}
	if user, err := user.Current(); err == nil {
		return fmt.Sprintf("/tmp/serviced-%s/isvcs_volumes", user.Username)
	}
	return "/tmp/serviced/isvcs_volumes"
}

// loop maintains the state of the container; it handles requests to start() &
// stop() containers as well as detect container failures.
func (c *Container) loop() {

	var exitChan chan error
	var cmd *exec.Cmd

	for {
		select {
		case req := <-c.ops:
			switch req.op {
			case containerOpStop:
				glog.Infof("containerOpStop(): %s", c.Name)
				if exitChan == nil {
					req.response <- ErrNotRunning
					continue
				}
				oldCmd := cmd
				cmd = nil
				exitChan = nil        // setting extChan to nil will disable reading from it in the select()
				oldCmd.Process.Kill() // kill the docker run() wrapper
				c.stop()              // stop the container if it's not already stopped
				c.rm()                // remove the container if it's not already gone
				req.response <- nil

			case containerOpStart:
				glog.Infof("containerOpStart(): %s", c.Name)
				if cmd != nil {
					req.response <- ErrRunning
					continue
				}
				c.stop()                // stop the container, if it's not stoppped
				c.rm()                  // remove it if it was not already removed
				cmd, exitChan = c.run() // run the actual container
				if c.HealthCheck != nil {
					req.response <- c.HealthCheck() // run the HealthCheck if it exists
				} else {
					req.response <- nil
				}

			}
		case exitErr := <-exitChan:
			glog.Errorf("Unexpected failure of %s, got %s", c.Name, exitErr)
			c.stop()                // stop the container, if it's not stoppped
			c.rm()                  // remove it if it was not already removed
			cmd, exitChan = c.run() // run the actual container
		}
	}
}

// getMatchingContainersIds
func (c *Container) getMatchingContainersIds(client *docker.Client) (*[]string, error) {
	containers, err := client.ListContainers(docker.ListContainersOptions{All: true})
	if err != nil {
		return nil, err
	}
	matching := make([]string, 0)
	for _, container := range containers {
		for _, name := range container.Names {
			if strings.HasPrefix(name, "/"+c.Name) {
				matching = append(matching, container.ID)
			}
		}
	}
	return &matching, nil
}

// attempt to stop all matching containers
func (c *Container) stop() error {
	client, err := newDockerClient("unix:///var/run/docker.sock")
	if err != nil {
		glog.Errorf("Could not create docker client: %s", err)
		return err
	}
	if ids, err := c.getMatchingContainersIds(client); err != nil {
		return err
	} else {
		for _, id := range *ids {
			client.StopContainer(id, 20)
		}
	}
	return nil
}

// attempt to remove all matching containers
func (c *Container) rm() error {
	client, err := newDockerClient("unix:///var/run/docker.sock")
	if err != nil {
		glog.Errorf("Could not create docker client: %s", err)
		return err
	}
	if ids, err := c.getMatchingContainersIds(client); err != nil {
		return err
	} else {
		for _, id := range *ids {
			client.RemoveContainer(id)
		}
	}
	return nil
}

// Run() an instance of this container and return it's exec.Command reference and a
// channel that sends the exit code, when the container exits
func (c *Container) run() (*exec.Cmd, chan error) {

	// the container name is semi random because containers can get wedged
	// in docker and can not be removed until a reboot (or aufs trickery)
	containerName := c.Name + "-" + uuid()

	exitChan := make(chan error, 1)
	args := make([]string, 0)
	args = append(args, "run", "-rm", "-name", containerName)

	// attach all exported ports
	for _, port := range c.Ports {
		args = append(args, "-p", fmt.Sprintf("%d:%d", port, port))
	}

	// attach resources directory to all containers
	args = append(args, "-v", resourcesDir()+":"+"/usr/local/serviced/resources")

	// attach all exported volumes
	for name, volume := range c.Volumes {
		hostDir := path.Join(c.VolumesDir(), c.Name, name)
		if exists, _ := isDir(hostDir); !exists {
			if err := os.MkdirAll(hostDir, 0777); err != nil {
				glog.Errorf("could not create %s on host: %s", hostDir, err)
				exitChan <- err
				return nil, exitChan
			}
		}
		args = append(args, "-v", hostDir+":"+volume)
	}

	// set the image and command to run
	args = append(args, c.Repo+":"+c.Tag, "/bin/sh", "-c", c.Command)

	glog.V(1).Infof("Executing docker %s", args)
	var cmd *exec.Cmd
	tries := 5
	for {
		var err error
		if tries > 0 {
			cmd = exec.Command("docker", args...)
			if err := cmd.Start(); err != nil {
				glog.Errorf("Could not start: %s", c.Name)
				c.stop()
				c.rm()
				time.Sleep(time.Second * 1)
			} else {
				break
			}
		} else {
			exitChan <- err
			return cmd, exitChan
		}
		tries = -1
	}
	go func() {
		exitChan <- cmd.Wait()
	}()
	return cmd, exitChan
}

// Start() a container by sending the loop() a request
func (c *Container) Start() error {
	req := containerOpRequest{
		op:       containerOpStart,
		response: make(chan error),
	}
	c.ops <- req
	return <-req.response
}

// Stop() a container by sending the loop() a request
func (c *Container) Stop() error {
	req := containerOpRequest{
		op:       containerOpStop,
		response: make(chan error),
	}
	c.ops <- req
	return <-req.response
}
<|endoftext|>


<commit_before>package main

import (
    "net/http"
    "os"
    "io"
    "time"
    "io/ioutil"
    "fmt"
    fp "path/filepath"
)

const (
  UPDATE_FILE = ".hotrod-update"
  BASE_DIR = "/app/"
)

func handler(w http.ResponseWriter, r *http.Request, add, isFile bool) {
  // after 200000 bytes of file parts stored in memory
  // the remainder are persisted to disk in temporary files
  err := r.ParseMultipartForm(200000)
  if err != nil {
    http.Error(w, err.Error(), http.StatusInternalServerError)
    return
  }

  formData := r.MultipartForm
  relPath := formData.Value["path"][0]

  filepath := fp.Join(BASE_DIR, relPath)

  if add {

    dir := filepath
    if isFile {
      dir = fp.Dir(filepath)
    }

    err = os.MkdirAll(dir, 0777)
    if err != nil {
      http.Error(w, "Unable to create the folder for writing. Check your write access privilege", http.StatusInternalServerError)
      return
    }

    if isFile {
      file := formData.File["file"][0]

      f, err := file.Open()
      defer f.Close()
      if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
      }

      dest, err := os.Create(filepath)
      defer dest.Close()
      if err != nil {
        http.Error(w, "Unable to create the file for writing. Check your write access privilege", http.StatusInternalServerError)
        return
      }

      _, err = io.Copy(dest, f)
      if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
      }
    }

  } else {

    err = os.RemoveAll(filepath)
    if err != nil {
      http.Error(w, "Unable to delete the file/folder. Check your write access privilege", http.StatusInternalServerError)
      return
    }
  }

  os.Chtimes(fp.Join(BASE_DIR, UPDATE_FILE), time.Now(), time.Now())
}

func addBaseHandler(w http.ResponseWriter, r *http.Request) {
  fmt.Fprintf(w, "Hello, server running.")
}

func addFileHandler(w http.ResponseWriter, r *http.Request) {
  handler(w, r, true, true)
}

func addFolderHandler(w http.ResponseWriter, r *http.Request) {
  handler(w, r, true, false)
}

func removeHandler(w http.ResponseWriter, r *http.Request) {
  handler(w, r, false, false)
}

func main() {
    ioutil.WriteFile(fp.Join(BASE_DIR, UPDATE_FILE), []byte(""), 0777)

    http.HandleFunc("/", addBaseHandler)
    http.HandleFunc("/addFile", addFileHandler)
    http.HandleFunc("/addFolder", addFolderHandler)
    http.HandleFunc("/remove", removeHandler)
    http.ListenAndServe(":8888", nil)
}
<commit_msg>add debug<commit_after>package main

import (
    "net/http"
    "os"
    "io"
    "time"
    "io/ioutil"
    "fmt"
    fp "path/filepath"
)

const (
  UPDATE_FILE = ".hotrod-update"
  BASE_DIR = "/app/"
)

var addFile = 0
var remove = 0
var addFolder = 0

func handler(w http.ResponseWriter, r *http.Request, add, isFile bool) {
  // after 200000 bytes of file parts stored in memory
  // the remainder are persisted to disk in temporary files
  err := r.ParseMultipartForm(200000)
  if err != nil {
    http.Error(w, err.Error(), http.StatusInternalServerError)
    return
  }

  formData := r.MultipartForm
  relPath := formData.Value["path"][0]

  filepath := fp.Join(BASE_DIR, relPath)

  if add {

    dir := filepath
    if isFile {
      dir = fp.Dir(filepath)
    }

    err = os.MkdirAll(dir, 0777)
    if err != nil {
      http.Error(w, "Unable to create the folder for writing. Check your write access privilege", http.StatusInternalServerError)
      return
    }

    if isFile {
      file := formData.File["file"][0]

      f, err := file.Open()
      defer f.Close()
      if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
      }

      dest, err := os.Create(filepath)
      defer dest.Close()
      if err != nil {
        http.Error(w, "Unable to create the file for writing. Check your write access privilege", http.StatusInternalServerError)
        return
      }

      _, err = io.Copy(dest, f)
      if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
      }
    }

  } else {

    err = os.RemoveAll(filepath)
    if err != nil {
      http.Error(w, "Unable to delete the file/folder. Check your write access privilege", http.StatusInternalServerError)
      return
    }
  }

  os.Chtimes(fp.Join(BASE_DIR, UPDATE_FILE), time.Now(), time.Now())
}

func addBaseHandler(w http.ResponseWriter, r *http.Request) {
  fmt.Fprintf(w, "Hello, server running. Added files: %s, added folders: %s, removed: %s.", addFile, addFolder, remove)
}

func addFileHandler(w http.ResponseWriter, r *http.Request) {
  addFile += 1
  handler(w, r, true, true)
}

func addFolderHandler(w http.ResponseWriter, r *http.Request) {
  addFolder += 1
  handler(w, r, true, false)
}

func removeHandler(w http.ResponseWriter, r *http.Request) {
  remove += 1
  handler(w, r, false, false)
}

func main() {
    ioutil.WriteFile(fp.Join(BASE_DIR, UPDATE_FILE), []byte(""), 0777)

    http.HandleFunc("/", addBaseHandler)
    http.HandleFunc("/addFile", addFileHandler)
    http.HandleFunc("/addFolder", addFolderHandler)
    http.HandleFunc("/remove", removeHandler)
    http.ListenAndServe(":8888", nil)
}
<|endoftext|>


<commit_before>package main

import  (
        "fmt"
        "github.com/spf13/cobra"
        "github.com/rakyll/globalconf"
        "github.com/mrshu/go-notetxt"
        "flag"
        "os/user"
)

func main() {

        conf, _ := globalconf.New("gonoter")

        var flagNotedir = flag.String("dir", "", "Location of the note.txt directory.")
        var dir string

        var today bool

        var cmdAdd = &cobra.Command{
            Use:   "add [title] [tag]",
            Short: "Add a note.",
            Long:  `Add a note and tag it.`,
            Run: func(cmd *cobra.Command, args []string) {
                if len(args) < 1 {
                        fmt.Println("I need something to add")
                        return
                }
            },
        }
        cmdAdd.Flags().BoolVarP(&numtasks, "today", "T", false,
                                 "Add today's journal entry.")

        var cmdList = &cobra.Command{
            Use:   "list",
            Short: "List notes.",
            Long:  `List all valid note files in the directory.`,
            Run: func(cmd *cobra.Command, args []string) {
                notes, err := notetxt.ParseDir(dir)
                if err != nil {
                    panic(err)
                }

                for i, note := range notes {
                    fmt.Printf("%d %s - %v\n", i, note.Name, note.Tags)
                }
            },
        }

        var GonoterCmd = &cobra.Command{
            Use:   "gonoter",
            Short: "gonoter is a go implementation of note.txt specification.",
            Long: `A small, fast and fun implementation of note.txt`,
            Run: func(cmd *cobra.Command, args []string) {
            },
        }

        GonoterCmd.PersistentFlags().StringVarP(&dir, "directory", "", "",
                                     "Location of the note.txt directory.")

        conf.ParseAll()
        if dir == "" {
                if *flagNotedir == "" {
                        usr, err := user.Current()
                        if err != nil {
                                panic(err)
                        }

                        dir = usr.HomeDir + "/notes"
                } else {
                        dir = *flagNotedir
                }
        }

        GonoterCmd.AddCommand(cmdAdd)
        GonoterCmd.AddCommand(cmdList)
        GonoterCmd.Execute()
}
<commit_msg>fix: Fixed a typo within cmdAdd<commit_after>package main

import  (
        "fmt"
        "github.com/spf13/cobra"
        "github.com/rakyll/globalconf"
        "github.com/mrshu/go-notetxt"
        "flag"
        "os/user"
)

func main() {

        conf, _ := globalconf.New("gonoter")

        var flagNotedir = flag.String("dir", "", "Location of the note.txt directory.")
        var dir string

        var today bool

        var cmdAdd = &cobra.Command{
            Use:   "add [title] [tag]",
            Short: "Add a note.",
            Long:  `Add a note and tag it.`,
            Run: func(cmd *cobra.Command, args []string) {
                if len(args) < 1 {
                        fmt.Println("I need something to add")
                        return
                }
            },
        }
        cmdAdd.Flags().BoolVarP(&today, "today", "T", false,
                                 "Add today's journal entry.")

        var cmdList = &cobra.Command{
            Use:   "list",
            Short: "List notes.",
            Long:  `List all valid note files in the directory.`,
            Run: func(cmd *cobra.Command, args []string) {
                notes, err := notetxt.ParseDir(dir)
                if err != nil {
                    panic(err)
                }

                for i, note := range notes {
                    fmt.Printf("%d %s - %v\n", i, note.Name, note.Tags)
                }
            },
        }

        var GonoterCmd = &cobra.Command{
            Use:   "gonoter",
            Short: "gonoter is a go implementation of note.txt specification.",
            Long: `A small, fast and fun implementation of note.txt`,
            Run: func(cmd *cobra.Command, args []string) {
            },
        }

        GonoterCmd.PersistentFlags().StringVarP(&dir, "directory", "", "",
                                     "Location of the note.txt directory.")

        conf.ParseAll()
        if dir == "" {
                if *flagNotedir == "" {
                        usr, err := user.Current()
                        if err != nil {
                                panic(err)
                        }

                        dir = usr.HomeDir + "/notes"
                } else {
                        dir = *flagNotedir
                }
        }

        GonoterCmd.AddCommand(cmdAdd)
        GonoterCmd.AddCommand(cmdList)
        GonoterCmd.Execute()
}
<|endoftext|>


<commit_before>package controllers

import (
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/gorilla/mux"
	"github.com/prest/prest/adapters/postgres"
	"github.com/prest/prest/config"
)

func TestGetSchemas(t *testing.T) {
	config.Load()
	postgres.Load()

	var testCases = []struct {
		description string
		url         string
		method      string
		status      int
		body        string
	}{
		{"Get schemas without custom where clause", "/schemas", "GET", http.StatusOK, "[{\"schema_name\":\"information_schema\"}, \n {\"schema_name\":\"pg_catalog\"}, \n {\"schema_name\":\"pg_temp_1\"}, \n {\"schema_name\":\"pg_toast\"}, \n {\"schema_name\":\"pg_toast_temp_1\"}, \n {\"schema_name\":\"public\"}]"},
		{"Get schemas with custom where clause", "/schemas?schema_name=$eq.public", "GET", http.StatusOK, "[{\"schema_name\":\"public\"}]"},
		{"Get schemas with custom order clause", "/schemas?schema_name=$eq.public&_order=schema_name", "GET", http.StatusOK, "[{\"schema_name\":\"public\"}]"},
		{"Get schemas with custom order invalid clause", "/schemas?schema_name=$eq.public&_order=$eq.schema_name", "GET", http.StatusBadRequest, "Invalid identifier\n"},
		{"Get schemas with custom where clause and pagination", "/schemas?schema_name=$eq.public&_page=1&_page_size=20", "GET", http.StatusOK, "[{\"schema_name\":\"public\"}]"},
		{"Get schemas with COUNT clause", "/schemas?_count=*", "GET", http.StatusOK, "[{\"count\":6}]"},
		{"Get schemas with custom where invalid clause", "/schemas?0schema_name=$eq.public", "GET", http.StatusBadRequest, "invalid identifier: 0schema_name\n"},
		{"Get schemas with noexistent column", "/schemas?schematame=$eq.test", "GET", http.StatusBadRequest, "pq: column \"schematame\" does not exist\n"},
		{"Get schemas with distinct clause", "/schemas?schema_name=$eq.public&_distinct=true", "GET", http.StatusOK, "[{\"schema_name\":\"public\"}]"},
	}

	router := mux.NewRouter()
	router.HandleFunc("/schemas", GetSchemas).Methods("GET")
	server := httptest.NewServer(router)
	defer server.Close()

	for _, tc := range testCases {
		t.Log(tc.description)
		doRequest(t, server.URL+tc.url, nil, tc.method, tc.status, "GetSchemas", tc.body)
	}
}

func TestVersionDependentGetSchemas(t *testing.T) {
	//This test supports error messages from different versions of Go.
	var testCases = []struct {
		description string
		url         string
		method      string
		status      int
		body        []string
	}{
		{"Get schemas with custom where and pagination invalid",
			"/schemas?schema_name=$eq.public&_page=A",
			"GET",
			http.StatusBadRequest,
			[]string{
				"strconv.ParseInt: parsing \"A\": invalid syntax\n",
				"strconv.Atoi: parsing \"A\": invalid syntax\n",
			},
		},
	}

	router := mux.NewRouter()
	router.HandleFunc("/schemas", GetSchemas).Methods("GET")
	server := httptest.NewServer(router)
	defer server.Close()

	for _, tc := range testCases {
		t.Log(tc.description)
		doRequest(t, server.URL+tc.url, nil, tc.method, tc.status, "GetSchemas", tc.body...)
	}

}
<commit_msg>TestGetSchemas<commit_after>package controllers

import (
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/gorilla/mux"
	"github.com/prest/prest/adapters/postgres"
	"github.com/prest/prest/config"
)

func TestGetSchemas(t *testing.T) {
	config.Load()
	postgres.Load()

	var testCases = []struct {
		description string
		url         string
		method      string
		status      int
		body        string
	}{
		{"Get schemas without custom where clause", "/schemas", "GET", http.StatusOK, "[{\"schema_name\":\"information_schema\"}, \n {\"schema_name\":\"pg_catalog\"}, \n {\"schema_name\":\"pg_toast\"}, \n {\"schema_name\":\"public\"}]"},
		{"Get schemas with custom where clause", "/schemas?schema_name=$eq.public", "GET", http.StatusOK, "[{\"schema_name\":\"public\"}]"},
		{"Get schemas with custom order clause", "/schemas?schema_name=$eq.public&_order=schema_name", "GET", http.StatusOK, "[{\"schema_name\":\"public\"}]"},
		{"Get schemas with custom order invalid clause", "/schemas?schema_name=$eq.public&_order=$eq.schema_name", "GET", http.StatusBadRequest, "Invalid identifier\n"},
		{"Get schemas with custom where clause and pagination", "/schemas?schema_name=$eq.public&_page=1&_page_size=20", "GET", http.StatusOK, "[{\"schema_name\":\"public\"}]"},
		{"Get schemas with COUNT clause", "/schemas?_count=*", "GET", http.StatusOK, "[{\"count\":6}]"},
		{"Get schemas with custom where invalid clause", "/schemas?0schema_name=$eq.public", "GET", http.StatusBadRequest, "invalid identifier: 0schema_name\n"},
		{"Get schemas with noexistent column", "/schemas?schematame=$eq.test", "GET", http.StatusBadRequest, "pq: column \"schematame\" does not exist\n"},
		{"Get schemas with distinct clause", "/schemas?schema_name=$eq.public&_distinct=true", "GET", http.StatusOK, "[{\"schema_name\":\"public\"}]"},
	}

	router := mux.NewRouter()
	router.HandleFunc("/schemas", GetSchemas).Methods("GET")
	server := httptest.NewServer(router)
	defer server.Close()

	for _, tc := range testCases {
		t.Log(tc.description)
		doRequest(t, server.URL+tc.url, nil, tc.method, tc.status, "GetSchemas", tc.body)
	}
}

func TestVersionDependentGetSchemas(t *testing.T) {
	//This test supports error messages from different versions of Go.
	var testCases = []struct {
		description string
		url         string
		method      string
		status      int
		body        []string
	}{
		{"Get schemas with custom where and pagination invalid",
			"/schemas?schema_name=$eq.public&_page=A",
			"GET",
			http.StatusBadRequest,
			[]string{
				"strconv.ParseInt: parsing \"A\": invalid syntax\n",
				"strconv.Atoi: parsing \"A\": invalid syntax\n",
			},
		},
	}

	router := mux.NewRouter()
	router.HandleFunc("/schemas", GetSchemas).Methods("GET")
	server := httptest.NewServer(router)
	defer server.Close()

	for _, tc := range testCases {
		t.Log(tc.description)
		doRequest(t, server.URL+tc.url, nil, tc.method, tc.status, "GetSchemas", tc.body...)
	}

}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014 Santiago Arias | Remy Jourde
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

package tasks

import (
	"encoding/json"
	"errors"
	"net/http"

	"appengine"

	"github.com/santiaago/gonawin/helpers"
	"github.com/santiaago/gonawin/helpers/log"
	mdl "github.com/santiaago/gonawin/models"
)

// DeleteUserActivities handler, use it to delete user activities.
func DeleteUserActivities(w http.ResponseWriter, r *http.Request) error {
	if r.Method != "POST" {
		log.Infof(c, "%s something went wrong...")
		return &helpers.BadRequest{Err: errors.New(helpers.ErrorCodeNotSupported)}
	}

	c := appengine.NewContext(r)
	desc := "Task queue - DeleteUsersActivities Handler:"
	log.Infof(c, "%s processing...", desc)

	log.Infof(c, "%s reading data...", desc)
	activityIdsBlob := []byte(r.FormValue("activity_ids"))

	var activityIds []int64
	err := json.Unmarshal(activityIdsBlob, &activityIds)
	if err != nil {
		log.Errorf(c, "%s unable to extract activityIds from data, %v", desc, err)
	}

	if err = mdl.DestroyActivities(c, activityIds); err != nil {
		log.Errorf(c, "%s activities have not been deleted. %v", desc, err)
	}

	log.Infof(c, "%s task done!", desc)
	return nil
}

// DeleteUserPredicts handler, use it to delete the predictions of a given user.
func DeleteUserPredicts(w http.ResponseWriter, r *http.Request) error {
	if r.Method != "POST" {
		log.Infof(c, "%s something went wrong...")
		return &helpers.BadRequest{Err: errors.New(helpers.ErrorCodeNotSupported)}
	}

	c := appengine.NewContext(r)
	desc := "Task queue - DeleteUserPredicts Handler:"
	log.Infof(c, "%s processing...", desc)

	log.Infof(c, "%s reading data...", desc)
	predictIdsBlob := []byte(r.FormValue("predict_ids"))

	var predictIds []int64
	err := json.Unmarshal(predictIdsBlob, &predictIds)
	if err != nil {
		log.Errorf(c, "%s unable to extract predictIds from data, %v", desc, err)
	}

	if err = mdl.DestroyPredicts(c, predictIds); err != nil {
		log.Errorf(c, "%s predicts have not been deleted. %v", desc, err)
	}

	log.Infof(c, "%s task done!", desc)
	return nil
}
<commit_msg>task delete - fix build<commit_after>/*
 * Copyright (c) 2014 Santiago Arias | Remy Jourde
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

package tasks

import (
	"encoding/json"
	"errors"
	"net/http"

	"appengine"

	"github.com/santiaago/gonawin/helpers"
	"github.com/santiaago/gonawin/helpers/log"
	mdl "github.com/santiaago/gonawin/models"
)

// DeleteUserActivities handler, use it to delete user activities.
func DeleteUserActivities(w http.ResponseWriter, r *http.Request) error {

	c := appengine.NewContext(r)
	desc := "Task queue - DeleteUsersActivities Handler:"

	if r.Method != "POST" {
		log.Infof(c, "%s something went wrong...", desc)
		return &helpers.BadRequest{Err: errors.New(helpers.ErrorCodeNotSupported)}
	}

	log.Infof(c, "%s processing...", desc)

	log.Infof(c, "%s reading data...", desc)
	activityIdsBlob := []byte(r.FormValue("activity_ids"))

	var activityIds []int64
	err := json.Unmarshal(activityIdsBlob, &activityIds)
	if err != nil {
		log.Errorf(c, "%s unable to extract activityIds from data, %v", desc, err)
	}

	if err = mdl.DestroyActivities(c, activityIds); err != nil {
		log.Errorf(c, "%s activities have not been deleted. %v", desc, err)
	}

	log.Infof(c, "%s task done!", desc)
	return nil
}

// DeleteUserPredicts handler, use it to delete the predictions of a given user.
func DeleteUserPredicts(w http.ResponseWriter, r *http.Request) error {

	c := appengine.NewContext(r)
	desc := "Task queue - DeleteUserPredicts Handler:"

	if r.Method != "POST" {
		log.Infof(c, "%s something went wrong...", desc)
		return &helpers.BadRequest{Err: errors.New(helpers.ErrorCodeNotSupported)}
	}

	log.Infof(c, "%s processing...", desc)

	log.Infof(c, "%s reading data...", desc)
	predictIdsBlob := []byte(r.FormValue("predict_ids"))

	var predictIds []int64
	err := json.Unmarshal(predictIdsBlob, &predictIds)
	if err != nil {
		log.Errorf(c, "%s unable to extract predictIds from data, %v", desc, err)
	}

	if err = mdl.DestroyPredicts(c, predictIds); err != nil {
		log.Errorf(c, "%s predicts have not been deleted. %v", desc, err)
	}

	log.Infof(c, "%s task done!", desc)
	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2014 Google Inc. All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// podex is a command line tool to bootstrap kubernetes container
// manifest from docker image metadata.
//
// Manifests can then be edited by a human to match deployment needs.
//
// Example usage:
//
// $ docker pull google/nodejs-hello
// $ podex -yaml google/nodejs-hello > google/nodejs-hello/pod.yaml
// $ podex -json google/nodejs-hello > google/nodejs-hello/pod.json

package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strconv"
	"strings"

	"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
	"github.com/ghodss/yaml"
)

const usage = "usage: podex [-json|-yaml] [-id PODNAME] IMAGES"

var generateJSON = flag.Bool("json", false, "generate json manifest")
var generateYAML = flag.Bool("yaml", false, "generate yaml manifest")
var podName = flag.String("id", "", "set pod name")

type image struct {
	Host      string
	Namespace string
	Image     string
	Tag       string
}

func main() {
	flag.Parse()

	if flag.NArg() < 1 {
		log.Fatal(usage)
	}
	if *podName == "" {
		if flag.NArg() > 1 {
			log.Print(usage)
			log.Fatal("podex: -id arg is required when passing more than one image")
		}
		_, _, *podName, _ = splitDockerImageName(flag.Arg(0))
	}

	if (!*generateJSON && !*generateYAML) || (*generateJSON && *generateYAML) {
		log.Fatal(usage)
	}

	podContainers := []v1beta1.Container{}

	for _, imageName := range flag.Args() {
		host, namespace, repo, tag := splitDockerImageName(imageName)

		container := v1beta1.Container{
			Name:  repo,
			Image: imageName,
		}

		img, err := getImageMetadata(host, namespace, repo, tag)

		if err != nil {
			log.Fatalf("failed to get image metadata %q: %v", imageName, err)
		}
		for p := range img.ContainerConfig.ExposedPorts {
			port, err := strconv.Atoi(p.Port())
			if err != nil {
				log.Fatalf("failed to parse port %q: %v", p.Port(), err)
			}
			container.Ports = append(container.Ports, v1beta1.Port{
				Name:          strings.Join([]string{repo, p.Proto(), p.Port()}, "-"),
				ContainerPort: port,
				Protocol:      v1beta1.Protocol(strings.ToUpper(p.Proto())),
			})
		}
		podContainers = append(podContainers, container)
	}

	// TODO(proppy): add flag to handle multiple version
	manifest := v1beta1.ContainerManifest{
		Version:    "v1beta1",
		ID:         *podName + "-pod",
		Containers: podContainers,
		RestartPolicy: v1beta1.RestartPolicy{
			Always: &v1beta1.RestartPolicyAlways{},
		},
	}

	if *generateJSON {
		bs, err := json.MarshalIndent(manifest, "", "  ")
		if err != nil {
			log.Fatalf("failed to render JSON container manifest: %v", err)
		}
		os.Stdout.Write(bs)
	}
	if *generateYAML {
		bs, err := yaml.Marshal(manifest)
		if err != nil {
			log.Fatalf("failed to render YAML container manifest: %v", err)
		}
		os.Stdout.Write(bs)
	}
}

// splitDockerImageName split a docker image name of the form [HOST/][NAMESPACE/]REPOSITORY[:TAG]
func splitDockerImageName(imageName string) (host, namespace, repo, tag string) {
	hostNamespaceImage := strings.Split(imageName, "/")
	last := len(hostNamespaceImage) - 1
	repoTag := strings.Split(hostNamespaceImage[last], ":")
	repo = repoTag[0]
	if len(repoTag) > 1 {
		tag = repoTag[1]
	}
	switch len(hostNamespaceImage) {
	case 2:
		host = ""
		namespace = hostNamespaceImage[0]
	case 3:
		host = hostNamespaceImage[0]
		namespace = hostNamespaceImage[1]
	}
	return
}

type Port string

func (p Port) Port() string {
	parts := strings.Split(string(p), "/")
	return parts[0]
}

func (p Port) Proto() string {
	parts := strings.Split(string(p), "/")
	if len(parts) == 1 {
		return "tcp"
	}
	return parts[1]
}

type imageMetadata struct {
	ID              string `json:"id"`
	ContainerConfig struct {
		ExposedPorts map[Port]struct{}
	} `json:"container_config"`
}

func getImageMetadata(host, namespace, repo, tag string) (*imageMetadata, error) {
	if host == "" {
		host = "index.docker.io"
	}
	if namespace == "" {
		namespace = "library"
	}
	if tag == "" {
		tag = "latest"
	}
	req, err := http.NewRequest("GET", fmt.Sprintf("https://%s/v1/repositories/%s/%s/images", host, namespace, repo), nil)

	if err != nil {
		return nil, fmt.Errorf("error creating request: %v", err)
	}
	req.Header.Add("X-Docker-Token", "true")
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return nil, fmt.Errorf("error getting X-Docker-Token from index.docker.io: %v", err)
	}
	endpoints := resp.Header.Get("X-Docker-Endpoints")
	token := resp.Header.Get("X-Docker-Token")
	req, err = http.NewRequest("GET", fmt.Sprintf("https://%s/v1/repositories/%s/%s/tags/%s", endpoints, namespace, repo, tag), nil)
	if err != nil {
		return nil, fmt.Errorf("error creating request: %v", err)
	}
	req.Header.Add("Authorization", "Token "+token)
	resp, err = http.DefaultClient.Do(req)
	if err != nil {
		return nil, fmt.Errorf("error getting image id for %s/%s:%s %v", namespace, repo, tag, err)
	}
	var imageID string
	if err = json.NewDecoder(resp.Body).Decode(&imageID); err != nil {
		return nil, fmt.Errorf("error decoding image id: %v", err)
	}
	req, err = http.NewRequest("GET", fmt.Sprintf("https://%s/v1/images/%s/json", endpoints, imageID), nil)
	if err != nil {
		return nil, fmt.Errorf("error creating request: %v", err)
	}
	req.Header.Add("Authorization", "Token "+token)
	resp, err = http.DefaultClient.Do(req)
	if err != nil {
		return nil, fmt.Errorf("error getting json for image %q: %v", imageID, err)
	}
	data, _ := ioutil.ReadAll(resp.Body)
	buf := bytes.NewBuffer(data)
	log.Print(string(data))
	var image imageMetadata
	if err := json.NewDecoder(buf).Decode(&image); err != nil {
		return nil, fmt.Errorf("error decoding image %q metadata: %v", imageID, err)
	}
	return &image, nil
}
<commit_msg>contrib/podex: remove logging<commit_after>/*
Copyright 2014 Google Inc. All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// podex is a command line tool to bootstrap kubernetes container
// manifest from docker image metadata.
//
// Manifests can then be edited by a human to match deployment needs.
//
// Example usage:
//
// $ docker pull google/nodejs-hello
// $ podex -yaml google/nodejs-hello > google/nodejs-hello/pod.yaml
// $ podex -json google/nodejs-hello > google/nodejs-hello/pod.json

package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"
	"strconv"
	"strings"

	"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
	"github.com/ghodss/yaml"
)

const usage = "usage: podex [-json|-yaml] [-id PODNAME] IMAGES"

var generateJSON = flag.Bool("json", false, "generate json manifest")
var generateYAML = flag.Bool("yaml", false, "generate yaml manifest")
var podName = flag.String("id", "", "set pod name")

type image struct {
	Host      string
	Namespace string
	Image     string
	Tag       string
}

func main() {
	flag.Parse()

	if flag.NArg() < 1 {
		log.Fatal(usage)
	}
	if *podName == "" {
		if flag.NArg() > 1 {
			log.Print(usage)
			log.Fatal("podex: -id arg is required when passing more than one image")
		}
		_, _, *podName, _ = splitDockerImageName(flag.Arg(0))
	}

	if (!*generateJSON && !*generateYAML) || (*generateJSON && *generateYAML) {
		log.Fatal(usage)
	}

	podContainers := []v1beta1.Container{}

	for _, imageName := range flag.Args() {
		host, namespace, repo, tag := splitDockerImageName(imageName)

		container := v1beta1.Container{
			Name:  repo,
			Image: imageName,
		}

		img, err := getImageMetadata(host, namespace, repo, tag)

		if err != nil {
			log.Fatalf("failed to get image metadata %q: %v", imageName, err)
		}
		for p := range img.ContainerConfig.ExposedPorts {
			port, err := strconv.Atoi(p.Port())
			if err != nil {
				log.Fatalf("failed to parse port %q: %v", p.Port(), err)
			}
			container.Ports = append(container.Ports, v1beta1.Port{
				Name:          strings.Join([]string{repo, p.Proto(), p.Port()}, "-"),
				ContainerPort: port,
				Protocol:      v1beta1.Protocol(strings.ToUpper(p.Proto())),
			})
		}
		podContainers = append(podContainers, container)
	}

	// TODO(proppy): add flag to handle multiple version
	manifest := v1beta1.ContainerManifest{
		Version:    "v1beta1",
		ID:         *podName + "-pod",
		Containers: podContainers,
		RestartPolicy: v1beta1.RestartPolicy{
			Always: &v1beta1.RestartPolicyAlways{},
		},
	}

	if *generateJSON {
		bs, err := json.MarshalIndent(manifest, "", "  ")
		if err != nil {
			log.Fatalf("failed to render JSON container manifest: %v", err)
		}
		os.Stdout.Write(bs)
	}
	if *generateYAML {
		bs, err := yaml.Marshal(manifest)
		if err != nil {
			log.Fatalf("failed to render YAML container manifest: %v", err)
		}
		os.Stdout.Write(bs)
	}
}

// splitDockerImageName split a docker image name of the form [HOST/][NAMESPACE/]REPOSITORY[:TAG]
func splitDockerImageName(imageName string) (host, namespace, repo, tag string) {
	hostNamespaceImage := strings.Split(imageName, "/")
	last := len(hostNamespaceImage) - 1
	repoTag := strings.Split(hostNamespaceImage[last], ":")
	repo = repoTag[0]
	if len(repoTag) > 1 {
		tag = repoTag[1]
	}
	switch len(hostNamespaceImage) {
	case 2:
		host = ""
		namespace = hostNamespaceImage[0]
	case 3:
		host = hostNamespaceImage[0]
		namespace = hostNamespaceImage[1]
	}
	return
}

type Port string

func (p Port) Port() string {
	parts := strings.Split(string(p), "/")
	return parts[0]
}

func (p Port) Proto() string {
	parts := strings.Split(string(p), "/")
	if len(parts) == 1 {
		return "tcp"
	}
	return parts[1]
}

type imageMetadata struct {
	ID              string `json:"id"`
	ContainerConfig struct {
		ExposedPorts map[Port]struct{}
	} `json:"container_config"`
}

func getImageMetadata(host, namespace, repo, tag string) (*imageMetadata, error) {
	if host == "" {
		host = "index.docker.io"
	}
	if namespace == "" {
		namespace = "library"
	}
	if tag == "" {
		tag = "latest"
	}
	req, err := http.NewRequest("GET", fmt.Sprintf("https://%s/v1/repositories/%s/%s/images", host, namespace, repo), nil)

	if err != nil {
		return nil, fmt.Errorf("error creating request: %v", err)
	}
	req.Header.Add("X-Docker-Token", "true")
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return nil, fmt.Errorf("error getting X-Docker-Token from index.docker.io: %v", err)
	}
	endpoints := resp.Header.Get("X-Docker-Endpoints")
	token := resp.Header.Get("X-Docker-Token")
	req, err = http.NewRequest("GET", fmt.Sprintf("https://%s/v1/repositories/%s/%s/tags/%s", endpoints, namespace, repo, tag), nil)
	if err != nil {
		return nil, fmt.Errorf("error creating request: %v", err)
	}
	req.Header.Add("Authorization", "Token "+token)
	resp, err = http.DefaultClient.Do(req)
	if err != nil {
		return nil, fmt.Errorf("error getting image id for %s/%s:%s %v", namespace, repo, tag, err)
	}
	var imageID string
	if err = json.NewDecoder(resp.Body).Decode(&imageID); err != nil {
		return nil, fmt.Errorf("error decoding image id: %v", err)
	}
	req, err = http.NewRequest("GET", fmt.Sprintf("https://%s/v1/images/%s/json", endpoints, imageID), nil)
	if err != nil {
		return nil, fmt.Errorf("error creating request: %v", err)
	}
	req.Header.Add("Authorization", "Token "+token)
	resp, err = http.DefaultClient.Do(req)
	if err != nil {
		return nil, fmt.Errorf("error getting json for image %q: %v", imageID, err)
	}
	var image imageMetadata
	if err := json.NewDecoder(resp.Body).Decode(&image); err != nil {
		return nil, fmt.Errorf("error decoding image %q metadata: %v", imageID, err)
	}
	return &image, nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"strings"

	"github.com/flynn/flynn/Godeps/_workspace/src/github.com/jackc/pgx"
	ct "github.com/flynn/flynn/controller/types"
	"github.com/flynn/flynn/host/types"
	"github.com/flynn/flynn/pkg/postgres"
	"github.com/flynn/flynn/pkg/random"
)

type ArtifactRepo struct {
	db *postgres.DB
}

func NewArtifactRepo(db *postgres.DB) *ArtifactRepo {
	return &ArtifactRepo{db}
}

func (r *ArtifactRepo) Add(data interface{}) error {
	a := data.(*ct.Artifact)
	// TODO: actually validate
	if a.ID == "" {
		a.ID = random.UUID()
	}
	if a.Type == "" {
		return ct.ValidationError{"type", "must not be empty"}
	}
	if a.URI == "" {
		return ct.ValidationError{"uri", "must not be empty"}
	}
	tx, err := r.db.Begin()
	if err != nil {
		return err
	}

	err = tx.QueryRow("artifact_insert", a.ID, string(a.Type), a.URI, a.Meta).Scan(&a.CreatedAt)
	if postgres.IsUniquenessError(err, "") {
		tx.Rollback()
		tx, err = r.db.Begin()
		if err != nil {
			return err
		}
		err = tx.QueryRow("artifact_select_by_type_and_uri", string(a.Type), a.URI).Scan(&a.ID, &a.Meta, &a.CreatedAt)
		if err != nil {
			tx.Rollback()
			return err
		}
	} else if err == nil {
		if err := createEvent(tx.Exec, &ct.Event{
			ObjectID:   a.ID,
			ObjectType: ct.EventTypeArtifact,
		}, a); err != nil {
			tx.Rollback()
			return err
		}
	}
	if err != nil {
		tx.Rollback()
		return err
	}
	return tx.Commit()
}

func scanArtifact(s postgres.Scanner) (*ct.Artifact, error) {
	artifact := &ct.Artifact{}
	var typ string
	err := s.Scan(&artifact.ID, &typ, &artifact.URI, &artifact.Meta, &artifact.CreatedAt)
	if err == pgx.ErrNoRows {
		err = ErrNotFound
	}
	artifact.Type = host.ArtifactType(typ)
	return artifact, err
}

func (r *ArtifactRepo) Get(id string) (interface{}, error) {
	row := r.db.QueryRow("artifact_select", id)
	return scanArtifact(row)
}

func (r *ArtifactRepo) List() (interface{}, error) {
	rows, err := r.db.Query("artifact_list")
	if err != nil {
		return nil, err
	}
	var artifacts []*ct.Artifact
	for rows.Next() {
		artifact, err := scanArtifact(rows)
		if err != nil {
			rows.Close()
			return nil, err
		}
		artifacts = append(artifacts, artifact)
	}
	return artifacts, rows.Err()
}

func (r *ArtifactRepo) ListIDs(ids ...string) (map[string]*ct.Artifact, error) {
	if len(ids) == 0 {
		return nil, nil
	}
	rows, err := r.db.Query("artifact_list_ids", fmt.Sprintf("{%s}", strings.Join(ids, ",")))
	if err != nil {
		return nil, err
	}
	artifacts := make(map[string]*ct.Artifact, len(ids))
	for rows.Next() {
		artifact, err := scanArtifact(rows)
		if err != nil {
			rows.Close()
			return nil, err
		}
		artifacts[artifact.ID] = artifact
	}
	return artifacts, rows.Err()
}

func scanArtifacts(rows *pgx.Rows) (interface{}, error) {
	var artifacts []*ct.Artifact
	for rows.Next() {
		artifact, err := scanArtifact(rows)
		if err != nil {
			rows.Close()
			return nil, err
		}
		artifacts = append(artifacts, artifact)
	}
	return artifacts, rows.Err()
}
<commit_msg>controller: Always create an event when pushing an artifact<commit_after>package main

import (
	"fmt"
	"strings"

	"github.com/flynn/flynn/Godeps/_workspace/src/github.com/jackc/pgx"
	ct "github.com/flynn/flynn/controller/types"
	"github.com/flynn/flynn/host/types"
	"github.com/flynn/flynn/pkg/postgres"
	"github.com/flynn/flynn/pkg/random"
)

type ArtifactRepo struct {
	db *postgres.DB
}

func NewArtifactRepo(db *postgres.DB) *ArtifactRepo {
	return &ArtifactRepo{db}
}

func (r *ArtifactRepo) Add(data interface{}) error {
	a := data.(*ct.Artifact)
	// TODO: actually validate
	if a.ID == "" {
		a.ID = random.UUID()
	}
	if a.Type == "" {
		return ct.ValidationError{"type", "must not be empty"}
	}
	if a.URI == "" {
		return ct.ValidationError{"uri", "must not be empty"}
	}
	tx, err := r.db.Begin()
	if err != nil {
		return err
	}

	err = tx.QueryRow("artifact_insert", a.ID, string(a.Type), a.URI, a.Meta).Scan(&a.CreatedAt)
	if postgres.IsUniquenessError(err, "") {
		tx.Rollback()
		tx, err = r.db.Begin()
		if err != nil {
			return err
		}
		err = tx.QueryRow("artifact_select_by_type_and_uri", string(a.Type), a.URI).Scan(&a.ID, &a.Meta, &a.CreatedAt)
		if err != nil {
			tx.Rollback()
			return err
		}
	}
	if err == nil {
		if err := createEvent(tx.Exec, &ct.Event{
			ObjectID:   a.ID,
			ObjectType: ct.EventTypeArtifact,
		}, a); err != nil {
			tx.Rollback()
			return err
		}
	} else {
		tx.Rollback()
		return err
	}
	return tx.Commit()
}

func scanArtifact(s postgres.Scanner) (*ct.Artifact, error) {
	artifact := &ct.Artifact{}
	var typ string
	err := s.Scan(&artifact.ID, &typ, &artifact.URI, &artifact.Meta, &artifact.CreatedAt)
	if err == pgx.ErrNoRows {
		err = ErrNotFound
	}
	artifact.Type = host.ArtifactType(typ)
	return artifact, err
}

func (r *ArtifactRepo) Get(id string) (interface{}, error) {
	row := r.db.QueryRow("artifact_select", id)
	return scanArtifact(row)
}

func (r *ArtifactRepo) List() (interface{}, error) {
	rows, err := r.db.Query("artifact_list")
	if err != nil {
		return nil, err
	}
	var artifacts []*ct.Artifact
	for rows.Next() {
		artifact, err := scanArtifact(rows)
		if err != nil {
			rows.Close()
			return nil, err
		}
		artifacts = append(artifacts, artifact)
	}
	return artifacts, rows.Err()
}

func (r *ArtifactRepo) ListIDs(ids ...string) (map[string]*ct.Artifact, error) {
	if len(ids) == 0 {
		return nil, nil
	}
	rows, err := r.db.Query("artifact_list_ids", fmt.Sprintf("{%s}", strings.Join(ids, ",")))
	if err != nil {
		return nil, err
	}
	artifacts := make(map[string]*ct.Artifact, len(ids))
	for rows.Next() {
		artifact, err := scanArtifact(rows)
		if err != nil {
			rows.Close()
			return nil, err
		}
		artifacts[artifact.ID] = artifact
	}
	return artifacts, rows.Err()
}

func scanArtifacts(rows *pgx.Rows) (interface{}, error) {
	var artifacts []*ct.Artifact
	for rows.Next() {
		artifact, err := scanArtifact(rows)
		if err != nil {
			rows.Close()
			return nil, err
		}
		artifacts = append(artifacts, artifact)
	}
	return artifacts, rows.Err()
}
<|endoftext|>


<commit_before>package controllers

import (
	"github.com/UserStack/ustackweb/models"
)

type ProfileController struct {
	BaseController
}

func (this *ProfileController) Prepare() {
	this.PrepareXsrf()
	this.RequireAuth()
	this.PrepareLayout()
}

func (this *ProfileController) Get() {
	this.Layout = "layouts/default.html.tpl"
	this.TplNames = "profile/index.html.tpl"
	user, err := models.Users().FindByName("admin")
	if err != nil {
		return
	}
	keys, err := user.DataKeys()
	if err != nil {
		return
	}
	data := make(map[string]string)
	for _, key := range keys {
		value, err := user.Data(key)
		if err == nil {
			data[key] = value
		}
	}
	this.Data["userData"] = data
}
<commit_msg>Display current/last login as time.<commit_after>package controllers

import (
	"strconv"
	"time"

	"github.com/UserStack/ustackweb/models"
)

type ProfileController struct {
	BaseController
}

func (this *ProfileController) Prepare() {
	this.PrepareXsrf()
	this.RequireAuth()
	this.PrepareLayout()
}

func (this *ProfileController) Get() {
	this.Layout = "layouts/default.html.tpl"
	this.TplNames = "profile/index.html.tpl"
	user, err := models.Users().FindByName("admin")
	if err != nil {
		return
	}
	keys, err := user.DataKeys()
	if err != nil {
		return
	}
	data := make(map[string]interface{})
	for _, key := range keys {
		value, err := user.Data(key)
		if err == nil {
			if key == "currentlogin" || key == "lastlogin" {
				i, err := strconv.ParseInt(value, 10, 0)
				if err == nil {
					data[key] = time.Unix(i, 0)
				}
			} else {
				data[key] = value
			}
		}
	}
	this.Data["userData"] = data
}
<|endoftext|>


<commit_before><commit_msg>Exported NewClientCodec.<commit_after><|endoftext|>


<commit_before>package core

import (
	"time"

	"github.com/af83/edwig/logger"
	"github.com/af83/edwig/model"
)

type ModelGuardian struct {
	model.ClockConsumer
	model.UUIDConsumer

	stop        chan struct{}
	referential *Referential
}

func NewModelGuardian(referential *Referential) *ModelGuardian {
	return &ModelGuardian{referential: referential}
}

func (guardian *ModelGuardian) Start() {
	logger.Log.Debugf("Start models guardian")

	guardian.stop = make(chan struct{})
	go guardian.Run()
}

func (guardian *ModelGuardian) Stop() {
	if guardian.stop != nil {
		close(guardian.stop)
	}
}

func (guardian *ModelGuardian) Run() {
	c := guardian.Clock().After(10 * time.Second)

	for {
		select {
		case <-guardian.stop:
			return
		case <-c:
			guardian.refreshStopAreas()
			guardian.checkReloadModel()
			guardian.simulateActualAttributes()

			c = guardian.Clock().After(10 * time.Second)
		}
	}
}

func (guardian *ModelGuardian) checkReloadModel() {
	if guardian.Clock().Now().After(guardian.referential.NextReloadAt()) {
		guardian.referential.ReloadModel()
	}
}

func (guardian *ModelGuardian) refreshStopAreas() {
	// Open a new transaction
	tx := guardian.referential.NewTransaction()
	defer tx.Close()

	logger.Log.Debugf("Check StopAreas status")

	for _, stopArea := range tx.Model().StopAreas().FindAll() {
		now := guardian.Clock().Now()
		if !stopArea.CollectedAlways && !stopArea.CollectedUntil.After(now) {
			continue
		}

		stopAreaTx := guardian.referential.NewTransaction()
		defer stopAreaTx.Close()
		transactionnalStopArea, _ := stopAreaTx.Model().StopAreas().Find(stopArea.Id())

		outdated := now.Add(-1 * time.Minute)

		if transactionnalStopArea.RequestedAt().Before(outdated) && transactionnalStopArea.UpdatedAt().Before(outdated) {
			transactionnalStopArea.Requested(now)
			stopAreaTx.Model().StopAreas().Save(&transactionnalStopArea)
			stopAreaTx.Commit()

			stopAreaUpdateRequest := &StopAreaUpdateRequest{
				id:         StopAreaUpdateRequestId(guardian.NewUUID()),
				stopAreaId: transactionnalStopArea.Id(),
				createdAt:  guardian.Clock().Now(),
			}
			guardian.referential.CollectManager().UpdateStopArea(stopAreaUpdateRequest)
		}
	}
}

func (guardian *ModelGuardian) simulateActualAttributes() {
	tx := guardian.referential.NewTransaction()
	defer tx.Close()

	for _, stopVisit := range tx.Model().StopVisits().FindAll() {
		if stopVisit.IsCollected() == true {
			return
		}

		stopVisitTx := guardian.referential.NewTransaction()
		defer stopVisitTx.Close()

		transactionnalStopVisit, _ := tx.Model().StopVisits().Find(stopVisit.Id())
		simulator := NewActualAttributesSimulator(&transactionnalStopVisit)
		simulator.SetClock(guardian.Clock())
		if simulator.Simulate() {
			transactionnalStopVisit.Save()
			stopVisitTx.Commit()
		} else {
			stopVisitTx.Rollback()
		}
	}
}

type ActualAttributesSimulator struct {
	model.ClockConsumer

	stopVisit *model.StopVisit
	now       time.Time
}

func NewActualAttributesSimulator(stopVisit *model.StopVisit) *ActualAttributesSimulator {
	return &ActualAttributesSimulator{stopVisit: stopVisit}
}

func (simulator *ActualAttributesSimulator) Now() time.Time {
	if simulator.now.IsZero() {
		simulator.now = simulator.Clock().Now()
	}
	return simulator.now
}

func (simulator *ActualAttributesSimulator) ArrivalTime() time.Time {
	return simulator.stopVisit.Schedules.ArrivalTimeFromKind([]model.StopVisitScheduleType{"aimed", "expected"})
}

func (simulator *ActualAttributesSimulator) AfterArrivalTime() bool {
	return simulator.Clock().Now().After(simulator.ArrivalTime())
}

func (simulator *ActualAttributesSimulator) DepartureTime() time.Time {
	return simulator.stopVisit.Schedules.DepartureTimeFromKind([]model.StopVisitScheduleType{"aimed", "expected"})
}

func (simulator *ActualAttributesSimulator) AfterDepartureTime() bool {
	return simulator.Clock().Now().After(simulator.DepartureTime())
}

func (simulator *ActualAttributesSimulator) Simulate() bool {
	if simulator.stopVisit.IsCollected() == true {
		return false
	}

	return simulator.simulateArrival() || simulator.simulateDeparture()
}

func (simulator *ActualAttributesSimulator) simulateArrival() bool {
	if simulator.AfterArrivalTime() && simulator.CanArrive() {
		simulator.stopVisit.ArrivalStatus = model.STOP_VISIT_ARRIVAL_ARRIVED
		simulator.stopVisit.Schedules.SetArrivalTime(model.STOP_VISIT_SCHEDULE_ACTUAL, simulator.Now())

		logger.Log.Printf("Set StopVisit %s ArrivalStatus at %s", simulator.stopVisit.Id(), model.STOP_VISIT_ARRIVAL_ARRIVED)

		if !simulator.AfterDepartureTime() {
			simulator.stopVisit.VehicleAtStop = true
			logger.Log.Printf("Set StopVisit %s VehicleAtStop at true", simulator.stopVisit.Id())
		}

		return true
	}

	return false
}

func (simulator *ActualAttributesSimulator) CanArrive() bool {
	switch simulator.stopVisit.ArrivalStatus {
	case model.STOP_VISIT_ARRIVAL_ONTIME, model.STOP_VISIT_ARRIVAL_EARLY, model.STOP_VISIT_ARRIVAL_DELAYED:
		return true
	default:
		return false
	}
}

func (simulator *ActualAttributesSimulator) CanDepart() bool {
	switch simulator.stopVisit.DepartureStatus {
	case model.STOP_VISIT_DEPARTURE_ONTIME, model.STOP_VISIT_DEPARTURE_EARLY, model.STOP_VISIT_DEPARTURE_DELAYED:
		return true
	default:
		return false
	}
}

func (simulator *ActualAttributesSimulator) simulateDeparture() bool {
	if simulator.AfterDepartureTime() && simulator.CanDepart() {
		simulator.stopVisit.DepartureStatus = model.STOP_VISIT_DEPARTURE_DEPARTED

		simulator.stopVisit.Schedules.SetDepartureTime(model.STOP_VISIT_SCHEDULE_ACTUAL, simulator.Now())
		simulator.stopVisit.VehicleAtStop = false

		logger.Log.Printf("Set StopVisit %s DepartureStatus at %s", simulator.stopVisit.Id(), model.STOP_VISIT_DEPARTURE_DEPARTED)

		return true
	}
	return false
}
<commit_msg>Fixes ModelGuardian#simulateActualAttributes. continue and not return when StopVisit isn't collected. Refs #2826<commit_after>package core

import (
	"time"

	"github.com/af83/edwig/logger"
	"github.com/af83/edwig/model"
)

type ModelGuardian struct {
	model.ClockConsumer
	model.UUIDConsumer

	stop        chan struct{}
	referential *Referential
}

func NewModelGuardian(referential *Referential) *ModelGuardian {
	return &ModelGuardian{referential: referential}
}

func (guardian *ModelGuardian) Start() {
	logger.Log.Debugf("Start models guardian")

	guardian.stop = make(chan struct{})
	go guardian.Run()
}

func (guardian *ModelGuardian) Stop() {
	if guardian.stop != nil {
		close(guardian.stop)
	}
}

func (guardian *ModelGuardian) Run() {
	c := guardian.Clock().After(10 * time.Second)

	for {
		select {
		case <-guardian.stop:
			return
		case <-c:
			logger.Log.Debugf("Model guardian visit")

			guardian.refreshStopAreas()
			guardian.checkReloadModel()
			guardian.simulateActualAttributes()

			c = guardian.Clock().After(10 * time.Second)
		}
	}
}

func (guardian *ModelGuardian) checkReloadModel() {
	if guardian.Clock().Now().After(guardian.referential.NextReloadAt()) {
		guardian.referential.ReloadModel()
	}
}

func (guardian *ModelGuardian) refreshStopAreas() {
	// Open a new transaction
	tx := guardian.referential.NewTransaction()
	defer tx.Close()

	for _, stopArea := range tx.Model().StopAreas().FindAll() {
		now := guardian.Clock().Now()
		if !stopArea.CollectedAlways && !stopArea.CollectedUntil.After(now) {
			continue
		}

		stopAreaTx := guardian.referential.NewTransaction()
		defer stopAreaTx.Close()
		transactionnalStopArea, _ := stopAreaTx.Model().StopAreas().Find(stopArea.Id())

		outdated := now.Add(-1 * time.Minute)

		if transactionnalStopArea.RequestedAt().Before(outdated) && transactionnalStopArea.UpdatedAt().Before(outdated) {
			transactionnalStopArea.Requested(now)
			stopAreaTx.Model().StopAreas().Save(&transactionnalStopArea)
			stopAreaTx.Commit()

			stopAreaUpdateRequest := &StopAreaUpdateRequest{
				id:         StopAreaUpdateRequestId(guardian.NewUUID()),
				stopAreaId: transactionnalStopArea.Id(),
				createdAt:  guardian.Clock().Now(),
			}
			guardian.referential.CollectManager().UpdateStopArea(stopAreaUpdateRequest)
		}
	}
}

func (guardian *ModelGuardian) simulateActualAttributes() {
	tx := guardian.referential.NewTransaction()
	defer tx.Close()

	for _, stopVisit := range tx.Model().StopVisits().FindAll() {
		if stopVisit.IsCollected() == true {
			continue
		}

		logger.Log.Debugf("Simulate actual attributes on StopVisit %v", stopVisit.Id())

		stopVisitTx := guardian.referential.NewTransaction()
		defer stopVisitTx.Close()

		transactionnalStopVisit, _ := tx.Model().StopVisits().Find(stopVisit.Id())
		simulator := NewActualAttributesSimulator(&transactionnalStopVisit)
		simulator.SetClock(guardian.Clock())
		if simulator.Simulate() {
			transactionnalStopVisit.Save()
			stopVisitTx.Commit()
		} else {
			stopVisitTx.Rollback()
		}
	}
}

type ActualAttributesSimulator struct {
	model.ClockConsumer

	stopVisit *model.StopVisit
	now       time.Time
}

func NewActualAttributesSimulator(stopVisit *model.StopVisit) *ActualAttributesSimulator {
	return &ActualAttributesSimulator{stopVisit: stopVisit}
}

func (simulator *ActualAttributesSimulator) Now() time.Time {
	if simulator.now.IsZero() {
		simulator.now = simulator.Clock().Now()
	}
	return simulator.now
}

func (simulator *ActualAttributesSimulator) ArrivalTime() time.Time {
	return simulator.stopVisit.Schedules.ArrivalTimeFromKind([]model.StopVisitScheduleType{"aimed", "expected"})
}

func (simulator *ActualAttributesSimulator) AfterArrivalTime() bool {
	return simulator.Clock().Now().After(simulator.ArrivalTime())
}

func (simulator *ActualAttributesSimulator) DepartureTime() time.Time {
	return simulator.stopVisit.Schedules.DepartureTimeFromKind([]model.StopVisitScheduleType{"aimed", "expected"})
}

func (simulator *ActualAttributesSimulator) AfterDepartureTime() bool {
	return simulator.Clock().Now().After(simulator.DepartureTime())
}

func (simulator *ActualAttributesSimulator) Simulate() bool {
	if simulator.stopVisit.IsCollected() == true {
		return false
	}

	return simulator.simulateArrival() || simulator.simulateDeparture()
}

func (simulator *ActualAttributesSimulator) simulateArrival() bool {
	if simulator.AfterArrivalTime() && simulator.CanArrive() {
		simulator.stopVisit.ArrivalStatus = model.STOP_VISIT_ARRIVAL_ARRIVED
		simulator.stopVisit.Schedules.SetArrivalTime(model.STOP_VISIT_SCHEDULE_ACTUAL, simulator.Now())

		logger.Log.Printf("Set StopVisit %s ArrivalStatus at %s", simulator.stopVisit.Id(), model.STOP_VISIT_ARRIVAL_ARRIVED)

		if !simulator.AfterDepartureTime() {
			simulator.stopVisit.VehicleAtStop = true
			logger.Log.Printf("Set StopVisit %s VehicleAtStop at true", simulator.stopVisit.Id())
		}

		return true
	}

	return false
}

func (simulator *ActualAttributesSimulator) CanArrive() bool {
	switch simulator.stopVisit.ArrivalStatus {
	case model.STOP_VISIT_ARRIVAL_ONTIME, model.STOP_VISIT_ARRIVAL_EARLY, model.STOP_VISIT_ARRIVAL_DELAYED:
		return true
	default:
		return false
	}
}

func (simulator *ActualAttributesSimulator) CanDepart() bool {
	switch simulator.stopVisit.DepartureStatus {
	case model.STOP_VISIT_DEPARTURE_ONTIME, model.STOP_VISIT_DEPARTURE_EARLY, model.STOP_VISIT_DEPARTURE_DELAYED:
		return true
	default:
		return false
	}
}

func (simulator *ActualAttributesSimulator) simulateDeparture() bool {
	if simulator.AfterDepartureTime() && simulator.CanDepart() {
		simulator.stopVisit.DepartureStatus = model.STOP_VISIT_DEPARTURE_DEPARTED

		simulator.stopVisit.Schedules.SetDepartureTime(model.STOP_VISIT_SCHEDULE_ACTUAL, simulator.Now())
		simulator.stopVisit.VehicleAtStop = false

		logger.Log.Printf("Set StopVisit %s DepartureStatus at %s", simulator.stopVisit.Id(), model.STOP_VISIT_DEPARTURE_DEPARTED)

		return true
	}
	return false
}
<|endoftext|>


<commit_before><commit_msg>chame: omit exp/nbf if its value is null<commit_after><|endoftext|>