<commit_before>/*
Package compose provides a Go wrapper around Docker Compose, useful for integration testing.

	// Define Compose config.
	var composeYML =`
	test_mockserver:
	  container_name: ms
	  image: jamesdbloom/mockserver
	  ports:
	    - "10000:1080"
	    - "1090"
	test_postgres:
	  container_name: pg
	  image: postgres
	  ports:
	    - "5432"

	// Start containers.
	c, err := compose.Start(composeYML, true, true)
	if err != nil {
		panic(err)
	}
	defer compose.Kill()

	// Build MockServer public URL.
	mockServerURL := fmt.Sprintf(
		"http://%v:%v",
		compose.MustInferDockerHost(),
		c.Containers["ms"].MustGetFirstPublicPort(1080, "tcp"))

	// Wait for MockServer to start accepting connections.
	MustConnectWithDefaults(func() error {
		_, err := http.Get(mockServerURL)
		return err
	})
	...
*/
package compose

import (
	"fmt"
	"log"
	"os"
	"regexp"
	"strings"
)

// Compose is the main type exported by the package, used to interact with a running Docker Compose configuration.
type Compose struct {
	FileName   string
	Containers map[string]*Container
}

var (
	logger           = log.New(os.Stdout, "go-compose: ", log.LstdFlags)
	replaceEnvRegexp = regexp.MustCompile("\\$\\{[^\\}]+\\}")
	composeUpRegexp  = regexp.MustCompile("(?m:^docker start <- \\(u'(.*)'\\)$)")
)

const (
	composeProjectName = "compose"
)

// Start starts a Docker Compose configuration.
// If forcePull is true, it attempts do pull newer versions of the images.
// If rmFirst is true, it attempts to kill and delete containers before starting new ones.
func Start(dockerComposeYML string, forcePull, rmFirst bool) (*Compose, error) {
	logger.Println("initializing...")
	dockerComposeYML = replaceEnv(dockerComposeYML)

	fName, err := writeTmp(dockerComposeYML)
	if err != nil {
		return nil, err
	}

	ids, err := startCompose(fName, forcePull, rmFirst)
	if err != nil {
		return nil, err
	}

	containers := make(map[string]*Container)

	for _, id := range ids {
		container, err := Inspect(id)
		if err != nil {
			return nil, err
		}
		if !container.State.Running {
			return nil, fmt.Errorf("compose: container '%v' is not running", container.Name)
		}
		containers[container.Name[1:]] = container
	}

	return &Compose{FileName: fName, Containers: containers}, nil
}

// MustStart is like Start, but panics on error.
func MustStart(dockerComposeYML string, forcePull, killFirst bool) *Compose {
	compose, err := Start(dockerComposeYML, forcePull, killFirst)
	if err != nil {
		panic(err)
	}
	return compose
}

// Kill kills any running containers for the current configuration.
func (c *Compose) Kill() error {
	logger.Println("killing containers...")
	_, err := runCompose(c.FileName, "kill")
	if err == nil {
		logger.Println("containers killed")
		return nil
	}
	return fmt.Errorf("compose: error killing containers: %v", err)
}

// MustKill is like Kill, but panics on error.
func (c *Compose) MustKill() {
	if err := c.Kill(); err != nil {
		panic(err)
	}
}

func replaceEnv(dockerComposeYML string) string {
	return replaceEnvRegexp.ReplaceAllStringFunc(dockerComposeYML, replaceEnvFunc)
}

func replaceEnvFunc(s string) string {
	return os.Getenv(strings.TrimSpace(s[2 : len(s)-1]))
}

func startCompose(fName string, forcePull, rmFirst bool) ([]string, error) {
	if forcePull {
		logger.Println("pulling images...")
		if _, err := runCompose(fName, "pull"); err != nil {
			return nil, fmt.Errorf("compose: error pulling images: %v", err)
		}
	}

	if rmFirst {
		logger.Println("removing stale containers...")
		_, err := runCompose(fName, "kill")
		if err != nil {
			return nil, fmt.Errorf("compose: error killing stale containers: %v", err)
		}
		logger.Println("killing stale containers...")
		_, err = runCompose(fName, "rm", "--force")
		if err != nil {
			return nil, fmt.Errorf("compose: error removing stale containers: %v", err)
		}
	}

	logger.Println("starting containers...")
	out, err := runCompose(fName, "--verbose", "up", "-d")
	if err != nil {
		return nil, fmt.Errorf("compose: error starting containers: %v", err)
	}
	logger.Println("containers started")

	matches := composeUpRegexp.FindAllStringSubmatch(out, -1)
	ids := make([]string, 0, len(matches))
	for _, match := range matches {
		ids = append(ids, match[1])
	}

	return ids, nil
}

func runCompose(fName string, otherArgs ...string) (string, error) {
	args := []string{"-f", fName, "-p", composeProjectName}
	args = append(args, otherArgs...)
	return runCmd("docker-compose", args...)
}
<commit_msg>Fix typo in documentation.<commit_after>/*
Package compose provides a Go wrapper around Docker Compose, useful for integration testing.

	// Define Compose config.
	var composeYML =`
	test_mockserver:
	  container_name: ms
	  image: jamesdbloom/mockserver
	  ports:
	    - "10000:1080"
	    - "1090"
	test_postgres:
	  container_name: pg
	  image: postgres
	  ports:
	    - "5432"
	`

	// Start containers.
	c, err := compose.Start(composeYML, true, true)
	if err != nil {
		panic(err)
	}
	defer compose.Kill()

	// Build MockServer public URL.
	mockServerURL := fmt.Sprintf(
		"http://%v:%v",
		compose.MustInferDockerHost(),
		c.Containers["ms"].MustGetFirstPublicPort(1080, "tcp"))

	// Wait for MockServer to start accepting connections.
	MustConnectWithDefaults(func() error {
		_, err := http.Get(mockServerURL)
		return err
	})
	...
*/
package compose

import (
	"fmt"
	"log"
	"os"
	"regexp"
	"strings"
)

// Compose is the main type exported by the package, used to interact with a running Docker Compose configuration.
type Compose struct {
	FileName   string
	Containers map[string]*Container
}

var (
	logger           = log.New(os.Stdout, "go-compose: ", log.LstdFlags)
	replaceEnvRegexp = regexp.MustCompile("\\$\\{[^\\}]+\\}")
	composeUpRegexp  = regexp.MustCompile("(?m:^docker start <- \\(u'(.*)'\\)$)")
)

const (
	composeProjectName = "compose"
)

// Start starts a Docker Compose configuration.
// If forcePull is true, it attempts do pull newer versions of the images.
// If rmFirst is true, it attempts to kill and delete containers before starting new ones.
func Start(dockerComposeYML string, forcePull, rmFirst bool) (*Compose, error) {
	logger.Println("initializing...")
	dockerComposeYML = replaceEnv(dockerComposeYML)

	fName, err := writeTmp(dockerComposeYML)
	if err != nil {
		return nil, err
	}

	ids, err := startCompose(fName, forcePull, rmFirst)
	if err != nil {
		return nil, err
	}

	containers := make(map[string]*Container)

	for _, id := range ids {
		container, err := Inspect(id)
		if err != nil {
			return nil, err
		}
		if !container.State.Running {
			return nil, fmt.Errorf("compose: container '%v' is not running", container.Name)
		}
		containers[container.Name[1:]] = container
	}

	return &Compose{FileName: fName, Containers: containers}, nil
}

// MustStart is like Start, but panics on error.
func MustStart(dockerComposeYML string, forcePull, killFirst bool) *Compose {
	compose, err := Start(dockerComposeYML, forcePull, killFirst)
	if err != nil {
		panic(err)
	}
	return compose
}

// Kill kills any running containers for the current configuration.
func (c *Compose) Kill() error {
	logger.Println("killing containers...")
	_, err := runCompose(c.FileName, "kill")
	if err == nil {
		logger.Println("containers killed")
		return nil
	}
	return fmt.Errorf("compose: error killing containers: %v", err)
}

// MustKill is like Kill, but panics on error.
func (c *Compose) MustKill() {
	if err := c.Kill(); err != nil {
		panic(err)
	}
}

func replaceEnv(dockerComposeYML string) string {
	return replaceEnvRegexp.ReplaceAllStringFunc(dockerComposeYML, replaceEnvFunc)
}

func replaceEnvFunc(s string) string {
	return os.Getenv(strings.TrimSpace(s[2 : len(s)-1]))
}

func startCompose(fName string, forcePull, rmFirst bool) ([]string, error) {
	if forcePull {
		logger.Println("pulling images...")
		if _, err := runCompose(fName, "pull"); err != nil {
			return nil, fmt.Errorf("compose: error pulling images: %v", err)
		}
	}

	if rmFirst {
		logger.Println("removing stale containers...")
		_, err := runCompose(fName, "kill")
		if err != nil {
			return nil, fmt.Errorf("compose: error killing stale containers: %v", err)
		}
		logger.Println("killing stale containers...")
		_, err = runCompose(fName, "rm", "--force")
		if err != nil {
			return nil, fmt.Errorf("compose: error removing stale containers: %v", err)
		}
	}

	logger.Println("starting containers...")
	out, err := runCompose(fName, "--verbose", "up", "-d")
	if err != nil {
		return nil, fmt.Errorf("compose: error starting containers: %v", err)
	}
	logger.Println("containers started")

	matches := composeUpRegexp.FindAllStringSubmatch(out, -1)
	ids := make([]string, 0, len(matches))
	for _, match := range matches {
		ids = append(ids, match[1])
	}

	return ids, nil
}

func runCompose(fName string, otherArgs ...string) (string, error) {
	args := []string{"-f", fName, "-p", composeProjectName}
	args = append(args, otherArgs...)
	return runCmd("docker-compose", args...)
}
<|endoftext|>


<commit_before>package statsd

import (
	"fmt"
	"github.com/kisielk/cmd"
	"net"
)

// DefaultConsoleAddr is the default address on which a ConsoleServer will listen
const DefaultConsoleAddr = ":8126"

// ConsoleServer is an object that listens for telnet connection on a TCP address Addr
// and provides a console interface to a manage a MetricAggregator
type ConsoleServer struct {
	Addr       string
	Aggregator *MetricAggregator
}

// ListenAndServe listens on the ConsoleServer's TCP network address and then calls Serve
func (s *ConsoleServer) ListenAndServe() error {
	addr := s.Addr
	if addr == "" {
		addr = DefaultConsoleAddr
	}
	l, err := net.Listen("tcp", addr)
	if err != nil {
		return err
	}
	return s.Serve(l)
}

// Serve accepts incoming connections on the listener and serves them a console interface to
// the MetricAggregator
func (s *ConsoleServer) Serve(l net.Listener) error {
	defer l.Close()
	for {
		c, err := l.Accept()
		if err != nil {
			return err
		}
		console := consoleConn{c, s}
		go console.serve()
	}
	panic("not reached")
}

// consoleConn represents a single ConsoleServer connection
type consoleConn struct {
	conn   net.Conn
	server *ConsoleServer
}

// serve reads from the consoleConn and responds to incoming requests
func (c *consoleConn) serve() {
	defer c.conn.Close()

	commands := map[string]cmd.CmdFn{
		"help": func(args []string) (string, error) {
			return "Commands: stats, counters, timers, gauges, delcounters, deltimers, delgauges, quit\n", nil
		},
		"stats": func(args []string) (string, error) {
			c.server.Aggregator.Lock()
			defer c.server.Aggregator.Unlock()
			return fmt.Sprintf(
				"Invalid messages received: %d\n"+
					"Last message received: %s\n"+
					"Last flush to Graphite: %s\n"+
					"Last error from Graphite: %s\n",
				c.server.Aggregator.Stats.BadLines,
				c.server.Aggregator.Stats.LastMessage,
				c.server.Aggregator.Stats.LastFlush,
				c.server.Aggregator.Stats.LastFlushError), nil
		},
		"counters": func(args []string) (string, error) {
			c.server.Aggregator.Lock()
			defer c.server.Aggregator.Unlock()
			return fmt.Sprintln(c.server.Aggregator.Counters), nil
		},
		"timers": func(args []string) (string, error) {
			c.server.Aggregator.Lock()
			defer c.server.Aggregator.Unlock()
			return fmt.Sprintln(c.server.Aggregator.Timers), nil
		},
		"gauges": func(args []string) (string, error) {
			c.server.Aggregator.Lock()
			defer c.server.Aggregator.Unlock()
			return fmt.Sprintln(c.server.Aggregator.Gauges), nil
		},
		"delcounters": func(args []string) (string, error) {
			c.server.Aggregator.Lock()
			defer c.server.Aggregator.Unlock()
			i := 0
			for _, k := range args {
				delete(c.server.Aggregator.Counters, k)
				i++
			}
			return fmt.Sprintf("deleted %d counters\n", i), nil
		},
		"deltimers": func(args []string) (string, error) {
			c.server.Aggregator.Lock()
			defer c.server.Aggregator.Unlock()
			i := 0
			for _, k := range args {
				delete(c.server.Aggregator.Timers, k)
				i++
			}
			return fmt.Sprintf("deleted %d timers\n", i), nil
		},
		"delgauges": func(args []string) (string, error) {
			c.server.Aggregator.Lock()
			defer c.server.Aggregator.Unlock()
			i := 0
			for _, k := range args {
				delete(c.server.Aggregator.Gauges, k)
				i++
			}
			return fmt.Sprintf("deleted %d gauges\n", i), nil
		},
		"quit": func(args []string) (string, error) {
			return "goodbye\n", fmt.Errorf("client quit")
		},
	}

	console := cmd.New(commands, c.conn, c.conn)
	console.Prompt = "console> "
	console.Loop()
}
<commit_msg>my fork<commit_after>package statsd

import (
	"fmt"
	"github.com/fabware/cmd"
	"net"
)

// DefaultConsoleAddr is the default address on which a ConsoleServer will listen
const DefaultConsoleAddr = ":8126"

// ConsoleServer is an object that listens for telnet connection on a TCP address Addr
// and provides a console interface to a manage a MetricAggregator
type ConsoleServer struct {
	Addr       string
	Aggregator *MetricAggregator
}

// ListenAndServe listens on the ConsoleServer's TCP network address and then calls Serve
func (s *ConsoleServer) ListenAndServe() error {
	addr := s.Addr
	if addr == "" {
		addr = DefaultConsoleAddr
	}
	l, err := net.Listen("tcp", addr)
	if err != nil {
		return err
	}
	return s.Serve(l)
}

// Serve accepts incoming connections on the listener and serves them a console interface to
// the MetricAggregator
func (s *ConsoleServer) Serve(l net.Listener) error {
	defer l.Close()
	for {
		c, err := l.Accept()
		if err != nil {
			return err
		}
		console := consoleConn{c, s}
		go console.serve()
	}
	panic("not reached")
}

// consoleConn represents a single ConsoleServer connection
type consoleConn struct {
	conn   net.Conn
	server *ConsoleServer
}

// serve reads from the consoleConn and responds to incoming requests
func (c *consoleConn) serve() {
	defer c.conn.Close()

	commands := map[string]cmd.CmdFn{
		"help": func(args []string) (string, error) {
			return "Commands: stats, counters, timers, gauges, delcounters, deltimers, delgauges, quit\n", nil
		},
		"stats": func(args []string) (string, error) {
			c.server.Aggregator.Lock()
			defer c.server.Aggregator.Unlock()
			return fmt.Sprintf(
				"Invalid messages received: %d\n"+
					"Last message received: %s\n"+
					"Last flush to Graphite: %s\n"+
					"Last error from Graphite: %s\n",
				c.server.Aggregator.Stats.BadLines,
				c.server.Aggregator.Stats.LastMessage,
				c.server.Aggregator.Stats.LastFlush,
				c.server.Aggregator.Stats.LastFlushError), nil
		},
		"counters": func(args []string) (string, error) {
			c.server.Aggregator.Lock()
			defer c.server.Aggregator.Unlock()
			return fmt.Sprintln(c.server.Aggregator.Counters), nil
		},
		"timers": func(args []string) (string, error) {
			c.server.Aggregator.Lock()
			defer c.server.Aggregator.Unlock()
			return fmt.Sprintln(c.server.Aggregator.Timers), nil
		},
		"gauges": func(args []string) (string, error) {
			c.server.Aggregator.Lock()
			defer c.server.Aggregator.Unlock()
			return fmt.Sprintln(c.server.Aggregator.Gauges), nil
		},
		"delcounters": func(args []string) (string, error) {
			c.server.Aggregator.Lock()
			defer c.server.Aggregator.Unlock()
			i := 0
			for _, k := range args {
				delete(c.server.Aggregator.Counters, k)
				i++
			}
			return fmt.Sprintf("deleted %d counters\n", i), nil
		},
		"deltimers": func(args []string) (string, error) {
			c.server.Aggregator.Lock()
			defer c.server.Aggregator.Unlock()
			i := 0
			for _, k := range args {
				delete(c.server.Aggregator.Timers, k)
				i++
			}
			return fmt.Sprintf("deleted %d timers\n", i), nil
		},
		"delgauges": func(args []string) (string, error) {
			c.server.Aggregator.Lock()
			defer c.server.Aggregator.Unlock()
			i := 0
			for _, k := range args {
				delete(c.server.Aggregator.Gauges, k)
				i++
			}
			return fmt.Sprintf("deleted %d gauges\n", i), nil
		},
		"quit": func(args []string) (string, error) {
			return "goodbye\n", fmt.Errorf("client quit")
		},
	}

	console := cmd.New(commands, c.conn, c.conn)
	console.Prompt = "console> "
	console.Loop()
}
<|endoftext|>


<commit_before>package main

import "fmt"

type node struct {
	x int
	y int
}

func main() {

	var nodes, tempNodes []node
	n := node{0, 0}
	max := 3
	tempNodes = append(tempNodes, n)

	for i := 1; i <= max; i++ {
		for _, _n := range tempNodes {

			if _n.x < max {
				nn := node{_n.x + 1, _n.y}
				nodes = append(nodes, nn)
			}

			if _n.y < max {
				nn := node{_n.x, _n.y + 1}
				nodes = append(nodes, nn)
			}
		}
		tempNodes = nodes
		nodes = nil
	}

	fmt.Println(n)
	fmt.Println(nodes)
	fmt.Println(tempNodes)
	fmt.Println(max)
}
<commit_msg>update problem 15 solution<commit_after>package main

import "fmt"

type node struct {
	x int
	y int
}

func done(ns []node, max int) (bool, int) {
	count := 0
	for _, n := range ns {
		if n.x < max || n.y < max {
			return false, count
		}
		count++
	}
	return true, count
}

func main() {

	max := 10

	n := node{0, 0}

	var ns1, ns2 []node

	ns1 = append(ns1, n)

	for {
		for _, _n := range ns1 {
			if _n.x < max {
				tn := node{_n.x + 1, _n.y}
				ns2 = append(ns2, tn)
			}

			if _n.y < max {
				tn := node{_n.x, _n.y + 1}
				ns2 = append(ns2, tn)
			}
		}

		done, count := done(ns2, max)

		fmt.Println(len(ns2))
		//fmt.Println(ns2)

		if done {
			fmt.Println(count)
			break
		}

		ns1 = ns2
		ns2 = nil
	}

}
<|endoftext|>


<commit_before>package store_test

import (
	"bytes"
	"fmt"
	. "launchpad.net/gocheck"
	"launchpad.net/mgo"
	"os/exec"
	"time"
)

// ----------------------------------------------------------------------------
// The mgo test suite

type MgoSuite struct {
	Addr    string
	Session *mgo.Session
	output  bytes.Buffer
	server  *exec.Cmd
}

func (s *MgoSuite) SetUpSuite(c *C) {
	mgo.SetDebug(true)
	mgo.SetStats(true)
	dbdir := c.MkDir()
	args := []string{
		"--dbpath", dbdir,
		"--bind_ip", "127.0.0.1",
		"--port", "50017",
		"--nssize", "1",
		"--noprealloc",
		"--smallfiles",
	}
	s.server = exec.Command("mongod", args...)
	s.server.Stdout = &s.output
	s.server.Stderr = &s.output
	err := s.server.Start()
	if err != nil {
		panic(err)
	}
}

func (s *MgoSuite) TearDownSuite(c *C) {
	s.server.Process.Kill()
	s.server.Process.Wait()
}

func (s *MgoSuite) SetUpTest(c *C) {
	fmt.Printf("SETUP 1")
	err := DropAll("localhost:50017")
	if err != nil {
		panic(err)
	}
	fmt.Printf("SETUP 2")
	mgo.SetLogger(c)
	mgo.ResetStats()
	s.Addr = "127.0.0.1:50017"
	s.Session, err = mgo.Dial(s.Addr)
	if err != nil {
		panic(err)
	}
}

func (s *MgoSuite) TearDownTest(c *C) {
	s.Session.Close()
	for i := 0; ; i++ {
		stats := mgo.GetStats()
		if stats.SocketsInUse == 0 && stats.SocketsAlive == 0 {
			break
		}
		if i == 20 {
			c.Fatal("Test left sockets in a dirty state")
		}
		c.Logf("Waiting for sockets to die: %d in use, %d alive", stats.SocketsInUse, stats.SocketsAlive)
		time.Sleep(5e8)
	}
}

func DropAll(mongourl string) (err error) {
	session, err := mgo.DialWithTimeout(mongourl, 10*time.Second)
	if err != nil {
		return err
	}
	defer session.Close()

	names, err := session.DatabaseNames()
	if err != nil {
		return err
	}
	for _, name := range names {
		switch name {
		case "admin", "local", "config":
		default:
			err = session.DB(name).DropDatabase()
			if err != nil {
				return err
			}
		}
	}
	return nil
}
<commit_msg>gaah, committed exploratory nonsense<commit_after>package store_test

import (
	"bytes"
	. "launchpad.net/gocheck"
	"launchpad.net/mgo"
	"os/exec"
	"time"
)

// ----------------------------------------------------------------------------
// The mgo test suite

type MgoSuite struct {
	Addr    string
	Session *mgo.Session
	output  bytes.Buffer
	server  *exec.Cmd
}

func (s *MgoSuite) SetUpSuite(c *C) {
	mgo.SetDebug(true)
	mgo.SetStats(true)
	dbdir := c.MkDir()
	args := []string{
		"--dbpath", dbdir,
		"--bind_ip", "127.0.0.1",
		"--port", "50017",
		"--nssize", "1",
		"--noprealloc",
		"--smallfiles",
	}
	s.server = exec.Command("mongod", args...)
	s.server.Stdout = &s.output
	s.server.Stderr = &s.output
	err := s.server.Start()
	if err != nil {
		panic(err)
	}
}

func (s *MgoSuite) TearDownSuite(c *C) {
	s.server.Process.Kill()
	s.server.Process.Wait()
}

func (s *MgoSuite) SetUpTest(c *C) {
	err := DropAll("localhost:50017")
	if err != nil {
		panic(err)
	}
	mgo.SetLogger(c)
	mgo.ResetStats()
	s.Addr = "127.0.0.1:50017"
	s.Session, err = mgo.Dial(s.Addr)
	if err != nil {
		panic(err)
	}
}

func (s *MgoSuite) TearDownTest(c *C) {
	s.Session.Close()
	for i := 0; ; i++ {
		stats := mgo.GetStats()
		if stats.SocketsInUse == 0 && stats.SocketsAlive == 0 {
			break
		}
		if i == 20 {
			c.Fatal("Test left sockets in a dirty state")
		}
		c.Logf("Waiting for sockets to die: %d in use, %d alive", stats.SocketsInUse, stats.SocketsAlive)
		time.Sleep(5e8)
	}
}

func DropAll(mongourl string) (err error) {
	session, err := mgo.DialWithTimeout(mongourl, 30*time.Second)
	if err != nil {
		return err
	}
	defer session.Close()

	names, err := session.DatabaseNames()
	if err != nil {
		return err
	}
	for _, name := range names {
		switch name {
		case "admin", "local", "config":
		default:
			err = session.DB(name).DropDatabase()
			if err != nil {
				return err
			}
		}
	}
	return nil
}
<|endoftext|>


<commit_before>// Package Wbzr provides tool to create a wooble in a given language and to package
// (wrap) some woobles.
package wbzr

import (
	"bytes"
	"io/ioutil"
	"text/template"

	"github.com/woobleio/wooblizer/wbzr/engine"
)

// ScriptLang are constants for implemented script languages.
type ScriptLang int

const (
	JSES5 ScriptLang = iota
)

type Wbzr struct {
	DomainsSec []string
	Scripts    []engine.Script

	lang     ScriptLang
	skeleton string
}

// New takes a script language which is used to inject and output a file.
func New(sl ScriptLang) *Wbzr {
	var skeleton string
	switch sl {
	case JSES5:
		skeleton = wbJses5
	default:
		panic("Language not supported")
	}

	return &Wbzr{
		nil,
		make([]engine.Script, 0),
		sl,
		skeleton,
	}
}

// Get returns an injected source.
func (wb *Wbzr) Get(name string) (engine.Script, error) {
	for _, sc := range wb.Scripts {
		if sc.GetName() == name {
			return sc, nil
		}
	}
	return nil, ErrUniqueName
}

// Inject injects a source code to be wooblized. It takes a name which must be
// unique. Src can be empty, it'll create a default object
func (wb *Wbzr) Inject(src string, name string) (engine.Script, error) {
	if _, err := wb.Get(name); err == nil {
		return nil, ErrUniqueName
	}
	var sc engine.Script
	var err error

	switch wb.lang {
	case JSES5:
		sc, err = engine.NewJSES5(src, name)
	}

	if err != nil {
		return nil, err
	}

	wb.Scripts = append(wb.Scripts, sc)
	return sc, nil
}

// InjectFile injects a source from a file.
func (wb *Wbzr) InjectFile(path string, name string) (engine.Script, error) {
	c, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, err
	}

	return wb.Inject(string(c[:]), name)
}

// Secure set some domains to protect the script and make it works only for specific domains
func (wb *Wbzr) Secure(domains ...string) {
	wb.DomainsSec = domains
}

func (wb *Wbzr) SecureAndWrap(domains ...string) (*bytes.Buffer, error) {
	wb.Secure(domains...)
	return wb.Wrap()
}

// Wrap packages some woobles (all the woobles injected in the Wbzr)
// and build a file which contains the wooble library.
func (wb *Wbzr) Wrap() (*bytes.Buffer, error) {
	for _, sc := range wb.Scripts {
		if _, err := sc.Build(); err != nil {
			return nil, err
		}
	}

	fns := template.FuncMap{
		"plus1": func(x int) int {
			return x + 1
		},
	}

	tmpl := template.Must(template.New("WbJSES5").Funcs(fns).Parse(wbJses5))

	var out bytes.Buffer
	if err := tmpl.Execute(&out, wb); err != nil {
		return nil, err
	}

	return &out, nil
}

// WooblyJSES5 is a Wooble creation template for JSES5
var WooblyJSES5 = `woobly = {
  // Use this attribute instead of document. Ex: this._doc.stuff
  // Use 'document' to access parent's document
  _doc: function() {return document},
  _init: function() {
    // Creation code at runtime
  },
  attribute: "a value (optionnal)",
  method: function(a, b) {
    // a method (optionnal)
  }
}`

var wbJses5 = `
function Wb(id) {
	{{if .DomainsSec}}
	{{$lenDoms := len .DomainsSec}}
	var ah = [{{range $i, $o := .DomainsSec}}"{{$o}}"{{if ne (plus1 $i) $lenDoms}},{{end}}{{end}}];
  var xx = ah.indexOf(window.location.hostname);
  if(ah.indexOf(window.location.hostname) == -1) {
  	console.log("Wooble error : domain restricted");
    return;
  }
	{{end}}

	if(window === this) {
  	return new Wb(id);
  }

  var cs = {
		{{$lenScripts := len .Scripts}}
  	{{range $i, $o := .Scripts}}"{{$o.GetName}}":{{"{"}}{{$o.GetSource}}{{"}"}}{{if ne (plus1 $i) $lenScripts}},{{end}}{{end}}
  }

  var c = cs[id];
  if(typeof c == 'undefined') {
  	console.log("Wooble error : creation", id, "not found");
    return undefined;
  }

  this.init = function (target) {
    if(document.querySelector(target) == null) {
    	console.log("Wooble error : Element", target, "not found in the document");
      return;
    }

    if("_buildDoc" in c) {
			if (!document.head.attachShadow) {
				// Browsers shadow dom support with polyfill
				var s = document.createElement('script');
				s.type = 'text/javascript';
				s.src = 'https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/1.0.0-rc.11/webcomponents-lite.js';
				document.getElementsByTagName('head')[0].appendChild(s);
				s.onload = function() {
					c._buildDoc(target);
				}
			} else {
				c._buildDoc(target);
			}
		}
    if("_buildStyle" in c) c._buildStyle();
    if("_init" in c) c._init();

		return c;
  }

  this.get = function() {
  	return c;
  }

  return this;
}
`
<commit_msg>Adds async JSES5<commit_after>// Package Wbzr provides tool to create a wooble in a given language and to package
// (wrap) some woobles.
package wbzr

import (
	"bytes"
	"io/ioutil"
	"text/template"

	"github.com/woobleio/wooblizer/wbzr/engine"
)

// ScriptLang are constants for implemented script languages.
type ScriptLang int

const (
	JSES5 ScriptLang = iota
)

type Wbzr struct {
	DomainsSec []string
	Scripts    []engine.Script

	lang     ScriptLang
	skeleton string
}

// New takes a script language which is used to inject and output a file.
func New(sl ScriptLang) *Wbzr {
	var skeleton string
	switch sl {
	case JSES5:
		skeleton = wbJses5
	default:
		panic("Language not supported")
	}

	return &Wbzr{
		nil,
		make([]engine.Script, 0),
		sl,
		skeleton,
	}
}

// Get returns an injected source.
func (wb *Wbzr) Get(name string) (engine.Script, error) {
	for _, sc := range wb.Scripts {
		if sc.GetName() == name {
			return sc, nil
		}
	}
	return nil, ErrUniqueName
}

// Inject injects a source code to be wooblized. It takes a name which must be
// unique. Src can be empty, it'll create a default object
func (wb *Wbzr) Inject(src string, name string) (engine.Script, error) {
	if _, err := wb.Get(name); err == nil {
		return nil, ErrUniqueName
	}
	var sc engine.Script
	var err error

	switch wb.lang {
	case JSES5:
		sc, err = engine.NewJSES5(src, name)
	}

	if err != nil {
		return nil, err
	}

	wb.Scripts = append(wb.Scripts, sc)
	return sc, nil
}

// InjectFile injects a source from a file.
func (wb *Wbzr) InjectFile(path string, name string) (engine.Script, error) {
	c, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, err
	}

	return wb.Inject(string(c[:]), name)
}

// Secure set some domains to protect the script and make it works only for specific domains
func (wb *Wbzr) Secure(domains ...string) {
	wb.DomainsSec = domains
}

func (wb *Wbzr) SecureAndWrap(domains ...string) (*bytes.Buffer, error) {
	wb.Secure(domains...)
	return wb.Wrap()
}

// Wrap packages some woobles (all the woobles injected in the Wbzr)
// and build a file which contains the wooble library.
func (wb *Wbzr) Wrap() (*bytes.Buffer, error) {
	for _, sc := range wb.Scripts {
		if _, err := sc.Build(); err != nil {
			return nil, err
		}
	}

	fns := template.FuncMap{
		"plus1": func(x int) int {
			return x + 1
		},
	}

	tmpl := template.Must(template.New("WbJSES5").Funcs(fns).Parse(wbJses5))

	var out bytes.Buffer
	if err := tmpl.Execute(&out, wb); err != nil {
		return nil, err
	}

	return &out, nil
}

// WooblyJSES5 is a Wooble creation template for JSES5
var WooblyJSES5 = `woobly = {
  // Use this attribute instead of document. Ex: this._doc.stuff
  // Use 'document' to access parent's document
  _doc: function() {return document},
  _init: function() {
    // Creation code at runtime
  },
  attribute: "a value (optionnal)",
  method: function(a, b) {
    // a method (optionnal)
  }
}`

var wbJses5 = `
function Wb(id) {
	{{if .DomainsSec}}
	{{$lenDoms := len .DomainsSec}}
	var ah = [{{range $i, $o := .DomainsSec}}"{{$o}}"{{if ne (plus1 $i) $lenDoms}},{{end}}{{end}}];
  var xx = ah.indexOf(window.location.hostname);
  if(ah.indexOf(window.location.hostname) == -1) {
  	console.log("Wooble error : domain restricted");
    return;
  }
	{{end}}

	if(window === this) {
  	return new Wb(id);
  }

  var cs = {
		{{$lenScripts := len .Scripts}}
  	{{range $i, $o := .Scripts}}"{{$o.GetName}}":{{"{"}}{{$o.GetSource}}{{"}"}}{{if ne (plus1 $i) $lenScripts}},{{end}}{{end}}
  }

  var c = cs[id];
  if(typeof c == 'undefined') {
  	console.log("Wooble error : creation", id, "not found");
    return undefined;
  }

  this.init = function (target) {
    if(document.querySelector(target) == null) {
    	console.log("Wooble error : Element", target, "not found in the document");
      return;
    }

		var t = this;
    return new Promise(function(r, e) {
    	if("_buildDoc" in c) {
        if (!document.head.attachShadow) {
          // Browsers shadow dom support with polyfill
          var s = document.createElement('script');
          s.type = 'text/javascript';
          s.src = 'https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/1.0.0-rc.11/webcomponents-lite.js';
          document.getElementsByTagName('head')[0].appendChild(s);
          s.onload = function() {
            t._build(target);
            r(c);
          }
        } else {
          t._build(target);
          r(c);
        }
      }
    });

		return c;
  }

	this._build = function(target) {
		c._buildDoc(target);
		if("_buildStyle" in c) c._buildStyle();
		if("_init" in c) c._init();
	}

  this.get = function() {
  	return c;
  }

  return this;
}
`
<|endoftext|>


<commit_before>package immortal

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"os/signal"
	"path/filepath"
	"strconv"
	"sync"
	"syscall"
	"testing"
	"time"
)

func TestHelperProcessSupervise(*testing.T) {
	if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
		return
	}
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, os.Kill)
	select {
	case <-c:
		os.Exit(1)
	case <-time.After(10 * time.Second):
		os.Exit(0)
	}
}

func TestHelperProcessSupervise2(*testing.T) {
	if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
		return
	}
	os.Exit(0)
}

func TestSupervise(t *testing.T) {
	log.SetOutput(ioutil.Discard)
	log.SetFlags(0)
	base := filepath.Base(os.Args[0]) // "exec.test"
	dir := filepath.Dir(os.Args[0])   // "/tmp/go-buildNNNN/os/exec/_test"
	if dir == "." {
		t.Skip("skipping; running test at root somehow")
	}
	parentDir := filepath.Dir(dir) // "/tmp/go-buildNNNN/os/exec"
	dirBase := filepath.Base(dir)  // "_test"
	if dirBase == "." {
		t.Skipf("skipping; unexpected shallow dir of %q", dir)
	}
	tmpfile, err := ioutil.TempFile("", "TestPidFile")
	if err != nil {
		t.Error(err)
	}
	defer os.Remove(tmpfile.Name()) // clean up
	cfg := &Config{
		Env:     map[string]string{"GO_WANT_HELPER_PROCESS": "1"},
		command: []string{filepath.Join(dirBase, base), "-test.run=TestHelperProcessSupervise", "--"},
		Cwd:     parentDir,
		ctrl:    true,
		Pid: Pid{
			Parent: filepath.Join(parentDir, "parent.pid"),
			Child:  filepath.Join(parentDir, "child.pid"),
			Follow: tmpfile.Name(),
		},
	}
	// to remove lock
	os.RemoveAll(filepath.Join(parentDir, "supervise"))
	d, err := New(cfg)
	if err != nil {
		t.Fatal(err)
	}
	time.Sleep(time.Second)
	fctrl, err := OpenFifo(filepath.Join(parentDir, "supervise/control"))
	if err != nil {
		t.Fatal(err)
	}
	go Supervise(d)
	defer func() {
		fmt.Fprintln(fctrl, "kill")
		fmt.Fprintln(fctrl, "exit")
	}()

	sup := &Sup{}

	time.Sleep(time.Second)

	// check pids
	parent_pid, err := sup.ReadPidFile(filepath.Join(parentDir, "parent.pid"))
	if err != nil {
		t.Error(err)
	}
	expect(t, os.Getpid(), parent_pid)
	child_pid, err := sup.ReadPidFile(filepath.Join(parentDir, "child.pid"))
	if err != nil {
		t.Error(err)
	}
	expect(t, true, child_pid > 0)

	fmt.Fprintln(fctrl, "t")
	time.Sleep(time.Second)
	newchild_pid, err := sup.ReadPidFile(filepath.Join(parentDir, "child.pid"))
	if err != nil {
		t.Error(err)
	}
	if child_pid == newchild_pid {
		t.Error("Expecting new child pid")
	}

	// test info
	syscall.Kill(parent_pid, syscall.SIGQUIT)
	time.Sleep(time.Second)

	// fake watch pid with other process
	cmd := exec.Command("sleep", "1")
	cmd.Start()
	go func() {
		cmd.Wait()
	}()
	watchPid := cmd.Process.Pid
	err = ioutil.WriteFile(tmpfile.Name(), []byte(strconv.Itoa(watchPid)), 0644)
	if err != nil {
		t.Error(err)
	}

	// reset
	fmt.Fprintln(fctrl, "t")

	select {
	case <-time.After(5 * time.Second):
		t.Error("time out")
	default:
		for sup.IsRunning(watchPid) {
			// wait mock watchpid to finish
			time.Sleep(2100 * time.Millisecond)
		}
		newchild_pid_after, err := sup.ReadPidFile(filepath.Join(parentDir, "child.pid"))
		if err != nil {
			t.Error(err)
		}
		if newchild_pid == newchild_pid_after {
			t.Error("Expecting different pids")
		}
	}
}

func TestSuperviseWait(t *testing.T) {
	log.SetOutput(ioutil.Discard)
	log.SetFlags(0)
	base := filepath.Base(os.Args[0]) // "exec.test"
	dir := filepath.Dir(os.Args[0])   // "/tmp/go-buildNNNN/os/exec/_test"
	if dir == "." {
		t.Skip("skipping; running test at root somehow")
	}
	parentDir := filepath.Dir(dir) // "/tmp/go-buildNNNN/os/exec"
	dirBase := filepath.Base(dir)  // "_test"
	if dirBase == "." {
		t.Skipf("skipping; unexpected shallow dir of %q", dir)
	}
	cfg := &Config{
		Env:     map[string]string{"GO_WANT_HELPER_PROCESS": "1"},
		command: []string{filepath.Join(dirBase, base), "-test.run=TestHelperProcessSupervise2", "--"},
		Cwd:     parentDir,
		ctrl:    true,
		Pid: Pid{
			Parent: filepath.Join(parentDir, "parent.pid"),
			Child:  filepath.Join(parentDir, "child.pid"),
		},
	}
	// to remove lock
	os.RemoveAll(filepath.Join(parentDir, "supervise"))
	d, err := New(cfg)
	if err != nil {
		t.Fatal(err)
	}
	time.Sleep(time.Second)
	fctrl, err := OpenFifo(filepath.Join(parentDir, "supervise/control"))
	if err != nil {
		t.Fatal(err)
	}
	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		defer wg.Done()
		Supervise(d)
	}()
	time.Sleep(2 * time.Second)
	fmt.Fprintln(fctrl, "exit")
	wg.Wait()
	expect(t, true, d.count >= 2)
}
<commit_msg>	modified:   supervise_test.go<commit_after>package immortal

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"os/signal"
	"path/filepath"
	"strconv"
	"sync"
	"syscall"
	"testing"
	"time"
)

func TestHelperProcessSupervise(*testing.T) {
	if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
		return
	}
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, os.Kill)
	select {
	case <-c:
		os.Exit(1)
	case <-time.After(10 * time.Second):
		os.Exit(0)
	}
}

func TestHelperProcessSupervise2(*testing.T) {
	if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
		return
	}
	os.Exit(0)
}

func TestSupervise(t *testing.T) {
	log.SetOutput(ioutil.Discard)
	log.SetFlags(0)
	base := filepath.Base(os.Args[0]) // "exec.test"
	dir := filepath.Dir(os.Args[0])   // "/tmp/go-buildNNNN/os/exec/_test"
	if dir == "." {
		t.Skip("skipping; running test at root somehow")
	}
	parentDir := filepath.Dir(dir) // "/tmp/go-buildNNNN/os/exec"
	dirBase := filepath.Base(dir)  // "_test"
	if dirBase == "." {
		t.Skipf("skipping; unexpected shallow dir of %q", dir)
	}
	tmpfile, err := ioutil.TempFile("", "TestPidFile")
	if err != nil {
		t.Error(err)
	}
	defer os.Remove(tmpfile.Name()) // clean up
	cfg := &Config{
		Env:     map[string]string{"GO_WANT_HELPER_PROCESS": "1"},
		command: []string{filepath.Join(dirBase, base), "-test.run=TestHelperProcessSupervise", "--"},
		Cwd:     parentDir,
		ctrl:    true,
		Pid: Pid{
			Parent: filepath.Join(parentDir, "parent.pid"),
			Child:  filepath.Join(parentDir, "child.pid"),
			Follow: tmpfile.Name(),
		},
	}
	// to remove lock
	os.RemoveAll(filepath.Join(parentDir, "supervise"))
	d, err := New(cfg)
	if err != nil {
		t.Fatal(err)
	}
	time.Sleep(time.Second)
	fctrl, err := OpenFifo(filepath.Join(parentDir, "supervise/control"))
	if err != nil {
		t.Fatal(err)
	}
	go Supervise(d)
	defer func() {
		fmt.Fprintln(fctrl, "kill")
		fmt.Fprintln(fctrl, "exit")
	}()

	sup := &Sup{}

	time.Sleep(time.Second)

	// check pids
	parent_pid, err := sup.ReadPidFile(filepath.Join(parentDir, "parent.pid"))
	if err != nil {
		t.Error(err)
	}
	expect(t, os.Getpid(), parent_pid)
	child_pid, err := sup.ReadPidFile(filepath.Join(parentDir, "child.pid"))
	if err != nil {
		t.Error(err)
	}
	expect(t, true, child_pid > 0)

	fmt.Fprintln(fctrl, "t")
	time.Sleep(time.Second)
	newchild_pid, err := sup.ReadPidFile(filepath.Join(parentDir, "child.pid"))
	if err != nil {
		t.Error(err)
	}
	if child_pid == newchild_pid {
		t.Error("Expecting new child pid")
	}

	// test info
	syscall.Kill(parent_pid, syscall.SIGQUIT)
	time.Sleep(time.Second)

	// fake watch pid with other process
	cmd := exec.Command("sleep", "1")
	cmd.Start()
	go func() {
		cmd.Wait()
	}()
	watchPid := cmd.Process.Pid
	err = ioutil.WriteFile(tmpfile.Name(), []byte(strconv.Itoa(watchPid)), 0644)
	if err != nil {
		t.Error(err)
	}

	// reset
	fmt.Fprintln(fctrl, "t")

	select {
	case <-time.After(5 * time.Second):
		t.Error("time out")
	default:
		for sup.IsRunning(watchPid) {
			// wait mock watchpid to finish
			time.Sleep(500 * time.Millisecond)
		}
		time.Sleep(500 * time.Millisecond)
		newchild_pid_after, err := sup.ReadPidFile(filepath.Join(parentDir, "child.pid"))
		if err != nil {
			t.Error(err)
		}
		if newchild_pid == newchild_pid_after {
			t.Error("Expecting different pids")
		}
	}
}

func TestSuperviseWait(t *testing.T) {
	log.SetOutput(ioutil.Discard)
	log.SetFlags(0)
	base := filepath.Base(os.Args[0]) // "exec.test"
	dir := filepath.Dir(os.Args[0])   // "/tmp/go-buildNNNN/os/exec/_test"
	if dir == "." {
		t.Skip("skipping; running test at root somehow")
	}
	parentDir := filepath.Dir(dir) // "/tmp/go-buildNNNN/os/exec"
	dirBase := filepath.Base(dir)  // "_test"
	if dirBase == "." {
		t.Skipf("skipping; unexpected shallow dir of %q", dir)
	}
	cfg := &Config{
		Env:     map[string]string{"GO_WANT_HELPER_PROCESS": "1"},
		command: []string{filepath.Join(dirBase, base), "-test.run=TestHelperProcessSupervise2", "--"},
		Cwd:     parentDir,
		ctrl:    true,
		Pid: Pid{
			Parent: filepath.Join(parentDir, "parent.pid"),
			Child:  filepath.Join(parentDir, "child.pid"),
		},
	}
	// to remove lock
	os.RemoveAll(filepath.Join(parentDir, "supervise"))
	d, err := New(cfg)
	if err != nil {
		t.Fatal(err)
	}
	time.Sleep(time.Second)
	fctrl, err := OpenFifo(filepath.Join(parentDir, "supervise/control"))
	if err != nil {
		t.Fatal(err)
	}
	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		defer wg.Done()
		Supervise(d)
	}()
	time.Sleep(2 * time.Second)
	fmt.Fprintln(fctrl, "exit")
	wg.Wait()
	expect(t, true, d.count >= 2)
}
<|endoftext|>


<commit_before>package wiki

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

	"github.com/cooper/quiki/wikifier"
)

// DisplayFile represents a plain text file to display.
type DisplayFile struct {

	// file name relative to wiki root.
	// path delimiter '/' is always used, regardless of OS.
	File string `json:"file,omitempty"`

	// absolute file path of the file.
	// OS-specific path delimiter is used.
	Path string `json:"path,omitempty"`

	// the plain text file content
	Content string

	// time when the file was last modified
	Modified *time.Time `json:"modified,omitempty"`
}

// DisplayFile returns the display result for a plain text file.
func (w *Wiki) DisplayFile(path string) interface{} {
	var r DisplayFile
	path = filepath.FromSlash(path) // just in case

	// ensure it can be made relative to dir.wiki
	relPath := w.relPath(path)
	if relPath == "" {
		return DisplayError{
			Error:         "Bad filepath",
			DetailedError: "File '" + path + "' cannot be made relative to '" + w.Opt.Dir.Wiki + "'",
		}
	}

	// file does not exist or can't be read
	fi, err := os.Lstat(path)
	if err != nil {
		return DisplayError{
			Error:         "File does not exist.",
			DetailedError: "File '" + path + "' error: " + err.Error(),
		}
	}

	// read file
	content, err := ioutil.ReadFile(path)
	if err != nil {
		return DisplayError{
			Error:         "Error reading file.",
			DetailedError: "File '" + path + "' error: " + err.Error(),
		}
	}

	// results
	mod := fi.ModTime()
	r.File = filepath.ToSlash(relPath)
	r.Path = path
	r.Modified = &mod
	r.Content = string(content)

	return r
}

func (w *Wiki) checkDirectories() {
	// TODO
	panic("unimplemented")
}

// relPath returns a path relative to the wiki root
// FIXME: check for ..???
func (w *Wiki) relPath(absPath string) string {
	wikiAbs, _ := filepath.Abs(w.Opt.Dir.Wiki)

	// can't resolve wiki path
	if wikiAbs == "" {
		return ""
	}

	// made it relative as-is
	if rel, err := filepath.Rel(wikiAbs, absPath); err == nil {
		return rel
	}

	// try to make it relative by resolving absPath as absolute
	absPath, _ = filepath.Abs(absPath)
	if absPath != "" {
		if rel, err := filepath.Rel(wikiAbs, absPath); err == nil {
			return rel
		}
	}

	return ""
}

func (w *Wiki) allPageFiles() []string {
	files, _ := wikifier.UniqueFilesInDir(w.Opt.Dir.Page, []string{"page", "md"}, false)
	return files
}

func (w *Wiki) allCategoryFiles(catType CategoryType) []string {
	dir := w.Opt.Dir.Category
	if catType != "" {
		dir = filepath.Join(dir, string(catType))
	}
	files, _ := wikifier.UniqueFilesInDir(dir, []string{"cat"}, false)
	return files
}

func (w *Wiki) allModelFiles() []string {
	files, _ := wikifier.UniqueFilesInDir(w.Opt.Dir.Model, []string{"model"}, false)
	return files
}

func (w *Wiki) allImageFiles() []string {
	files, _ := wikifier.UniqueFilesInDir(w.Opt.Dir.Image, []string{"png", "jpg", "jpeg"}, false)
	return files
}

// pathForPage returns the absolute path for a page.
func (w *Wiki) pathForPage(pageName string) string {

	// try lowercased version first (quiki style)
	lcPageName := wikifier.PageName(pageName)
	path, _ := filepath.Abs(filepath.Join(w.Opt.Dir.Page, lcPageName))

	// it doesn't exist; try non-lowercased version (markdown/etc)
	if _, err := os.Stat(path); err != nil {
		normalPageName := wikifier.PageName(pageName)
		normalPath, _ := filepath.Abs(filepath.Join(w.Opt.Dir.Page, normalPageName))
		if _, err := os.Stat(normalPath); err == nil {
			return normalPath
		}
	}

	return path
}

// pathForCategory returns the absolute path for a category. If necessary, it
// creates directories for the path components that do not exist.
func (w *Wiki) pathForCategory(catName string, catType CategoryType, createOK bool) string {
	catName = wikifier.CategoryName(catName)
	dir := filepath.Join(w.Opt.Dir.Cache, "category")
	if createOK {
		wikifier.MakeDir(dir, filepath.Join(string(catType), catName))
	}
	path, _ := filepath.Abs(filepath.Join(dir, string(catType), catName))
	return path
}

// pathForImage returns the absolute path for an image.
func (w *Wiki) pathForImage(imageName string) string {
	path, _ := filepath.Abs(filepath.Join(w.Opt.Dir.Image, imageName))
	return path
}

// pathForModel returns the absolute path for a model.
func (w *Wiki) pathForModel(modelName string) string {
	modelName = wikifier.PageNameExt(modelName, ".model")
	path, _ := filepath.Abs(filepath.Join(w.Opt.Dir.Model, modelName))
	return path
}

// Dir returns the absolute path to the resolved wiki directory.
// If the wiki directory is a symlink, it is followed.
//
// Optional path components can be passed as arguments to be joined
// with the wiki root by the path separator.
func (w *Wiki) Dir(dirs ...string) string {
	wikiAbs, _ := filepath.Abs(w.Opt.Dir.Wiki)
	return filepath.Join(append([]string{wikiAbs}, dirs...)...)
}

// UnresolvedAbsFilePath takes a relative path to a file within the wiki
// (e.g. `pages/mypage.page`) and joins it with the absolute path to the wiki
// directory. The result is an absolute path which may or may not exist.
//
// Symlinks are not followed. If that is desired, use absoluteFilePath instead.
//
func (w *Wiki) UnresolvedAbsFilePath(relPath string) string {

	// sanitize
	relPath = filepath.FromSlash(relPath)

	// join with wiki dir
	path := w.Dir(relPath)

	// resolve symlink
	abs, _ := filepath.Abs(path)
	return abs
}

// AbsFilePath takes a relative path to a file within the wiki
// (e.g. `pages/mypage.page`), joins it with the wiki directory, and evaluates it
// with `filepath.Abs()`. The result is an absolute path which may or may not exist.
//
// If the file is a symlink, it is followed. Thus, it is possible for the resulting
// path to exist outside the wiki directory. If that is not desired, use
// unresolvedAbsFilePath instead.
func (w *Wiki) AbsFilePath(relPath string) string {
	path, _ := filepath.Abs(w.Dir(w.UnresolvedAbsFilePath(relPath)))
	return path
}
<commit_msg>publicize RelPath, disallow it to return files outside wiki dir<commit_after>package wiki

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

	"github.com/cooper/quiki/wikifier"
)

// DisplayFile represents a plain text file to display.
type DisplayFile struct {

	// file name relative to wiki root.
	// path delimiter '/' is always used, regardless of OS.
	File string `json:"file,omitempty"`

	// absolute file path of the file.
	// OS-specific path delimiter is used.
	Path string `json:"path,omitempty"`

	// the plain text file content
	Content string

	// time when the file was last modified
	Modified *time.Time `json:"modified,omitempty"`
}

// DisplayFile returns the display result for a plain text file.
func (w *Wiki) DisplayFile(path string) interface{} {
	var r DisplayFile
	path = filepath.FromSlash(path) // just in case

	// ensure it can be made relative to dir.wiki
	relPath := w.RelPath(path)
	if relPath == "" {
		return DisplayError{
			Error:         "Bad filepath",
			DetailedError: "File '" + path + "' cannot be made relative to '" + w.Opt.Dir.Wiki + "'",
		}
	}

	// file does not exist or can't be read
	fi, err := os.Lstat(path)
	if err != nil {
		return DisplayError{
			Error:         "File does not exist.",
			DetailedError: "File '" + path + "' error: " + err.Error(),
		}
	}

	// read file
	content, err := ioutil.ReadFile(path)
	if err != nil {
		return DisplayError{
			Error:         "Error reading file.",
			DetailedError: "File '" + path + "' error: " + err.Error(),
		}
	}

	// results
	mod := fi.ModTime()
	r.File = filepath.ToSlash(relPath)
	r.Path = path
	r.Modified = &mod
	r.Content = string(content)

	return r
}

func (w *Wiki) checkDirectories() {
	// TODO
	panic("unimplemented")
}

// RelPath takes an absolute file path and attempts to make it relative
// to the wiki directory, regardless of whether the path exists.
//
// If the path can be made relative without following symlinks, this is
// preferred. If that fails, symlinks in absPath are followed and a
// second attempt is made.
//
// In any case the path cannot be made relative to the wiki directory,
// an empty string is returned.
func (w *Wiki) RelPath(absPath string) string {
	rel := w._relPath(absPath)
	if strings.Contains(rel, ".."+string(os.PathSeparator)) {
		return ""
	}
	if strings.Contains(rel, string(os.PathSeparator)+"..") {
		return ""
	}
	return rel
}

func (w *Wiki) _relPath(absPath string) string {
	wikiAbs := w.Dir()

	// can't resolve wiki path
	if wikiAbs == "" {
		return ""
	}

	// made it relative as-is
	if rel, err := filepath.Rel(wikiAbs, absPath); err == nil {
		return rel
	}

	// try to make it relative by resolving absPath as absolute
	absPath, _ = filepath.Abs(absPath)
	if absPath != "" {
		if rel, err := filepath.Rel(wikiAbs, absPath); err == nil {
			return rel
		}
	}

	return ""
}

func (w *Wiki) allPageFiles() []string {
	files, _ := wikifier.UniqueFilesInDir(w.Opt.Dir.Page, []string{"page", "md"}, false)
	return files
}

func (w *Wiki) allCategoryFiles(catType CategoryType) []string {
	dir := w.Opt.Dir.Category
	if catType != "" {
		dir = filepath.Join(dir, string(catType))
	}
	files, _ := wikifier.UniqueFilesInDir(dir, []string{"cat"}, false)
	return files
}

func (w *Wiki) allModelFiles() []string {
	files, _ := wikifier.UniqueFilesInDir(w.Opt.Dir.Model, []string{"model"}, false)
	return files
}

func (w *Wiki) allImageFiles() []string {
	files, _ := wikifier.UniqueFilesInDir(w.Opt.Dir.Image, []string{"png", "jpg", "jpeg"}, false)
	return files
}

// pathForPage returns the absolute path for a page.
func (w *Wiki) pathForPage(pageName string) string {

	// try lowercased version first (quiki style)
	lcPageName := wikifier.PageName(pageName)
	path, _ := filepath.Abs(filepath.Join(w.Opt.Dir.Page, lcPageName))

	// it doesn't exist; try non-lowercased version (markdown/etc)
	if _, err := os.Stat(path); err != nil {
		normalPageName := wikifier.PageName(pageName)
		normalPath, _ := filepath.Abs(filepath.Join(w.Opt.Dir.Page, normalPageName))
		if _, err := os.Stat(normalPath); err == nil {
			return normalPath
		}
	}

	return path
}

// pathForCategory returns the absolute path for a category. If necessary, it
// creates directories for the path components that do not exist.
func (w *Wiki) pathForCategory(catName string, catType CategoryType, createOK bool) string {
	catName = wikifier.CategoryName(catName)
	dir := filepath.Join(w.Opt.Dir.Cache, "category")
	if createOK {
		wikifier.MakeDir(dir, filepath.Join(string(catType), catName))
	}
	path, _ := filepath.Abs(filepath.Join(dir, string(catType), catName))
	return path
}

// pathForImage returns the absolute path for an image.
func (w *Wiki) pathForImage(imageName string) string {
	path, _ := filepath.Abs(filepath.Join(w.Opt.Dir.Image, imageName))
	return path
}

// pathForModel returns the absolute path for a model.
func (w *Wiki) pathForModel(modelName string) string {
	modelName = wikifier.PageNameExt(modelName, ".model")
	path, _ := filepath.Abs(filepath.Join(w.Opt.Dir.Model, modelName))
	return path
}

// Dir returns the absolute path to the resolved wiki directory.
// If the wiki directory is a symlink, it is followed.
//
// Optional path components can be passed as arguments to be joined
// with the wiki root by the path separator.
func (w *Wiki) Dir(dirs ...string) string {
	wikiAbs, _ := filepath.Abs(w.Opt.Dir.Wiki)
	return filepath.Join(append([]string{wikiAbs}, dirs...)...)
}

// UnresolvedAbsFilePath takes a relative path to a file within the wiki
// (e.g. `pages/mypage.page`) and joins it with the absolute path to the wiki
// directory. The result is an absolute path which may or may not exist.
//
// Symlinks are not followed. If that is desired, use absoluteFilePath instead.
//
func (w *Wiki) UnresolvedAbsFilePath(relPath string) string {

	// sanitize
	relPath = filepath.FromSlash(relPath)

	// join with wiki dir
	path := w.Dir(relPath)

	// resolve symlink
	abs, _ := filepath.Abs(path)
	return abs
}

// AbsFilePath takes a relative path to a file within the wiki
// (e.g. `pages/mypage.page`), joins it with the wiki directory, and evaluates it
// with `filepath.Abs()`. The result is an absolute path which may or may not exist.
//
// If the file is a symlink, it is followed. Thus, it is possible for the resulting
// path to exist outside the wiki directory. If that is not desired, use
// unresolvedAbsFilePath instead.
func (w *Wiki) AbsFilePath(relPath string) string {
	path, _ := filepath.Abs(w.Dir(w.UnresolvedAbsFilePath(relPath)))
	return path
}
<|endoftext|>


<commit_before>package wiki

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

	"github.com/cooper/quiki/wikifier"
)

// DisplayFile represents a plain text file to display.
type DisplayFile struct {

	// file name relative to wiki root.
	// path delimiter '/' is always used, regardless of OS.
	File string `json:"file,omitempty"`

	// absolute file path of the file.
	// OS-specific path delimiter is used.
	Path string `json:"path,omitempty"`

	// the plain text file content
	Content string

	// time when the file was last modified
	Modified *time.Time `json:"modified,omitempty"`
}

// DisplayFile returns the display result for a plain text file.
func (w *Wiki) DisplayFile(path string) interface{} {
	var r DisplayFile
	path = filepath.FromSlash(path) // just in case

	// ensure it can be made relative to dir.wiki
	relPath := w.relPath(path)
	if relPath == "" {
		return DisplayError{
			Error:         "Bad filepath",
			DetailedError: "File '" + path + "' cannot be made relative to '" + w.Opt.Dir.Wiki + "'",
		}
	}

	// file does not exist or can't be read
	fi, err := os.Lstat(path)
	if err != nil {
		return DisplayError{
			Error:         "File does not exist.",
			DetailedError: "File '" + path + "' error: " + err.Error(),
		}
	}

	// read file
	content, err := ioutil.ReadFile(path)
	if err != nil {
		return DisplayError{
			Error:         "Error reading file.",
			DetailedError: "File '" + path + "' error: " + err.Error(),
		}
	}

	// results
	mod := fi.ModTime()
	r.File = filepath.ToSlash(relPath)
	r.Path = path
	r.Modified = &mod
	r.Content = string(content)

	return r
}

func (w *Wiki) checkDirectories() {
	// TODO
	panic("unimplemented")
}

// relPath returns a path relative to the wiki root
// FIXME: check for ..???
func (w *Wiki) relPath(absPath string) string {
	wikiAbs, _ := filepath.Abs(w.Opt.Dir.Wiki)

	// can't resolve wiki path
	if wikiAbs == "" {
		return ""
	}

	// made it relative as-is
	if rel, err := filepath.Rel(wikiAbs, absPath); err == nil {
		return rel
	}

	// try to make it relative by resolving absPath as absolute
	absPath, _ = filepath.Abs(absPath)
	if absPath != "" {
		if rel, err := filepath.Rel(wikiAbs, absPath); err == nil {
			return rel
		}
	}

	return ""
}

func (w *Wiki) allPageFiles() []string {
	files, _ := wikifier.UniqueFilesInDir(w.Opt.Dir.Page, []string{"page", "md"}, false)
	return files
}

func (w *Wiki) allCategoryFiles(catType CategoryType) []string {
	dir := w.Opt.Dir.Category
	if catType != "" {
		dir = filepath.Join(dir, string(catType))
	}
	files, _ := wikifier.UniqueFilesInDir(dir, []string{"cat"}, false)
	return files
}

func (w *Wiki) allModelFiles() []string {
	files, _ := wikifier.UniqueFilesInDir(w.Opt.Dir.Model, []string{"model"}, false)
	return files
}

func (w *Wiki) allImageFiles() []string {
	files, _ := wikifier.UniqueFilesInDir(w.Opt.Dir.Image, []string{"png", "jpg", "jpeg"}, false)
	return files
}

// pathForPage returns the absolute path for a page.
func (w *Wiki) pathForPage(pageName string) string {

	// try lowercased version first (quiki style)
	lcPageName := wikifier.PageName(pageName)
	path, _ := filepath.Abs(filepath.Join(w.Opt.Dir.Page, lcPageName))

	// it doesn't exist; try non-lowercased version (markdown/etc)
	path, _ := filepath.Abs(filepath.Join(w.Opt.Dir.Page, pageName))
	if _, err := os.Stat(path); err != nil {
		normalPageName := wikifier.PageNameLC(pageName, false)
		normalPath, _ := filepath.Abs(filepath.Join(w.Opt.Dir.Page, normalPageName))
		if _, err := os.Stat(normalPath); err == nil {
			return normalPath
		}
	}

	return path
}

// pathForCategory returns the absolute path for a category. If necessary, it
// creates directories for the path components that do not exist.
func (w *Wiki) pathForCategory(catName string, catType CategoryType, createOK bool) string {
	catName = wikifier.CategoryName(catName, false)
	dir := filepath.Join(w.Opt.Dir.Cache, "category")
	if createOK {
		wikifier.MakeDir(dir, filepath.Join(string(catType), catName))
	}
	path, _ := filepath.Abs(filepath.Join(dir, string(catType), catName))
	return path
}

// pathForImage returns the absolute path for an image.
func (w *Wiki) pathForImage(imageName string) string {
	path, _ := filepath.Abs(filepath.Join(w.Opt.Dir.Image, imageName))
	return path
}

// pathForModel returns the absolute path for a model.
func (w *Wiki) pathForModel(modelName string) string {
	modelName = wikifier.PageNameExt(modelName, ".model")
	path, _ := filepath.Abs(filepath.Join(w.Opt.Dir.Model, modelName))
	return path
}
<commit_msg>use same path<commit_after>package wiki

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

	"github.com/cooper/quiki/wikifier"
)

// DisplayFile represents a plain text file to display.
type DisplayFile struct {

	// file name relative to wiki root.
	// path delimiter '/' is always used, regardless of OS.
	File string `json:"file,omitempty"`

	// absolute file path of the file.
	// OS-specific path delimiter is used.
	Path string `json:"path,omitempty"`

	// the plain text file content
	Content string

	// time when the file was last modified
	Modified *time.Time `json:"modified,omitempty"`
}

// DisplayFile returns the display result for a plain text file.
func (w *Wiki) DisplayFile(path string) interface{} {
	var r DisplayFile
	path = filepath.FromSlash(path) // just in case

	// ensure it can be made relative to dir.wiki
	relPath := w.relPath(path)
	if relPath == "" {
		return DisplayError{
			Error:         "Bad filepath",
			DetailedError: "File '" + path + "' cannot be made relative to '" + w.Opt.Dir.Wiki + "'",
		}
	}

	// file does not exist or can't be read
	fi, err := os.Lstat(path)
	if err != nil {
		return DisplayError{
			Error:         "File does not exist.",
			DetailedError: "File '" + path + "' error: " + err.Error(),
		}
	}

	// read file
	content, err := ioutil.ReadFile(path)
	if err != nil {
		return DisplayError{
			Error:         "Error reading file.",
			DetailedError: "File '" + path + "' error: " + err.Error(),
		}
	}

	// results
	mod := fi.ModTime()
	r.File = filepath.ToSlash(relPath)
	r.Path = path
	r.Modified = &mod
	r.Content = string(content)

	return r
}

func (w *Wiki) checkDirectories() {
	// TODO
	panic("unimplemented")
}

// relPath returns a path relative to the wiki root
// FIXME: check for ..???
func (w *Wiki) relPath(absPath string) string {
	wikiAbs, _ := filepath.Abs(w.Opt.Dir.Wiki)

	// can't resolve wiki path
	if wikiAbs == "" {
		return ""
	}

	// made it relative as-is
	if rel, err := filepath.Rel(wikiAbs, absPath); err == nil {
		return rel
	}

	// try to make it relative by resolving absPath as absolute
	absPath, _ = filepath.Abs(absPath)
	if absPath != "" {
		if rel, err := filepath.Rel(wikiAbs, absPath); err == nil {
			return rel
		}
	}

	return ""
}

func (w *Wiki) allPageFiles() []string {
	files, _ := wikifier.UniqueFilesInDir(w.Opt.Dir.Page, []string{"page", "md"}, false)
	return files
}

func (w *Wiki) allCategoryFiles(catType CategoryType) []string {
	dir := w.Opt.Dir.Category
	if catType != "" {
		dir = filepath.Join(dir, string(catType))
	}
	files, _ := wikifier.UniqueFilesInDir(dir, []string{"cat"}, false)
	return files
}

func (w *Wiki) allModelFiles() []string {
	files, _ := wikifier.UniqueFilesInDir(w.Opt.Dir.Model, []string{"model"}, false)
	return files
}

func (w *Wiki) allImageFiles() []string {
	files, _ := wikifier.UniqueFilesInDir(w.Opt.Dir.Image, []string{"png", "jpg", "jpeg"}, false)
	return files
}

// pathForPage returns the absolute path for a page.
func (w *Wiki) pathForPage(pageName string) string {

	// try lowercased version first (quiki style)
	lcPageName := wikifier.PageName(pageName)
	path, _ := filepath.Abs(filepath.Join(w.Opt.Dir.Page, lcPageName))

	// it doesn't exist; try non-lowercased version (markdown/etc)
	if _, err := os.Stat(path); err != nil {
		normalPageName := wikifier.PageNameLC(pageName, false)
		normalPath, _ := filepath.Abs(filepath.Join(w.Opt.Dir.Page, normalPageName))
		if _, err := os.Stat(normalPath); err == nil {
			return normalPath
		}
	}

	return path
}

// pathForCategory returns the absolute path for a category. If necessary, it
// creates directories for the path components that do not exist.
func (w *Wiki) pathForCategory(catName string, catType CategoryType, createOK bool) string {
	catName = wikifier.CategoryName(catName, false)
	dir := filepath.Join(w.Opt.Dir.Cache, "category")
	if createOK {
		wikifier.MakeDir(dir, filepath.Join(string(catType), catName))
	}
	path, _ := filepath.Abs(filepath.Join(dir, string(catType), catName))
	return path
}

// pathForImage returns the absolute path for an image.
func (w *Wiki) pathForImage(imageName string) string {
	path, _ := filepath.Abs(filepath.Join(w.Opt.Dir.Image, imageName))
	return path
}

// pathForModel returns the absolute path for a model.
func (w *Wiki) pathForModel(modelName string) string {
	modelName = wikifier.PageNameExt(modelName, ".model")
	path, _ := filepath.Abs(filepath.Join(w.Opt.Dir.Model, modelName))
	return path
}
<|endoftext|>


<commit_before>package db

import (
	"encoding/json"
	"log"

	"github.com/bosssauce/ponzu/content"
	"github.com/bosssauce/ponzu/system/admin/config"

	"github.com/boltdb/bolt"
	"github.com/nilslice/jwt"
)

var store *bolt.DB

// Close exports the abillity to close our db file. Should be called with defer
// after call to Init() from the same place.
func Close() {
	err := store.Close()
	if err != nil {
		log.Println(err)
	}
}

// Init creates a db connection, initializes db with required info, sets secrets
func Init() {
	store, err := bolt.Open("system.db", 0666, nil)
	if err != nil {
		log.Fatalln(err)
	}

	err = store.Update(func(tx *bolt.Tx) error {
		// initialize db with all content type buckets & sorted bucket for type
		for t := range content.Types {
			_, err := tx.CreateBucketIfNotExists([]byte(t))
			if err != nil {
				return err
			}

			_, err = tx.CreateBucketIfNotExists([]byte(t + "_sorted"))
			if err != nil {
				return err
			}
		}

		// init db with other buckets as needed
		buckets := []string{"_config", "_users"}
		for _, name := range buckets {
			_, err := tx.CreateBucketIfNotExists([]byte(name))
			if err != nil {
				return err
			}
		}

		// seed db with configs structure if not present
		b := tx.Bucket([]byte("_config"))
		if b.Get([]byte("settings")) == nil {
			j, err := json.Marshal(&config.Config{})
			if err != nil {
				return err
			}

			err = b.Put([]byte("settings"), j)
			if err != nil {
				return err
			}
		}

		clientSecret := ConfigCache("client_secret")

		if clientSecret != "" {
			jwt.Secret([]byte(clientSecret))
		}

		return nil
	})
	if err != nil {
		log.Fatalln("Coudn't initialize db with buckets.", err)
	}

	// sort all content into type_sorted buckets
	go func() {
		for t := range content.Types {
			SortContent(t)
		}
	}()

}

// SystemInitComplete checks if there is at least 1 admin user in the db which
// would indicate that the system has been configured to the minimum required.
func SystemInitComplete() bool {
	complete := false

	err := store.View(func(tx *bolt.Tx) error {
		users := tx.Bucket([]byte("_users"))

		err := users.ForEach(func(k, v []byte) error {
			complete = true
			return nil
		})
		if err != nil {
			return err
		}

		return nil
	})
	if err != nil {
		complete = false
		log.Fatalln(err)
	}

	return complete
}
<commit_msg>attempt fix for bolt err<commit_after>package db

import (
	"encoding/json"
	"log"

	"github.com/bosssauce/ponzu/content"
	"github.com/bosssauce/ponzu/system/admin/config"

	"github.com/boltdb/bolt"
	"github.com/nilslice/jwt"
)

var store *bolt.DB

// Close exports the abillity to close our db file. Should be called with defer
// after call to Init() from the same place.
func Close() {
	err := store.Close()
	if err != nil {
		log.Println(err)
	}
}

// Init creates a db connection, initializes db with required info, sets secrets
func Init() {
	store, err := bolt.Open("system.db", 0666, nil)
	if err != nil {
		log.Fatalln(err)
	}

	err = store.Update(func(tx *bolt.Tx) error {
		// initialize db with all content type buckets & sorted bucket for type
		for t := range content.Types {
			_, err := tx.CreateBucketIfNotExists([]byte(t))
			if err != nil {
				return err
			}

			_, err = tx.CreateBucketIfNotExists([]byte(t + "_sorted"))
			if err != nil {
				return err
			}
		}

		// init db with other buckets as needed
		buckets := []string{"_config", "_users"}
		for _, name := range buckets {
			_, err := tx.CreateBucketIfNotExists([]byte(name))
			if err != nil {
				return err
			}
		}

		// seed db with configs structure if not present
		b := tx.Bucket([]byte("_config"))
		if b.Get([]byte("settings")) == nil {
			j, err := json.Marshal(&config.Config{})
			if err != nil {
				return err
			}

			err = b.Put([]byte("settings"), j)
			if err != nil {
				return err
			}
		}

		clientSecret := ConfigCache("client_secret")

		if clientSecret != "" {
			jwt.Secret([]byte(clientSecret))
		}

		return nil
	})
	if err != nil {
		log.Fatalln("Coudn't initialize db with buckets.", err)
	}

	// sort all content into type_sorted buckets
	if SystemInitComplete() {
		go func() {
			for t := range content.Types {
				SortContent(t)
			}
		}()
	}

}

// SystemInitComplete checks if there is at least 1 admin user in the db which
// would indicate that the system has been configured to the minimum required.
func SystemInitComplete() bool {
	complete := false

	err := store.View(func(tx *bolt.Tx) error {
		users := tx.Bucket([]byte("_users"))

		err := users.ForEach(func(k, v []byte) error {
			complete = true
			return nil
		})
		if err != nil {
			return err
		}

		return nil
	})
	if err != nil {
		complete = false
		log.Fatalln(err)
	}

	return complete
}
<|endoftext|>


<commit_before>// implementation of ajvondrak's xand core
package xand

import (
	"fmt"
	"github.com/DrItanium/cores/registration/machine"
	"github.com/DrItanium/cores/registration/parser"
	"strconv"
	"strings"
	"unicode"
	"unicode/utf8"
)

type Word int8

const MemorySize = 128

func RegistrationName() string {
	return "xand"
}

func Register() {}

type MachineRegistrar func(...interface{}) (machine.Machine, error)

func (this MachineRegistrar) New(args ...interface{}) (machine.Machine, error) {
	return this(args)
}

func generateCore(a ...interface{}) (machine.Machine, error) {
	return New()
}

func init() {
	machine.Register(RegistrationName(), MachineRegistrar(generateCore))
}

type Core struct {
	pc     Word
	ir     [3]Word
	memory [MemorySize]Word
}

func (this *Core) fetch() bool {
	if (this.pc < 0) || (int(this.pc+2) >= len(this.memory)) {
		return false
	} else {
		this.ir[0] = this.memory[this.pc]
		this.ir[1] = this.memory[this.pc+1]
		this.ir[2] = this.memory[this.pc+2]
		return this.ir[0] >= 0 && this.ir[1] >= 0 && this.ir[2] >= 0
	}
}

func (this *Core) Run() error {
	for this.fetch() {
		// the xand operation it self
		this.memory[this.ir[0]] = this.memory[this.ir[0]] - this.memory[this.ir[1]]
		if this.memory[this.ir[0]] <= 0 {
			this.pc = this.ir[2]
		} else {
			this.pc += 3
		}
	}
	return nil
}

func (this *Core) Startup() error {
	return nil
}

func (this *Core) Shutdown() error {
	return nil
}

func (this *Core) GetDebugStatus() bool {
	return false
}

func (this *Core) SetDebug(_ bool) {

}

func (this *Core) InstallProgram(input <-chan byte) error {
	// read 128 bytes
	for i := 0; i < MemorySize; i++ {
		if value, more := <-input; !more {
			return fmt.Errorf("Not a complete xand memory image")
		} else {
			this.memory[i] = Word(value)
		}
	}
	return nil
}

func (this *Core) Dump(output chan<- byte) error {
	for _, value := range this.memory {
		output <- byte(value)
	}
	return nil
}

func New() (*Core, error) {
	return &Core{}, nil
}

type ParsingRegistrar func(...interface{}) (parser.Parser, error)

func (this ParsingRegistrar) New(args ...interface{}) (parser.Parser, error) {
	return this(args)
}

func generateParser(a ...interface{}) (parser.Parser, error) {
	var p _parser
	if core, err := New(); err != nil {
		return nil, err
	} else {
		p.core = core
		p.labels = make(map[string]Word)
		return &p, nil
	}
}

func init() {
	parser.Register(RegistrationName(), ParsingRegistrar(generateParser))
}

type deferredAddress struct {
	addr  Word
	title string
}

type _parser struct {
	core       *Core
	labels     map[string]Word
	statements []*statement
	deferred   []deferredAddress
}

func (this *_parser) Dump(pipe chan<- byte) error {
	return this.core.Dump(pipe)
}

func (this *_parser) Parse(lines <-chan parser.Entry) error {
	for line := range lines {
		stmt := carveLine(line.Line)
		stmt.index = line.Index
		this.statements = append(this.statements, stmt)
		for _, str := range stmt.contents {
			if err := str.Parse(); err != nil {
				return fmt.Errorf("Error: line: %d : %s\n", line.Index, err)
			}
		}
	}
	return nil
}

type nodeType int

func (this nodeType) String() string {
	switch this {
	case typeId:
		return "id"
	case typeImmediate:
		return "immediate"
	case typeLabel:
		return "label"
	case typeComment:
		return "comment"
	case keywordXand:
		return "xand"
	case keywordDotDotDot:
		return "..."
	default:
		return fmt.Sprintf("%d", this)
	}
}
func (this nodeType) immediate() bool {
	return this == typeImmediate
}
func (this nodeType) comment() bool {
	return this == typeComment
}

const (
	typeId nodeType = iota
	typeImmediate
	typeLabel
	typeComment
	keywordXand
	keywordDotDotDot
)

type node struct {
	Value interface{}
	Type  nodeType
}

func parseDecimalImmediate(str string) (Word, error) {
	val, err := strconv.ParseInt(str, 10, 8)
	return Word(val), err
}

func (this *node) parseLabel(val string) error {
	nVal := strings.TrimSuffix(val, ":")
	q, _ := utf8.DecodeRuneInString(nVal)
	if !unicode.IsLetter(q) {
		return fmt.Errorf("Label %s starts with a non letter %s!", nVal, q)
	} else {
		this.Type = typeLabel
		this.Value = nVal
		// now parse the label as a entirely new node and see if we get a register back
		if nVal == "xand" {
			return fmt.Errorf("Can't name a label xand")
		} else {
			return nil
		}
	}
}

func (this *node) parseImmediate(val string) error {
	this.Type = typeImmediate
	if v, err := parseDecimalImmediate(val[1:]); err != nil {
		return err
	} else {
		this.Value = v
		return nil
	}
}

var keywords = map[string]nodeType{
	"xand": keywordXand,
	"...":  keywordDotDotDot,
}

func (this *node) parseGeneric(val string) error {
	if v, ok := keywords[val]; ok {
		this.Type = v
		return nil
	} else {
		return fmt.Errorf("Unknown statement %s", val)
	}
}

func (this *node) Parse() error {
	if this.Type == typeId {
		val := this.Value.(string)
		if this.parseGeneric(val) == nil {

		} else if strings.HasSuffix(val, ":") {
			return this.parseLabel(val)
		} else if strings.HasPrefix(val, ";") {
			this.Type = typeComment
			this.Value = strings.TrimPrefix(val, ";")
		} else if strings.HasPrefix(val, "#") {
			return this.parseImmediate(val)
		}
	}
	return nil
}

func (this *node) isComment() bool {
	return this.Type == typeComment
}

func (this *node) isLabel() bool {
	return this.Type == typeLabel
}

type statement struct {
	contents []*node
	index    int
}

func (this *statement) Add(value string, t nodeType) {
	// always trim before adding
	str := strings.TrimSpace(value)
	if len(str) > 0 {
		this.contents = append(this.contents, &node{Value: str, Type: t})
	}
}
func (this *statement) AddUnknown(value string) {
	this.Add(value, typeId)
}
func (this *statement) String() string {
	str := fmt.Sprintf("%d: ", this.index)
	for _, n := range this.contents {
		str += fmt.Sprintf(" %T: %s ", n, *n)
	}
	return str
}
func (this *statement) First() (*node, error) {
	if len(this.contents) == 0 {
		return nil, fmt.Errorf("Empty statement!")
	} else {
		return this.contents[0], nil
	}
}
func (this *statement) Rest() []*node {
	return this.contents[1:]
}

func carveLine(line string) *statement {
	// trim the damn line first
	data := strings.TrimSpace(line)
	var s statement
	if len(data) == 0 {
		return &s
	}
	oldStart := 0
	start := 0
	// skip the strings at the beginning
	for width := 0; start < len(data); start += width {
		var r rune
		next := data[start:]
		r, width = utf8.DecodeRuneInString(next)
		if unicode.IsSpace(r) {
			s.AddUnknown(data[oldStart:start])
			oldStart = start
		} else if r == ';' {
			// consume the rest of the data
			s.AddUnknown(data[oldStart:start])
			// then capture the comment
			s.Add(data[start:], typeComment)
			oldStart = start
			break
		}
	}
	if oldStart < start {
		s.AddUnknown(data[oldStart:])
	}
	return &s
}

func (this *_parser) Process() error {
	for _, stmt := range this.statements {
		if err := this.parseStatement(stmt); err != nil {
			return fmt.Errorf("Error: line %d: msg: %s", stmt.index, err)
		}
	}
	for _, d := range this.deferred {
		if entry, ok := this.labels[d.title]; !ok {
			return fmt.Errorf("Label %s not defined!", d.title)
		} else {
			this.core.memory[d.addr] = entry
		}
	}
	return nil
}

func (this *_parser) newLabel(n *node) error {
	name := n.Value.(string)
	if _, ok := this.labels[name]; ok {
		return fmt.Errorf("Label %s is already defined!", name)
	} else {
		this.labels[name] = this.core.pc
		return nil
	}
}

func (this *_parser) parseStatement(stmt *statement) error {
	first, err := stmt.First()
	if err != nil {
		return err
	}
	rest := stmt.Rest()
	switch first.Type {
	case typeComment:
		if len(rest) > 0 {
			panic("Programmer Failure! Found something following a comment node in a statement. This is impossible!!!!")
		} else {
			return nil
		}
	case typeLabel:
		if err := this.newLabel(first); err != nil {
			return err
		} else if len(rest) > 0 {
			if this.core.pc < 0 {
				return fmt.Errorf("Too many instructions defined!")
			}
			// if there are more entries on the line then check them out
			var s statement
			s.index = stmt.index
			s.contents = rest
			return this.parseStatement(&s)
		}
	case keywordXand:
		if len(rest) == 3 {
			if this.core.pc < 0 {
				return fmt.Errorf("Too many instructions defined!")
			}
			var s statement
			s.index = stmt.index
			s.contents = rest
			return this.parseStatement(&s)
		} else {
			return fmt.Errorf("xand requires three arguments")
		}
	case keywordDotDotDot:
		this.core.memory[this.core.pc] = this.core.pc + 1
		this.core.pc++
		// hmmm should we allow this to continue on?...nope
		if len(rest) > 0 {
			return fmt.Errorf("... has to terminate a statement")
		}
	case typeImmediate:
		// just install the value to the current address
		this.core.memory[this.core.pc] = first.Value.(Word)
		this.core.pc++
		if len(rest) > 0 {
			if this.core.pc < 0 {
				return fmt.Errorf("Too many instructions defined!")
			}
			var s statement
			s.index = stmt.index
			s.contents = rest
			return this.parseStatement(&s)
		}
	case typeId:
		// defer statement for the time being
		if addr, ok := this.labels[first.Value.(string)]; !ok {
			this.deferred = append(this.deferred, deferredAddress{addr: this.core.pc, title: first.Value.(string)})
		} else {
			this.core.memory[this.core.pc] = addr
		}
		this.core.pc++
		if len(rest) > 0 {
			if this.core.pc < 0 {
				return fmt.Errorf("Too many instructions defined!")
			}
			var s statement
			s.index = stmt.index
			s.contents = rest
			return this.parseStatement(&s)
		}
	default:
		return fmt.Errorf("Unhandled nodeType %d: %s", first.Type, first.Value)
	}
	return nil
}
<commit_msg>Cleaned up xand slightly<commit_after>// implementation of ajvondrak's xand core
package xand

import (
	"fmt"
	"github.com/DrItanium/cores/registration/machine"
	"github.com/DrItanium/cores/registration/parser"
	"strconv"
	"strings"
	"unicode"
	"unicode/utf8"
)

type Word int8

const MemorySize = 128

func RegistrationName() string {
	return "xand"
}

func generateCore(a ...interface{}) (machine.Machine, error) {
	return New()
}

func init() {
	machine.Register(RegistrationName(), machine.Registrar(generateCore))
}

type Core struct {
	pc     Word
	ir     [3]Word
	memory [MemorySize]Word
}

func (this *Core) fetch() bool {
	if (this.pc < 0) || (int(this.pc+2) >= len(this.memory)) {
		return false
	} else {
		this.ir[0] = this.memory[this.pc]
		this.ir[1] = this.memory[this.pc+1]
		this.ir[2] = this.memory[this.pc+2]
		return this.ir[0] >= 0 && this.ir[1] >= 0 && this.ir[2] >= 0
	}
}

func (this *Core) Run() error {
	for this.fetch() {
		// the xand operation it self
		this.memory[this.ir[0]] = this.memory[this.ir[0]] - this.memory[this.ir[1]]
		if this.memory[this.ir[0]] <= 0 {
			this.pc = this.ir[2]
		} else {
			this.pc += 3
		}
	}
	return nil
}

func (this *Core) Startup() error {
	return nil
}

func (this *Core) Shutdown() error {
	return nil
}

func (this *Core) GetDebugStatus() bool {
	return false
}

func (this *Core) SetDebug(_ bool) {

}

func (this *Core) InstallProgram(input <-chan byte) error {
	// read 128 bytes
	for i := 0; i < MemorySize; i++ {
		if value, more := <-input; !more {
			return fmt.Errorf("Not a complete xand memory image")
		} else {
			this.memory[i] = Word(value)
		}
	}
	return nil
}

func (this *Core) Dump(output chan<- byte) error {
	for _, value := range this.memory {
		output <- byte(value)
	}
	return nil
}

func New() (*Core, error) {
	return &Core{}, nil
}

func generateParser(a ...interface{}) (parser.Parser, error) {
	var p _parser
	if core, err := New(); err != nil {
		return nil, err
	} else {
		p.core = core
		p.labels = make(map[string]Word)
		return &p, nil
	}
}

func init() {
	parser.Register(RegistrationName(), parser.Registrar(generateParser))
}

type deferredAddress struct {
	addr  Word
	title string
}

type _parser struct {
	core       *Core
	labels     map[string]Word
	statements []*statement
	deferred   []deferredAddress
}

func (this *_parser) Dump(pipe chan<- byte) error {
	return this.core.Dump(pipe)
}

func (this *_parser) Parse(lines <-chan parser.Entry) error {
	for line := range lines {
		stmt := carveLine(line.Line)
		stmt.index = line.Index
		this.statements = append(this.statements, stmt)
		for _, str := range stmt.contents {
			if err := str.Parse(); err != nil {
				return fmt.Errorf("Error: line: %d : %s\n", line.Index, err)
			}
		}
	}
	return nil
}

type nodeType int

func (this nodeType) String() string {
	switch this {
	case typeId:
		return "id"
	case typeImmediate:
		return "immediate"
	case typeLabel:
		return "label"
	case typeComment:
		return "comment"
	case keywordXand:
		return "xand"
	case keywordDotDotDot:
		return "..."
	default:
		return fmt.Sprintf("%d", this)
	}
}
func (this nodeType) immediate() bool {
	return this == typeImmediate
}
func (this nodeType) comment() bool {
	return this == typeComment
}

const (
	typeId nodeType = iota
	typeImmediate
	typeLabel
	typeComment
	keywordXand
	keywordDotDotDot
)

type node struct {
	Value interface{}
	Type  nodeType
}

func parseDecimalImmediate(str string) (Word, error) {
	val, err := strconv.ParseInt(str, 10, 8)
	return Word(val), err
}

func (this *node) parseLabel(val string) error {
	nVal := strings.TrimSuffix(val, ":")
	q, _ := utf8.DecodeRuneInString(nVal)
	if !unicode.IsLetter(q) {
		return fmt.Errorf("Label %s starts with a non letter %s!", nVal, q)
	} else {
		this.Type = typeLabel
		this.Value = nVal
		// now parse the label as a entirely new node and see if we get a register back
		if nVal == "xand" {
			return fmt.Errorf("Can't name a label xand")
		} else {
			return nil
		}
	}
}

func (this *node) parseImmediate(val string) error {
	this.Type = typeImmediate
	if v, err := parseDecimalImmediate(val[1:]); err != nil {
		return err
	} else {
		this.Value = v
		return nil
	}
}

var keywords = map[string]nodeType{
	"xand": keywordXand,
	"...":  keywordDotDotDot,
}

func (this *node) parseGeneric(val string) error {
	if v, ok := keywords[val]; ok {
		this.Type = v
		return nil
	} else {
		return fmt.Errorf("Unknown statement %s", val)
	}
}

func (this *node) Parse() error {
	if this.Type == typeId {
		val := this.Value.(string)
		if this.parseGeneric(val) == nil {

		} else if strings.HasSuffix(val, ":") {
			return this.parseLabel(val)
		} else if strings.HasPrefix(val, ";") {
			this.Type = typeComment
			this.Value = strings.TrimPrefix(val, ";")
		} else if strings.HasPrefix(val, "#") {
			return this.parseImmediate(val)
		}
	}
	return nil
}

func (this *node) isComment() bool {
	return this.Type == typeComment
}

func (this *node) isLabel() bool {
	return this.Type == typeLabel
}

type statement struct {
	contents []*node
	index    int
}

func (this *statement) Add(value string, t nodeType) {
	// always trim before adding
	str := strings.TrimSpace(value)
	if len(str) > 0 {
		this.contents = append(this.contents, &node{Value: str, Type: t})
	}
}
func (this *statement) AddUnknown(value string) {
	this.Add(value, typeId)
}
func (this *statement) String() string {
	str := fmt.Sprintf("%d: ", this.index)
	for _, n := range this.contents {
		str += fmt.Sprintf(" %T: %s ", n, *n)
	}
	return str
}
func (this *statement) First() (*node, error) {
	if len(this.contents) == 0 {
		return nil, fmt.Errorf("Empty statement!")
	} else {
		return this.contents[0], nil
	}
}
func (this *statement) Rest() []*node {
	return this.contents[1:]
}

func carveLine(line string) *statement {
	// trim the damn line first
	data := strings.TrimSpace(line)
	var s statement
	if len(data) == 0 {
		return &s
	}
	oldStart := 0
	start := 0
	// skip the strings at the beginning
	for width := 0; start < len(data); start += width {
		var r rune
		next := data[start:]
		r, width = utf8.DecodeRuneInString(next)
		if unicode.IsSpace(r) {
			s.AddUnknown(data[oldStart:start])
			oldStart = start
		} else if r == ';' {
			// consume the rest of the data
			s.AddUnknown(data[oldStart:start])
			// then capture the comment
			s.Add(data[start:], typeComment)
			oldStart = start
			break
		}
	}
	if oldStart < start {
		s.AddUnknown(data[oldStart:])
	}
	return &s
}

func (this *_parser) Process() error {
	for _, stmt := range this.statements {
		if err := this.parseStatement(stmt); err != nil {
			return fmt.Errorf("Error: line %d: msg: %s", stmt.index, err)
		}
	}
	for _, d := range this.deferred {
		if entry, ok := this.labels[d.title]; !ok {
			return fmt.Errorf("Label %s not defined!", d.title)
		} else {
			this.core.memory[d.addr] = entry
		}
	}
	return nil
}

func (this *_parser) newLabel(n *node) error {
	name := n.Value.(string)
	if _, ok := this.labels[name]; ok {
		return fmt.Errorf("Label %s is already defined!", name)
	} else {
		this.labels[name] = this.core.pc
		return nil
	}
}

func (this *_parser) parseStatement(stmt *statement) error {
	first, err := stmt.First()
	if err != nil {
		return err
	}
	rest := stmt.Rest()
	switch first.Type {
	case typeComment:
		if len(rest) > 0 {
			panic("Programmer Failure! Found something following a comment node in a statement. This is impossible!!!!")
		} else {
			return nil
		}
	case typeLabel:
		if err := this.newLabel(first); err != nil {
			return err
		} else if len(rest) > 0 {
			if this.core.pc < 0 {
				return fmt.Errorf("Too many instructions defined!")
			}
			// if there are more entries on the line then check them out
			var s statement
			s.index = stmt.index
			s.contents = rest
			return this.parseStatement(&s)
		}
	case keywordXand:
		if len(rest) == 3 {
			if this.core.pc < 0 {
				return fmt.Errorf("Too many instructions defined!")
			}
			var s statement
			s.index = stmt.index
			s.contents = rest
			return this.parseStatement(&s)
		} else {
			return fmt.Errorf("xand requires three arguments")
		}
	case keywordDotDotDot:
		this.core.memory[this.core.pc] = this.core.pc + 1
		this.core.pc++
		// hmmm should we allow this to continue on?...nope
		if len(rest) > 0 {
			return fmt.Errorf("... has to terminate a statement")
		}
	case typeImmediate:
		// just install the value to the current address
		this.core.memory[this.core.pc] = first.Value.(Word)
		this.core.pc++
		if len(rest) > 0 {
			if this.core.pc < 0 {
				return fmt.Errorf("Too many instructions defined!")
			}
			var s statement
			s.index = stmt.index
			s.contents = rest
			return this.parseStatement(&s)
		}
	case typeId:
		// defer statement for the time being
		if addr, ok := this.labels[first.Value.(string)]; !ok {
			this.deferred = append(this.deferred, deferredAddress{addr: this.core.pc, title: first.Value.(string)})
		} else {
			this.core.memory[this.core.pc] = addr
		}
		this.core.pc++
		if len(rest) > 0 {
			if this.core.pc < 0 {
				return fmt.Errorf("Too many instructions defined!")
			}
			var s statement
			s.index = stmt.index
			s.contents = rest
			return this.parseStatement(&s)
		}
	default:
		return fmt.Errorf("Unhandled nodeType %d: %s", first.Type, first.Value)
	}
	return nil
}
<|endoftext|>


<commit_before>package perfect

import "testing"

var _ error = ErrOnlyPositive

func TestGivesPositiveRequiredError(t *testing.T) {
	if _, err := Classify(0); err != ErrOnlyPositive {
		t.Errorf("Expected error %q but got %q", ErrOnlyPositive, err)
	}
}

func TestClassifiesCorrectly(t *testing.T) {
	cases := []struct {
		input    uint64
		expected Classification
	}{
		{1, ClassificationDeficient},
		{13, ClassificationDeficient},
		{12, ClassificationAbundant},
		{6, ClassificationPerfect},
		{28, ClassificationPerfect},
		{496, ClassificationPerfect},
		{8128, ClassificationPerfect},
	}
	for _, c := range cases {
		if cat, err := Classify(c.input); err != nil {
			t.Errorf("%d: Expected no error but got %s", c.input, err)
		} else if cat != c.expected {
			t.Errorf("%d: Expected %q, got %q", c.input, c.expected, cat)
		}
	}
}

const targetTestVersion = 1

func TestTestVersion(t *testing.T) {
	if testVersion != targetTestVersion {
		t.Errorf("Found testVersion = %v, want %v.", testVersion, targetTestVersion)
	}
}
<commit_msg>perfect-numbers: ensure test versioning consistency with other exercises (#560)<commit_after>package perfect

import "testing"

var _ error = ErrOnlyPositive

const targetTestVersion = 1

func TestTestVersion(t *testing.T) {
	if testVersion != targetTestVersion {
		t.Fatalf("Found testVersion = %v, want %v.", testVersion, targetTestVersion)
	}
}

func TestGivesPositiveRequiredError(t *testing.T) {
	if _, err := Classify(0); err != ErrOnlyPositive {
		t.Errorf("Expected error %q but got %q", ErrOnlyPositive, err)
	}
}

func TestClassifiesCorrectly(t *testing.T) {
	cases := []struct {
		input    uint64
		expected Classification
	}{
		{1, ClassificationDeficient},
		{13, ClassificationDeficient},
		{12, ClassificationAbundant},
		{6, ClassificationPerfect},
		{28, ClassificationPerfect},
		{496, ClassificationPerfect},
		{8128, ClassificationPerfect},
	}
	for _, c := range cases {
		if cat, err := Classify(c.input); err != nil {
			t.Errorf("%d: Expected no error but got %s", c.input, err)
		} else if cat != c.expected {
			t.Errorf("%d: Expected %q, got %q", c.input, c.expected, cat)
		}
	}
}
<|endoftext|>


<commit_before>package nbt

import (
	"errors"
	"strconv"
)

// ReadError is an error returned when a read error occurs
type ReadError struct {
	Where string
	Err   error
}

func (r ReadError) Error() string {
	return "encountered an error while trying to read a " + r.Where + ": " + r.Err.Error()
}

// WriteError is an error returned when a write error occurs
type WriteError struct {
	Where string
	Err   error
}

func (w WriteError) Error() string {
	return "encountered an error while trying to write a " + w.Where + ": " + w.Err.Error()
}

// UnknownTag is an error that occurs when an unknown tag id is discovered.
// This could also indicate corrupted or non-compliant data.
type UnknownTag struct {
	TagID
}

func (u UnknownTag) Error() string {
	return "discovered unknown TagId with id " + strconv.FormatUint(uint64(u.TagID), 10)
}

// WrongTag is an error returned when a tag of the incorrect type was intended
// to be added to a list.
type WrongTag struct {
	Expecting, Got TagID
}

func (w WrongTag) Error() string {
	return "expecting tag id " + w.Expecting.String() + ", got " + w.Got.String()
}

// BadRange is an error that occurs when trying to set an item on a list which
// is outside of the current limits of the list.
var ErrBadRange = errors.New("given index was out-of-range")
<commit_msg>corrected comment<commit_after>package nbt

import (
	"errors"
	"strconv"
)

// ReadError is an error returned when a read error occurs
type ReadError struct {
	Where string
	Err   error
}

func (r ReadError) Error() string {
	return "encountered an error while trying to read a " + r.Where + ": " + r.Err.Error()
}

// WriteError is an error returned when a write error occurs
type WriteError struct {
	Where string
	Err   error
}

func (w WriteError) Error() string {
	return "encountered an error while trying to write a " + w.Where + ": " + w.Err.Error()
}

// UnknownTag is an error that occurs when an unknown tag id is discovered.
// This could also indicate corrupted or non-compliant data.
type UnknownTag struct {
	TagID
}

func (u UnknownTag) Error() string {
	return "discovered unknown TagId with id " + strconv.FormatUint(uint64(u.TagID), 10)
}

// WrongTag is an error returned when a tag of the incorrect type was intended
// to be added to a list.
type WrongTag struct {
	Expecting, Got TagID
}

func (w WrongTag) Error() string {
	return "expecting tag id " + w.Expecting.String() + ", got " + w.Got.String()
}

// ErrBadRange is an error that occurs when trying to set an item on a list which
// is outside of the current limits of the list.
var ErrBadRange = errors.New("given index was out-of-range")
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Contributor:
// - Julien Vehent jvehent@mozilla.com [:ulfr]
package agentcontext

import (
	"bufio"
	"bytes"
	"fmt"
	"mig.ninja/mig"
	"os/exec"
	"strings"
)

func findHostname(orig_ctx AgentContext) (ctx AgentContext, err error) {
	ctx = orig_ctx
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("findHostname() -> %v", e)
		}
		logChan <- mig.Log{Desc: "leaving findHostname()"}.Debug()
	}()

	// get the hostname
	out, err := exec.Command("hostname").Output()
	if err != nil {
		panic(err)
	}
	// remove trailing newline
	ctx.Hostname = fmt.Sprintf("%s", out[0:len(out)-1])
	return
}

func findOSInfo(orig_ctx AgentContext) (ctx AgentContext, err error) {
	ctx = orig_ctx
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("findOSInfo() -> %v", e)
		}
		logChan <- mig.Log{Desc: "leaving findOSInfo()"}.Debug()
	}()
	hostname, domain, osname, osversion, err := getSysInfo()
	if err != nil {
		panic(err)
	}
	ctx.Hostname = hostname + "." + domain
	ctx.OSIdent = osname + " " + osversion
	ctx.Init = "windows"
	return
}

// getSysInfo call systeminfo and returns the OS version
func getSysInfo() (hostname, domain, osname, osversion string, err error) {
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("getSysInfo() -> %v", e)
		}
	}()
	// get data from the systeminfo
	out, err := exec.Command("cmd","/C", "wmic.exe os get Caption, Version /format:list & wmic.exe computersystem get Name, domain /format:list").Output()
	if err != nil {
		panic(err)
	}
	buf := bytes.NewReader(out)
	reader := bufio.NewReader(buf)
	iter := 0
	for {
		lineBytes, _, err := reader.ReadLine()
		// don't loop more than 200 times
		if err != nil || iter > 200 {
			goto exit
		}
		line := fmt.Sprintf("%s", lineBytes)
		if strings.Contains(line, "Caption=") {
			out := strings.SplitN(line, "=", 2)
			if len(out) == 2 {
				osname = out[1]
			}
			osname = cleanString(osname)
		} else if strings.Contains(line, "Version=") {
			out := strings.SplitN(line, "=", 2)
			if len(out) == 2 {
				osversion = out[1]
			}
			osversion = cleanString(osversion)
		} else if strings.Contains(line, "Domain=") {
			out := strings.SplitN(line, "=", 2)
			if len(out) == 2 {
				domain = out[1]
			}
			domain = cleanString(domain)
		} else if strings.Contains(line, "Name=") {
			out := strings.SplitN(line, "=", 2)
			if len(out) == 2 {
				hostname = out[1]
			}
			hostname = cleanString(hostname)
		}
		iter++
	}
exit:
	return
}

// GetConfDir returns the configuration directory for the platform
func GetConfDir() string {
	return `C:\mig\`
}

// GetRunDir returns the runtime directory for the platform
func GetRunDir() string {
	return GetConfDir()
}
<commit_msg>agent: gofmt env_windows.go<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Contributor:
// - Julien Vehent jvehent@mozilla.com [:ulfr]
package agentcontext

import (
	"bufio"
	"bytes"
	"fmt"
	"mig.ninja/mig"
	"os/exec"
	"strings"
)

func findHostname(orig_ctx AgentContext) (ctx AgentContext, err error) {
	ctx = orig_ctx
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("findHostname() -> %v", e)
		}
		logChan <- mig.Log{Desc: "leaving findHostname()"}.Debug()
	}()

	// get the hostname
	out, err := exec.Command("hostname").Output()
	if err != nil {
		panic(err)
	}
	// remove trailing newline
	ctx.Hostname = fmt.Sprintf("%s", out[0:len(out)-1])
	return
}

func findOSInfo(orig_ctx AgentContext) (ctx AgentContext, err error) {
	ctx = orig_ctx
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("findOSInfo() -> %v", e)
		}
		logChan <- mig.Log{Desc: "leaving findOSInfo()"}.Debug()
	}()
	hostname, domain, osname, osversion, err := getSysInfo()
	if err != nil {
		panic(err)
	}
	ctx.Hostname = hostname + "." + domain
	ctx.OSIdent = osname + " " + osversion
	ctx.Init = "windows"
	return
}

// getSysInfo call systeminfo and returns the OS version
func getSysInfo() (hostname, domain, osname, osversion string, err error) {
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("getSysInfo() -> %v", e)
		}
	}()
	// get data from the systeminfo
	out, err := exec.Command("cmd", "/C", "wmic.exe os get Caption, Version /format:list & wmic.exe computersystem get Name, domain /format:list").Output()
	if err != nil {
		panic(err)
	}
	buf := bytes.NewReader(out)
	reader := bufio.NewReader(buf)
	iter := 0
	for {
		lineBytes, _, err := reader.ReadLine()
		// don't loop more than 200 times
		if err != nil || iter > 200 {
			goto exit
		}
		line := fmt.Sprintf("%s", lineBytes)
		if strings.Contains(line, "Caption=") {
			out := strings.SplitN(line, "=", 2)
			if len(out) == 2 {
				osname = out[1]
			}
			osname = cleanString(osname)
		} else if strings.Contains(line, "Version=") {
			out := strings.SplitN(line, "=", 2)
			if len(out) == 2 {
				osversion = out[1]
			}
			osversion = cleanString(osversion)
		} else if strings.Contains(line, "Domain=") {
			out := strings.SplitN(line, "=", 2)
			if len(out) == 2 {
				domain = out[1]
			}
			domain = cleanString(domain)
		} else if strings.Contains(line, "Name=") {
			out := strings.SplitN(line, "=", 2)
			if len(out) == 2 {
				hostname = out[1]
			}
			hostname = cleanString(hostname)
		}
		iter++
	}
exit:
	return
}

// GetConfDir returns the configuration directory for the platform
func GetConfDir() string {
	return `C:\mig\`
}

// GetRunDir returns the runtime directory for the platform
func GetRunDir() string {
	return GetConfDir()
}
<|endoftext|>