<commit_before>package main

import (
	"fmt"
	"github.com/carbocation/forum.git/forum"
	"github.com/carbocation/util.git/datatypes/binarytree"
	"github.com/carbocation/util.git/datatypes/closuretable"
	"net/http"
	"strconv"
	"time"
	//"html/template"
	"database/sql"
	_ "github.com/lib/pq"
)

var db *sql.DB

func main() {
	// Initialize the DB and keep here so that it will presumably kept open in a pool
	db = initdb()
	defer db.Close()

	http.HandleFunc("/thread/", threadHandler)
	http.HandleFunc("/hello/", commentHandler)
	http.HandleFunc("/css/", cssHandler)
	http.HandleFunc("/", defaultHandler)
	http.ListenAndServe("localhost:9999", nil)
}

func initdb() *sql.DB {
	db, err := sql.Open("postgres", "dbname=forumtest sslmode=disable")
	if err != nil {
		panic(err)
	}
	//defer db.Close()

	return db
}

func defaultHandler(w http.ResponseWriter, r *http.Request) {
	remPartOfURL := r.URL.Path[len("/"):]
	fmt.Fprintf(w, "<link rel=\"stylesheet\" href=\"/css/main.css\">
Welcome, %s
Say hello", remPartOfURL)

	fmt.Fprint(w, "")
}

func cssHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/css")

	docname := r.URL.Path[len("/css/"):]

	switch {
	case docname == "main.css":
		fmt.Fprintf(w, "%s", mainCss())
	}

}

func mainCss() string {
	return `
div .comment {
	padding-left: 100px;
}
`
}

func commentHandler(w http.ResponseWriter, r *http.Request) {
	remPartOfURL := r.URL.Path[len("/hello/"):] //get everything after the /hello/ part of the URL
	//w.Header().Set("Content-Type", "text/html")

	fmt.Fprint(w, "<link rel=\"stylesheet\" href=\"/css/main.css\">")
	fmt.Fprintf(w, "Hello %s!", remPartOfURL)

	PrintNestedComments(w, ClosureTree())

	fmt.Fprint(w, "")
}

func threadHandler(w http.ResponseWriter, r *http.Request) {
	unsafeId := r.URL.Path[len("/thread/"):]

	//If the thread ID is not parseable as an integer, stop immediately
	id, err := strconv.ParseInt(unsafeId, 10, 64)
	if err != nil {
		return
	}

	// Generate a closuretable from the root requested id
	ct := closuretable.New(id)
	// Pull down the remaining elements in the closure table that are descendants of this node
	q := `select *
from entry_closures
where descendant in (
select descendant
from entry_closures
where ancestor=$1
)
and ancestor in (
select descendant
from entry_closures
where ancestor=$1
)
and depth = 1`
	stmt, err := db.Prepare(q)
	if err != nil {
		//fmt.Printf("Statement Preparation Error: %s", err)
		return
	}

	rows, err := stmt.Query(unsafeId)
	if err != nil {
		//fmt.Printf("Query Error: %v", err)
		return
	}

	//Populate the closuretable
	for rows.Next() {
		var ancestor, descendant int64
		var depth int
		err = rows.Scan(&ancestor, &descendant, &depth)
		if err != nil {
			//fmt.Printf("Rowscan error: %s", err)
			return
		}

		err = ct.AddChild(closuretable.Child{Parent: ancestor, Child: descendant})

		//err = ct.AddRelationship(closuretable.Relationship{Ancestor: ancestor, Descendant: descendant, Depth: depth})
		if err != nil {
			//fmt.Fprintf(w, "Error: %s", err)
			return
		}
	}

	fmt.Printf("Closure table is: %#v", ct)

	id, entries, err := forum.RetrieveDescendantEntries(unsafeId, db)
	if err != nil {
		//fmt.Fprintf(w, "Error: %s", err)
		return
	}

	//fmt.Printf("Entries: %#v, %s", entries, err)

	//Obligatory boxing step
	interfaceEntries := map[int64]interface{}{}
	for k, v := range entries {
		interfaceEntries[k] = v
	}

	tree, err := ct.TableToTree(interfaceEntries)
	fmt.Printf("ClosureTree is : %#v", ct)
	if err != nil {
		fmt.Printf("TableToTree error: %s", err)
	}

	fmt.Fprint(w, "<link rel=\"stylesheet\" href=\"/css/main.css\">")
	fmt.Printf("Entry: %#v\n", tree)
	PrintNestedComments(w, tree)
	fmt.Fprint(w, "")
}

func PrintNestedComments(w http.ResponseWriter, el *binarytree.Tree) {
	if el == nil {
		return
	}

	fmt.Fprint(w, "
")
	//Self
	fmt.Printf("Entry: %#v\n", el)
	e := el.Value.(forum.Entry)
	fmt.Fprintf(w, "Title: %s", e.Title)

	//Children are nested
	PrintNestedComments(w, el.Left())
	fmt.Fprint(w, "
")

	//Siblings are parallel
	PrintNestedComments(w, el.Right())
}

func ClosureTree() *binarytree.Tree {
	//Make some entries
	entries := map[int64]forum.Entry{
		0: forum.Entry{Id: 100, Title: "Title 100", Body: "Body 100", Created: time.Now(), AuthorId: 0},
		1: forum.Entry{Id: 101, Title: "Title 101", Body: "Body 101", Created: time.Now(), AuthorId: 1},
		2: forum.Entry{Id: 102, Title: "Title 102", Body: "Body 102", Created: time.Now(), AuthorId: 2},
		3: forum.Entry{Id: 103, Title: "Title 103", Body: "Body 103", Created: time.Now(), AuthorId: 3},
	}

	ct := closuretable.New(0)
	ct.AddChild(closuretable.Child{Parent: 0, Child: 1})
	ct.AddChild(closuretable.Child{Parent: 0, Child: 2})
	ct.AddChild(closuretable.Child{Parent: 1, Child: 3})

	// Obligatory boxing step
	// Convert to interface type so the generic TableToTree method can be called on these entries
	boxedEntries := map[int64]interface{}{}
	for k, v := range entries {
		boxedEntries[k] = v
	}

	tree, _ := ct.TableToTree(boxedEntries)

	return tree
}
<commit_msg>Removing commented out line.<commit_after>package main

import (
	"fmt"
	"github.com/carbocation/forum.git/forum"
	"github.com/carbocation/util.git/datatypes/binarytree"
	"github.com/carbocation/util.git/datatypes/closuretable"
	"net/http"
	"strconv"
	"time"
	//"html/template"
	"database/sql"
	_ "github.com/lib/pq"
)

var db *sql.DB

func main() {
	// Initialize the DB and keep here so that it will presumably kept open in a pool
	db = initdb()
	defer db.Close()

	http.HandleFunc("/thread/", threadHandler)
	http.HandleFunc("/hello/", commentHandler)
	http.HandleFunc("/css/", cssHandler)
	http.HandleFunc("/", defaultHandler)
	http.ListenAndServe("localhost:9999", nil)
}

func initdb() *sql.DB {
	db, err := sql.Open("postgres", "dbname=forumtest sslmode=disable")
	if err != nil {
		panic(err)
	}

	return db
}

func defaultHandler(w http.ResponseWriter, r *http.Request) {
	remPartOfURL := r.URL.Path[len("/"):]
	fmt.Fprintf(w, "<link rel=\"stylesheet\" href=\"/css/main.css\">
Welcome, %s
Say hello", remPartOfURL)

	fmt.Fprint(w, "")
}

func cssHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/css")

	docname := r.URL.Path[len("/css/"):]

	switch {
	case docname == "main.css":
		fmt.Fprintf(w, "%s", mainCss())
	}

}

func mainCss() string {
	return `
div .comment {
	padding-left: 100px;
}
`
}

func commentHandler(w http.ResponseWriter, r *http.Request) {
	remPartOfURL := r.URL.Path[len("/hello/"):] //get everything after the /hello/ part of the URL
	//w.Header().Set("Content-Type", "text/html")

	fmt.Fprint(w, "<link rel=\"stylesheet\" href=\"/css/main.css\">")
	fmt.Fprintf(w, "Hello %s!", remPartOfURL)

	PrintNestedComments(w, ClosureTree())

	fmt.Fprint(w, "")
}

func threadHandler(w http.ResponseWriter, r *http.Request) {
	unsafeId := r.URL.Path[len("/thread/"):]

	//If the thread ID is not parseable as an integer, stop immediately
	id, err := strconv.ParseInt(unsafeId, 10, 64)
	if err != nil {
		return
	}

	// Generate a closuretable from the root requested id
	ct := closuretable.New(id)
	// Pull down the remaining elements in the closure table that are descendants of this node
	q := `select *
from entry_closures
where descendant in (
select descendant
from entry_closures
where ancestor=$1
)
and ancestor in (
select descendant
from entry_closures
where ancestor=$1
)
and depth = 1`
	stmt, err := db.Prepare(q)
	if err != nil {
		//fmt.Printf("Statement Preparation Error: %s", err)
		return
	}

	rows, err := stmt.Query(unsafeId)
	if err != nil {
		//fmt.Printf("Query Error: %v", err)
		return
	}

	//Populate the closuretable
	for rows.Next() {
		var ancestor, descendant int64
		var depth int
		err = rows.Scan(&ancestor, &descendant, &depth)
		if err != nil {
			//fmt.Printf("Rowscan error: %s", err)
			return
		}

		err = ct.AddChild(closuretable.Child{Parent: ancestor, Child: descendant})

		//err = ct.AddRelationship(closuretable.Relationship{Ancestor: ancestor, Descendant: descendant, Depth: depth})
		if err != nil {
			//fmt.Fprintf(w, "Error: %s", err)
			return
		}
	}

	fmt.Printf("Closure table is: %#v", ct)

	id, entries, err := forum.RetrieveDescendantEntries(unsafeId, db)
	if err != nil {
		//fmt.Fprintf(w, "Error: %s", err)
		return
	}

	//fmt.Printf("Entries: %#v, %s", entries, err)

	//Obligatory boxing step
	interfaceEntries := map[int64]interface{}{}
	for k, v := range entries {
		interfaceEntries[k] = v
	}

	tree, err := ct.TableToTree(interfaceEntries)
	fmt.Printf("ClosureTree is : %#v", ct)
	if err != nil {
		fmt.Printf("TableToTree error: %s", err)
	}

	fmt.Fprint(w, "<link rel=\"stylesheet\" href=\"/css/main.css\">")
	fmt.Printf("Entry: %#v\n", tree)
	PrintNestedComments(w, tree)
	fmt.Fprint(w, "")
}

func PrintNestedComments(w http.ResponseWriter, el *binarytree.Tree) {
	if el == nil {
		return
	}

	fmt.Fprint(w, "
")
	//Self
	fmt.Printf("Entry: %#v\n", el)
	e := el.Value.(forum.Entry)
	fmt.Fprintf(w, "Title: %s", e.Title)

	//Children are nested
	PrintNestedComments(w, el.Left())
	fmt.Fprint(w, "
")

	//Siblings are parallel
	PrintNestedComments(w, el.Right())
}

func ClosureTree() *binarytree.Tree {
	//Make some entries
	entries := map[int64]forum.Entry{
		0: forum.Entry{Id: 100, Title: "Title 100", Body: "Body 100", Created: time.Now(), AuthorId: 0},
		1: forum.Entry{Id: 101, Title: "Title 101", Body: "Body 101", Created: time.Now(), AuthorId: 1},
		2: forum.Entry{Id: 102, Title: "Title 102", Body: "Body 102", Created: time.Now(), AuthorId: 2},
		3: forum.Entry{Id: 103, Title: "Title 103", Body: "Body 103", Created: time.Now(), AuthorId: 3},
	}

	ct := closuretable.New(0)
	ct.AddChild(closuretable.Child{Parent: 0, Child: 1})
	ct.AddChild(closuretable.Child{Parent: 0, Child: 2})
	ct.AddChild(closuretable.Child{Parent: 1, Child: 3})

	// Obligatory boxing step
	// Convert to interface type so the generic TableToTree method can be called on these entries
	boxedEntries := map[int64]interface{}{}
	for k, v := range entries {
		boxedEntries[k] = v
	}

	tree, _ := ct.TableToTree(boxedEntries)

	return tree
}
<|endoftext|>


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

package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/signal"
	"path"
	"strings"
	"sync"
	"sync/atomic"
	"syscall"

	"github.com/docker/docker/nat"
	"github.com/docker/docker/opts"
	"github.com/docker/docker/pkg/mflag"
	"github.com/fsouza/go-dockerclient"
	"github.com/pwaller/barrier"
)

// DockerErrorStatus returns the HTTP status code represented by `err` or Status
// OK if no error or 0 if err != nil and is not a docker error.
func DockerErrorStatus(err error) int {
	if err, ok := err.(*docker.Error); ok {
		return err.Status
	}
	if err == nil {
		return http.StatusOK
	}
	return 0
}

type Options struct {
	env, publish  opts.ListOpts
	source        ContainerSource
	containerArgs []string
	ports         nat.PortSet
	portBindings  nat.PortMap
}

type UpdateEvent struct {
	Source        ContainerSource
	OutputStream  io.Writer
	BuildComplete chan<- struct{}
}

// Determine if stdin is connected without blocking
func IsStdinReadable() bool {
	syscall.SetNonblock(int(os.Stdin.Fd()), true)
	_, err := os.Stdin.Read([]byte{0})
	syscall.SetNonblock(int(os.Stdin.Fd()), false)
	return err != io.EOF
}

func main() {
	var err error

	options := Options{
		env:     opts.NewListOpts(nil),
		publish: opts.NewListOpts(nil),
	}
	mflag.Var(&options.env, []string{"e", "-env"}, "Set environment variables")
	mflag.Var(&options.publish, []string{"p", "-publish"}, "Publish a container's port to the host")

	mflag.Parse()

	l := mflag.NArg()
	if l == 0 {
		options.source.Type = BuildCwd
	} else {
		args := mflag.Args()
		// If the first arg is "@", then use the Cwd
		if args[0] == "@" {
			options.source.Type = BuildCwd
		} else if args[0] == "daemon" {
			RunDaemon()
		} else {
			options.source.Type = DockerPull
			options.source.dockerImageName = args[0]
		}
		args = args[1:]
		options.containerArgs = args
	}

	if err := CheckIPTables(); err != nil {
		log.Fatal("Unable to run `iptables -L`, see README (", err, ")")
	}

	options.ports, options.portBindings, err = nat.ParsePortSpecs(options.publish.GetAll())
	if err != nil {
		log.Fatalln("--publish:", err)
	}

	log.Println("Hanoverd")

	var wg sync.WaitGroup
	defer wg.Wait()

	// Fired when we're signalled to exit
	var dying barrier.Barrier
	defer dying.Fall()

	if IsStdinReadable() {
		log.Println("Press CTRL-D to exit")
		go func() {
			defer dying.Fall()
			defer log.Println("Stdin closed, exiting...")

			// Await Stdin closure, don't care about errors
			_, _ = io.Copy(ioutil.Discard, os.Stdin)
		}()
	}

	events := make(chan UpdateEvent, 1)
	originalEvent := UpdateEvent{Source: options.source}
	events <- originalEvent

	// SIGINT handler
	go func() {
		sig := make(chan os.Signal)
		signal.Notify(sig, os.Interrupt)
		for _ = range sig {
			// For now, SIGINT always means build the working dir.
			events <- originalEvent
		}
	}()

	// SIGTERM handler
	go func() {
		defer dying.Fall()
		defer log.Println("Received SIGTERM")
		sig := make(chan os.Signal)
		signal.Notify(sig, syscall.SIGTERM)
		<-sig
	}()

	go loop(&wg, &dying, options, events)
	go httpInterface(events)

	<-dying.Barrier()
}

// Make an env []string from a list of options specified on the cmdline.
func makeEnv(opt opts.ListOpts) []string {
	var env []string
	for _, envVar := range opt.GetAll() {
		if strings.Contains(envVar, "=") {
			env = append(env, envVar)
		} else {
			env = append(env, fmt.Sprint(envVar, "=", os.Getenv(envVar)))
		}
	}
	return env
}

func httpInterface(events chan<- UpdateEvent) {
	http.HandleFunc("/update", func(w http.ResponseWriter, r *http.Request) {

		buildComplete := make(chan struct{})
		event := UpdateEvent{
			OutputStream:  NewFlushWriter(w),
			BuildComplete: buildComplete,
		}

		switch r.Method {
		case "POST":
			var (
				reader io.Reader
				err    error
			)

			switch r.Header.Get("Content-Type") {
			default:
				const msg = "Unrecognized Content-Type. Should be application/zip or application/x-tar (or x-bzip2 or gzip)"
				http.Error(w, msg, http.StatusBadRequest)
				return
			case "application/zip":
				reader, err = zip2tar(r.Body)
				if err != nil {
					const msg = "Problem whilst reading zip input"
					http.Error(w, msg, http.StatusBadRequest)
					return
				}

			case "application/x-bzip2", "application/x-tar":
				reader = r.Body
			}

			event.Source = ContainerSource{
				Type:                BuildTarballContent,
				buildTarballContent: reader,
			}
		default:
			fmt.Fprintln(w, "Signal build $PWD")
		}

		events <- event
		// Only wait on buildComplete when we know we got as far as requesting
		// the build.
		<-buildComplete
	})
	http.ListenAndServe("localhost:9123", nil)
}

func dockerConnect() (*docker.Client, error) {
	docker_host := os.Getenv("DOCKER_HOST")
	if docker_host == "" {
		docker_host = "unix:///run/docker.sock"
	}

	docker_tls_verify := os.Getenv("DOCKER_TLS_VERIFY") != ""

	var (
		client *docker.Client
		err    error
	)
	if docker_tls_verify {
		docker_cert_path := os.Getenv("DOCKER_CERT_PATH")
		docker_cert := docker_cert_path + "/cert.pem"
		docker_key := docker_cert_path + "/key.pem"
		// TODO there's no environment variable option in docker client for
		// this, it's called -tlscacert in its command line. We'll leave it
		// as the default (no CA, just trust) which boot2docker uses.
		docker_ca := ""
		client, err = docker.NewTLSClient(docker_host, docker_cert, docker_key, docker_ca)
	} else {
		client, err = docker.NewClient(docker_host)
	}
	return client, err
}

// Main loop managing the lifecycle of all containers.
func loop(wg *sync.WaitGroup, dying *barrier.Barrier, options Options, events chan UpdateEvent) {
	client, err := dockerConnect()
	if err != nil {
		dying.Fall()
		log.Println("Connecting to Docker failed:", err)
		return
	}

	wd, err := os.Getwd()
	if err != nil {
		panic(err)
	}
	baseName := path.Base(wd)

	var i uint64
	getName := func() string {
		n := atomic.AddUint64(&i, 1)
		return fmt.Sprint(baseName, "_", n)
	}

	env := makeEnv(options.env)

	var liveMutex sync.Mutex
	var live *Container

	lastEvent := <-events

	for {

		c := NewContainer(client, getName(), wg)
		c.Args = options.containerArgs
		c.Env = env

		// Global exit should cause container exit
		dying.Forward(&c.Closing)

		wg.Add(1)
		go func(c *Container) {
			defer wg.Done()

			go func() {
				for err := range c.Errors {
					log.Println("BUG: Async container error:", err)
					// TODO(pwaller): If this case is hit we might not want to
					// tear the container down really.
					c.Failed.Fall()
				}
			}()

			status, err := c.Run(lastEvent)
			if err != nil {
				switch err := err.(type) {
				case *docker.Error:
					// (name) Conflict
					if err.Status == 409 {
						// retry
						log.Printf("Container with name %q exists, using a new name...", c.Name)
						events <- lastEvent
						c.Failed.Fall()
						return
					}
				}
				log.Println("Container run failed:", strings.TrimSpace(err.Error()))
				c.Failed.Fall()
				return
			}
			log.Println("container", c.Name, "quit, exit status:", status)
		}(c)

		go func(c *Container) {

			log.Println("Awaiting container fate:", c.Name)
			select {
			case <-c.Failed.Barrier():
				log.Println("Container failed before going live:", c.Name)
				c.Closing.Fall()
				return
			case <-c.Superceded.Barrier():
				log.Println("Container superceded before going live:", c.Name)
				c.Closing.Fall()
				return
			case <-c.Closing.Barrier():
				log.Println("Container closed before going live:", c.Name)
				return

			case <-c.Ready.Barrier():
			}

			log.Println("Container going live:", c.Name)

			liveMutex.Lock()
			defer liveMutex.Unlock()
			previousLive := live

			// Block main exit until the firewall rule has been placed
			// (and removed)
			wg.Add(1)
			defer wg.Done()

			// get the public port for an internal one
			getMappedPort := func(p int) (int, bool) {
				for _, m := range c.container.NetworkSettings.PortMappingAPI() {
					if int(m.PrivatePort) == p {
						return int(m.PublicPort), true
					}
				}
				return -1, false
			}

			removal := []func(){}

			defer func() {
				// Block main exit until firewall rule has been removed
				wg.Add(1)
				go func() {
					defer wg.Done()

					<-c.Closing.Barrier()
					for _, remove := range removal {
						remove()
					}
				}()
			}()

			for internalPort, bindings := range options.portBindings {
				if mappedPort, ok := getMappedPort(internalPort.Int()); ok {
					for _, binding := range bindings {
						var public int
						_, err := fmt.Sscan(binding.HostPort, &public)
						if err != nil {
							// If no public port specified, use same port as internal port
							public = internalPort.Int()
						}

						ipAddress := c.container.NetworkSettings.IPAddress
						remove, err := ConfigureRedirect(public, mappedPort, ipAddress)
						if err != nil {
							// Firewall rule didn't get applied.
							c.err(fmt.Errorf("Firewall rule application failed: %q (public: %v, private: %v)", err, public, internalPort))
							return
						}

						removal = append(removal, remove)
					}
				} else {
					c.err(fmt.Errorf("Docker image not exposing port %v!", internalPort))
					return
				}
			}

			live = c
			if previousLive != nil {
				previousLive.Closing.Fall()
			}

		}(c)

		lastEvent = <-events

		c.Superceded.Fall()

		log.Println("Signalled!")
	}
}
<commit_msg>Use codegangsta/cli for option parsing<commit_after>// Copyright 2014 The Hanoverd Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/signal"
	"path"
	"strings"
	"sync"
	"sync/atomic"
	"syscall"

	"github.com/codegangsta/cli"
	"github.com/docker/docker/nat"
	"github.com/fsouza/go-dockerclient"
	"github.com/pwaller/barrier"
)

// DockerErrorStatus returns the HTTP status code represented by `err` or Status
// OK if no error or 0 if err != nil and is not a docker error.
func DockerErrorStatus(err error) int {
	if err, ok := err.(*docker.Error); ok {
		return err.Status
	}
	if err == nil {
		return http.StatusOK
	}
	return 0
}

type Options struct {
	env, publish  []string
	source        ContainerSource
	containerArgs []string
	ports         nat.PortSet
	portBindings  nat.PortMap
}

type UpdateEvent struct {
	Source        ContainerSource
	OutputStream  io.Writer
	BuildComplete chan<- struct{}
}

// Determine if stdin is connected without blocking
func IsStdinReadable() bool {
	syscall.SetNonblock(int(os.Stdin.Fd()), true)
	_, err := os.Stdin.Read([]byte{0})
	syscall.SetNonblock(int(os.Stdin.Fd()), false)
	return err != io.EOF
}

func main() {
	app := cli.NewApp()

	app.Name = "hanoverd"
	app.Usage = "handover docker containers"

	app.Flags = []cli.Flag{
		cli.StringSliceFlag{
			Name:  "env, e",
			Usage: "environment variables to pass (reads from env if = omitted)",
			Value: &cli.StringSlice{},
		},
		cli.StringSliceFlag{
			Name:  "publish, p",
			Usage: "ports to publish (same syntax as docker)",
			Value: &cli.StringSlice{},
		},
	}

	app.Action = oldMain

	app.RunAndExitOnError()
}

func oldMain(c *cli.Context) {
	var err error

	options := Options{}
	options.env = makeEnv(c.StringSlice("env"))
	options.statusURI = c.String("status-uri")

	if len(c.Args()) == 0 {
		options.source.Type = BuildCwd
	} else {
		args := c.Args()
		// If the first arg is "@", then use the Cwd
		if args[0] == "@" {
			options.source.Type = BuildCwd
		} else if args[0] == "daemon" {
			RunDaemon()
		} else {
			options.source.Type = DockerPull
			options.source.dockerImageName = args[0]
		}
		args = args[1:]
		options.containerArgs = args
	}

	if err := CheckIPTables(); err != nil {
		log.Fatal("Unable to run `iptables -L`, see README (", err, ")")
	}

	options.ports, options.portBindings, err = nat.ParsePortSpecs(c.StringSlice("publish"))
	if err != nil {
		log.Fatalln("--publish:", err)
	}

	log.Println("Hanoverd")

	var wg sync.WaitGroup
	defer wg.Wait()

	// Fired when we're signalled to exit
	var dying barrier.Barrier
	defer dying.Fall()

	if IsStdinReadable() {
		log.Println("Press CTRL-D to exit")
		go func() {
			defer dying.Fall()
			defer log.Println("Stdin closed, exiting...")

			// Await Stdin closure, don't care about errors
			_, _ = io.Copy(ioutil.Discard, os.Stdin)
		}()
	}

	events := make(chan UpdateEvent, 1)
	originalEvent := UpdateEvent{Source: options.source}
	events <- originalEvent

	// SIGINT handler
	go func() {
		sig := make(chan os.Signal)
		signal.Notify(sig, os.Interrupt)
		for _ = range sig {
			// For now, SIGINT always means build the working dir.
			events <- originalEvent
		}
	}()

	// SIGTERM handler
	go func() {
		defer dying.Fall()
		defer log.Println("Received SIGTERM")
		sig := make(chan os.Signal)
		signal.Notify(sig, syscall.SIGTERM)
		<-sig
	}()

	go loop(&wg, &dying, options, events)
	go httpInterface(events)

	<-dying.Barrier()
}

// Make an env []string from a list of options specified on the cmdline.
func makeEnv(opts []string) []string {
	var env []string
	for _, envVar := range opts {
		if strings.Contains(envVar, "=") {
			env = append(env, envVar)
		} else {
			env = append(env, fmt.Sprint(envVar, "=", os.Getenv(envVar)))
		}
	}
	return env
}

func httpInterface(events chan<- UpdateEvent) {
	http.HandleFunc("/update", func(w http.ResponseWriter, r *http.Request) {

		buildComplete := make(chan struct{})
		event := UpdateEvent{
			OutputStream:  NewFlushWriter(w),
			BuildComplete: buildComplete,
		}

		switch r.Method {
		case "POST":
			var (
				reader io.Reader
				err    error
			)

			switch r.Header.Get("Content-Type") {
			default:
				const msg = "Unrecognized Content-Type. Should be application/zip or application/x-tar (or x-bzip2 or gzip)"
				http.Error(w, msg, http.StatusBadRequest)
				return
			case "application/zip":
				reader, err = zip2tar(r.Body)
				if err != nil {
					const msg = "Problem whilst reading zip input"
					http.Error(w, msg, http.StatusBadRequest)
					return
				}

			case "application/x-bzip2", "application/x-tar":
				reader = r.Body
			}

			event.Source = ContainerSource{
				Type:                BuildTarballContent,
				buildTarballContent: reader,
			}
		default:
			fmt.Fprintln(w, "Signal build $PWD")
		}

		events <- event
		// Only wait on buildComplete when we know we got as far as requesting
		// the build.
		<-buildComplete
	})
	http.ListenAndServe("localhost:9123", nil)
}

func dockerConnect() (*docker.Client, error) {
	docker_host := os.Getenv("DOCKER_HOST")
	if docker_host == "" {
		docker_host = "unix:///run/docker.sock"
	}

	docker_tls_verify := os.Getenv("DOCKER_TLS_VERIFY") != ""

	var (
		client *docker.Client
		err    error
	)
	if docker_tls_verify {
		docker_cert_path := os.Getenv("DOCKER_CERT_PATH")
		docker_cert := docker_cert_path + "/cert.pem"
		docker_key := docker_cert_path + "/key.pem"
		// TODO there's no environment variable option in docker client for
		// this, it's called -tlscacert in its command line. We'll leave it
		// as the default (no CA, just trust) which boot2docker uses.
		docker_ca := ""
		client, err = docker.NewTLSClient(docker_host, docker_cert, docker_key, docker_ca)
	} else {
		client, err = docker.NewClient(docker_host)
	}
	return client, err
}

// Main loop managing the lifecycle of all containers.
func loop(wg *sync.WaitGroup, dying *barrier.Barrier, options Options, events chan UpdateEvent) {
	client, err := dockerConnect()
	if err != nil {
		dying.Fall()
		log.Println("Connecting to Docker failed:", err)
		return
	}

	wd, err := os.Getwd()
	if err != nil {
		panic(err)
	}
	baseName := path.Base(wd)

	var i uint64
	getName := func() string {
		n := atomic.AddUint64(&i, 1)
		return fmt.Sprint(baseName, "_", n)
	}

	var liveMutex sync.Mutex
	var live *Container

	lastEvent := <-events

	for {

		c := NewContainer(client, getName(), wg)
		c.Args = options.containerArgs
		c.Env = options.env

		// Global exit should cause container exit
		dying.Forward(&c.Closing)

		wg.Add(1)
		go func(c *Container) {
			defer wg.Done()

			go func() {
				for err := range c.Errors {
					log.Println("BUG: Async container error:", err)
					// TODO(pwaller): If this case is hit we might not want to
					// tear the container down really.
					c.Failed.Fall()
				}
			}()

			status, err := c.Run(lastEvent)
			if err != nil {
				switch err := err.(type) {
				case *docker.Error:
					// (name) Conflict
					if err.Status == 409 {
						// retry
						log.Printf("Container with name %q exists, using a new name...", c.Name)
						events <- lastEvent
						c.Failed.Fall()
						return
					}
				}
				log.Println("Container run failed:", strings.TrimSpace(err.Error()))
				c.Failed.Fall()
				return
			}
			log.Println("container", c.Name, "quit, exit status:", status)
		}(c)

		go func(c *Container) {

			log.Println("Awaiting container fate:", c.Name)
			select {
			case <-c.Failed.Barrier():
				log.Println("Container failed before going live:", c.Name)
				c.Closing.Fall()
				return
			case <-c.Superceded.Barrier():
				log.Println("Container superceded before going live:", c.Name)
				c.Closing.Fall()
				return
			case <-c.Closing.Barrier():
				log.Println("Container closed before going live:", c.Name)
				return

			case <-c.Ready.Barrier():
			}

			log.Println("Container going live:", c.Name)

			liveMutex.Lock()
			defer liveMutex.Unlock()
			previousLive := live

			// Block main exit until the firewall rule has been placed
			// (and removed)
			wg.Add(1)
			defer wg.Done()

			// get the public port for an internal one
			getMappedPort := func(p int) (int, bool) {
				for _, m := range c.container.NetworkSettings.PortMappingAPI() {
					if int(m.PrivatePort) == p {
						return int(m.PublicPort), true
					}
				}
				return -1, false
			}

			removal := []func(){}

			defer func() {
				// Block main exit until firewall rule has been removed
				wg.Add(1)
				go func() {
					defer wg.Done()

					<-c.Closing.Barrier()
					for _, remove := range removal {
						remove()
					}
				}()
			}()

			for internalPort, bindings := range options.portBindings {
				if mappedPort, ok := getMappedPort(internalPort.Int()); ok {
					for _, binding := range bindings {
						var public int
						_, err := fmt.Sscan(binding.HostPort, &public)
						if err != nil {
							// If no public port specified, use same port as internal port
							public = internalPort.Int()
						}

						ipAddress := c.container.NetworkSettings.IPAddress
						remove, err := ConfigureRedirect(public, mappedPort, ipAddress)
						if err != nil {
							// Firewall rule didn't get applied.
							c.err(fmt.Errorf("Firewall rule application failed: %q (public: %v, private: %v)", err, public, internalPort))
							return
						}

						removal = append(removal, remove)
					}
				} else {
					c.err(fmt.Errorf("Docker image not exposing port %v!", internalPort))
					return
				}
			}

			live = c
			if previousLive != nil {
				previousLive.Closing.Fall()
			}

		}(c)

		lastEvent = <-events

		c.Superceded.Fall()

		log.Println("Signalled!")
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/mgutz/minimist"
	"os"
)

var name = "hewer"
var version = "0.2.0"

var usage = `
Mine the crap out of some JSON-only log files

Usage: hewer [options] file [files...]
Options:
   -k <key>, --key <key>        Operate on this JSON key, either collecting
                                stats or converting its values

   -c <type>, --convert <type>  Convert the value at <key> to this type
                                and print modified JSON to stdout. Valid
                                values are number, json, string

   -h, --help                   Print this content and exit

   -v, --version                Print version and exit
`

func main() {
	// parse command line args
	argm := minimist.Parse()

	// check for help flag
	if argm.AsBool("help", "h", "?") {
		helpAndExit()
	}

	// check for version flag
	if argm.AsBool("v", "version") {
		fmt.Println(version)
		os.Exit(0)
	}

	// check for file args
	args := argm["_"].([]string)
	if len(args) < 1 {
		helpAndExit()
	}

	//TODO verify existence of files

	// grab optional "key" flag and init analytics
	key := argm.MayString("", "key", "k")

	convert := argm.MayString("", "convert", "c")

	//TODO parse mulitple files concurrently
	if convert == "" {
		analytics := NewAnalytics(key)
		for _, value := range args {
			ParseFile(value, analytics)
		}
		// print all results
		analytics.Print()
	} else {
		converter := NewConverter(key, convert)
		for _, value := range args {
			ParseAndConvertFile(value, converter)
		}
	}
}

func helpAndExit() {
	fmt.Println(usage)
	os.Exit(0)
}
<commit_msg>no longer requires mined files to be "JSON-only" •ᴗ•<commit_after>package main

import (
	"fmt"
	"github.com/mgutz/minimist"
	"os"
)

var name = "hewer"
var version = "0.2.0"

var usage = `
Mine the crap out of some JSON-based log files

Usage: hewer [options] file [files...]
Options:
   -k <key>, --key <key>        Operate on this JSON key, either collecting
                                stats or converting its values

   -c <type>, --convert <type>  Convert the value at <key> to this type
                                and print modified JSON to stdout. Valid
                                values are number, json, string

   -h, --help                   Print this content and exit

   -v, --version                Print version and exit
`

func main() {
	// parse command line args
	argm := minimist.Parse()

	// check for help flag
	if argm.AsBool("help", "h", "?") {
		helpAndExit()
	}

	// check for version flag
	if argm.AsBool("v", "version") {
		fmt.Println(version)
		os.Exit(0)
	}

	// check for file args
	args := argm["_"].([]string)
	if len(args) < 1 {
		helpAndExit()
	}

	//TODO verify existence of files

	// grab optional "key" flag and init analytics
	key := argm.MayString("", "key", "k")

	convert := argm.MayString("", "convert", "c")

	//TODO parse mulitple files concurrently
	if convert == "" {
		analytics := NewAnalytics(key)
		for _, value := range args {
			ParseFile(value, analytics)
		}
		// print all results
		analytics.Print()
	} else {
		converter := NewConverter(key, convert)
		for _, value := range args {
			ParseAndConvertFile(value, converter)
		}
	}
}

func helpAndExit() {
	fmt.Println(usage)
	os.Exit(0)
}
<|endoftext|>


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

package main

import (
	"flag"
	"fmt"
	"os"
	"os/signal"
	"syscall"

	"github.com/google/gops/agent"
	"github.com/tsuru/bs/bslog"
	"github.com/tsuru/bs/config"
	"github.com/tsuru/bs/log"
	"github.com/tsuru/bs/metric"
	_ "github.com/tsuru/bs/metric/logstash"
	"github.com/tsuru/bs/status"
)

const (
	version = "v1.13-rc6"
)

var printVersion bool

type StopWaiter interface {
	Stop()
	Wait()
}

func init() {
	flag.BoolVar(&printVersion, "version", false, "Print version and exit")
}

func startSignalHandler(callback func(os.Signal), signals ...os.Signal) {
	sigChan := make(chan os.Signal, 4)
	go func() {
		if signal, ok := <-sigChan; ok {
			callback(signal)
		}
	}()
	signal.Notify(sigChan, signals...)
}

func main() {
	err := agent.Listen(&agent.Options{
		NoShutdownCleanup: true,
	})
	if err != nil {
		bslog.Fatalf("Unable to initialize gops agent: %s\n", err)
	}
	defer agent.Close()
	flag.Parse()
	if printVersion {
		fmt.Printf("bs version %s\n", version)
		return
	}
	lf := log.LogForwarder{
		BindAddress:     config.Config.SyslogListenAddress,
		DockerEndpoint:  config.Config.DockerEndpoint,
		EnabledBackends: config.Config.LogBackends,
	}
	err = lf.Start()
	if err != nil {
		bslog.Fatalf("Unable to initialize log forwarder: %s\n", err)
	}
	mRunner := metric.NewRunner(config.Config.DockerEndpoint, config.Config.MetricsInterval,
		config.Config.MetricsBackend)
	mRunner.EnableBasicMetrics = config.Config.MetricsEnableBasic
	mRunner.EnableConnMetrics = config.Config.MetricsEnableConn
	mRunner.EnableHostMetrics = config.Config.MetricsEnableHost
	err = mRunner.Start()
	if err != nil {
		bslog.Warnf("Unable to initialize metrics runner: %s\n", err)
	}
	reporter, err := status.NewReporter(&status.ReporterConfig{
		TsuruEndpoint:  config.Config.TsuruEndpoint,
		TsuruToken:     config.Config.TsuruToken,
		DockerEndpoint: config.Config.DockerEndpoint,
		Interval:       config.Config.StatusInterval,
	})
	if err != nil {
		bslog.Warnf("Unable to initialize status reporter: %s\n", err)
	}
	monitorEl := []StopWaiter{&lf, mRunner}
	if reporter != nil {
		monitorEl = append(monitorEl, reporter)
	}
	var signaled bool
	startSignalHandler(func(signal os.Signal) {
		signaled = true
		for _, m := range monitorEl {
			go m.Stop()
		}
	}, os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT)
	for _, m := range monitorEl {
		m.Wait()
	}
	if !signaled {
		bslog.Fatalf("Exiting bs because no service could be initialized.")
	}
}
<commit_msg>bump version to 1.13<commit_after>// Copyright 2016 bs authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"flag"
	"fmt"
	"os"
	"os/signal"
	"syscall"

	"github.com/google/gops/agent"
	"github.com/tsuru/bs/bslog"
	"github.com/tsuru/bs/config"
	"github.com/tsuru/bs/log"
	"github.com/tsuru/bs/metric"
	_ "github.com/tsuru/bs/metric/logstash"
	"github.com/tsuru/bs/status"
)

const (
	version = "v1.13"
)

var printVersion bool

type StopWaiter interface {
	Stop()
	Wait()
}

func init() {
	flag.BoolVar(&printVersion, "version", false, "Print version and exit")
}

func startSignalHandler(callback func(os.Signal), signals ...os.Signal) {
	sigChan := make(chan os.Signal, 4)
	go func() {
		if signal, ok := <-sigChan; ok {
			callback(signal)
		}
	}()
	signal.Notify(sigChan, signals...)
}

func main() {
	err := agent.Listen(&agent.Options{
		NoShutdownCleanup: true,
	})
	if err != nil {
		bslog.Fatalf("Unable to initialize gops agent: %s\n", err)
	}
	defer agent.Close()
	flag.Parse()
	if printVersion {
		fmt.Printf("bs version %s\n", version)
		return
	}
	lf := log.LogForwarder{
		BindAddress:     config.Config.SyslogListenAddress,
		DockerEndpoint:  config.Config.DockerEndpoint,
		EnabledBackends: config.Config.LogBackends,
	}
	err = lf.Start()
	if err != nil {
		bslog.Fatalf("Unable to initialize log forwarder: %s\n", err)
	}
	mRunner := metric.NewRunner(config.Config.DockerEndpoint, config.Config.MetricsInterval,
		config.Config.MetricsBackend)
	mRunner.EnableBasicMetrics = config.Config.MetricsEnableBasic
	mRunner.EnableConnMetrics = config.Config.MetricsEnableConn
	mRunner.EnableHostMetrics = config.Config.MetricsEnableHost
	err = mRunner.Start()
	if err != nil {
		bslog.Warnf("Unable to initialize metrics runner: %s\n", err)
	}
	reporter, err := status.NewReporter(&status.ReporterConfig{
		TsuruEndpoint:  config.Config.TsuruEndpoint,
		TsuruToken:     config.Config.TsuruToken,
		DockerEndpoint: config.Config.DockerEndpoint,
		Interval:       config.Config.StatusInterval,
	})
	if err != nil {
		bslog.Warnf("Unable to initialize status reporter: %s\n", err)
	}
	monitorEl := []StopWaiter{&lf, mRunner}
	if reporter != nil {
		monitorEl = append(monitorEl, reporter)
	}
	var signaled bool
	startSignalHandler(func(signal os.Signal) {
		signaled = true
		for _, m := range monitorEl {
			go m.Stop()
		}
	}, os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT)
	for _, m := range monitorEl {
		m.Wait()
	}
	if !signaled {
		bslog.Fatalf("Exiting bs because no service could be initialized.")
	}
}
<|endoftext|>


<commit_before>package main

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

	"github.com/gorilla/handlers"
	"github.com/gorilla/mux"
	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
)

var (
	addr = flag.String("addr", ":8080", "The address and port to bind to for the webserver")
)

type Basebox struct {
	Namespace string
	Name      string
	Version   string
	Provider  string
	File      string
}

type Provider struct {
	Name string `json:"name"`
	Url  string `json:"url"`
}

type Version struct {
    DescriptionHtml string `json:"description_html"`
	DescriptionMarkdown string `json:"description_markdown"`
	Version  string `json:"version"`
	Status   string `json:"status"`
	Provders []Provider `json:"providers"`
}

type Manifest struct {
	Description      string `json:"description"`
	ShortDescription string `json:"short_description"`
	Name             string `json:"name"`
	Versions         []Version `json:"versions"`
}

func RootHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Add("Content-Type", "text/plain")
	w.WriteHeader(http.StatusOK)
	io.WriteString(w, "Hello World")
}

func ManifestHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	namespace := vars["namespace"]
	name := vars["name"]

	result := Basebox{}
	collection := session.DB("coeus").C("boxes")

	iter := collection.Find(bson.M{"namespace": namespace, "name": name}).Iter()
	var versions []Version
	for iter.Next(&result) {
		var p []Provider
		p = append(p, Provider{result.Provider, "http://" + r.Host + "/" + namespace + "/boxes/" + name + "/" + result.Version + "/" + result.Provider + ".box"})
		versions = append(versions, Version{"","",result.Version, "active", p})
	}
	msg, err := json.Marshal(Manifest{
		"Generated manifest for " + namespace + "/" + name,
		name,
		namespace + "/" + name,
		versions,
	})
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
	} else {
		w.Header().Add("Content-Type", "application/json; charset=utf-8")
		w.WriteHeader(http.StatusOK)
		w.Write(msg)
	}
}

func ProviderHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	namespace := vars["namespace"]
	name := vars["name"]
	version := vars["version"]
	provider := vars["provider"]

	result := Basebox{}
	collection := session.DB("coeus").C("boxes")

	collection.Find(bson.M{"namespace": namespace, "name": name, "version": version, "provider": provider[0:strings.LastIndex(provider, ".")]}).One(&result)
	file, err := session.DB("coeus").GridFS("coeus").Open(result.File)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
	} else {
		w.Header().Add("Content-Type", "application/octet-stream")
		w.Header().Add("Content-Length",strconv.FormatInt(file.Size(),10))
		w.WriteHeader(http.StatusOK)
		http.ServeContent(w,r,file.Name(),file.UploadDate(),file)
		file.Close()
	}
}

func UploadHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	namespace := vars["namespace"]
	name := vars["name"]
	version := vars["version"]
	provider := vars["provider"]
	basename := namespace + ":" + name + "-" + version + ".box"

	if err := r.ParseMultipartForm(1000000000); err != nil { // Parse using 1Gb chunks
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	if len(r.MultipartForm.File) > 1 {
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	for _, boxes := range r.MultipartForm.File {
		if len(boxes) > 1 {
			w.WriteHeader(http.StatusBadRequest)
			return
		}
		for i, _ := range boxes {
			f, err := boxes[i].Open()
			if err != nil {
				w.WriteHeader(http.StatusInternalServerError)
				return
			}
			defer f.Close()

			if file, err := session.DB("coeus").GridFS("coeus").Create(basename); err != nil {
				w.WriteHeader(http.StatusInternalServerError)
				return
			} else {
				defer file.Close()
				file.SetName(basename)
				if _, err := io.Copy(file, f); err != nil {
					w.WriteHeader(http.StatusInternalServerError)
					return
				}
			}
		}
	}
	collection := session.DB("coeus").C("boxes")
	collection.Insert(&Basebox{namespace, name, version, provider, basename})
	w.WriteHeader(http.StatusOK)
}

var session *mgo.Session

func init() {
	flag.Parse()
	var err error
	session, err = mgo.Dial("localhost:27017/coeus")
	if err != nil {
		panic(err)
	}

	collection := session.DB("coeus").C("boxes")

	collection.DropIndex("name", "version")
	collection.EnsureIndex(mgo.Index{
		Key:    []string{"namespace", "name", "version"},
		Unique: true,
	})

}

func main() {
	print("Running coeus\n")

	router := mux.NewRouter()
	router.HandleFunc("/", RootHandler)
	router.HandleFunc("/{namespace}/{name}", ManifestHandler)
	router.HandleFunc("/{namespace}/boxes/{name}/{version:[0-9\\.]*}/{provider:.*.box}", ProviderHandler).Methods("GET")
	router.HandleFunc("/{namespace}/{name}/{version:[0-9\\.]*}/{provider:.*.box}", UploadHandler).Methods("POST")

	//http.Handle("/", router)
	http.ListenAndServe(*addr, handlers.LoggingHandler(os.Stdout, router))

	session.Close()
}
<commit_msg>Changes to main.go<commit_after>package main

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

	"github.com/gorilla/handlers"
	"github.com/gorilla/mux"
	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
)

var (
	addr = flag.String("addr", ":8080", "The address and port to bind to for the webserver")
)

type Basebox struct {
	Namespace string
	Name      string
	Version   string
	Provider  string
	File      string
}

type Provider struct {
	Name string `json:"name"`
	Url  string `json:"url"`
}

type Version struct {
    DescriptionHtml string `json:"description_html"`
	DescriptionMarkdown string `json:"description_markdown"`
	Version  string `json:"version"`
	Status   string `json:"status"`
	Provders []Provider `json:"providers"`
}

type Manifest struct {
	Description      string `json:"description"`
	ShortDescription string `json:"short_description"`
	Name             string `json:"name"`
	Versions         []Version `json:"versions"`
}

func RootHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Add("Content-Type", "text/plain")
	w.WriteHeader(http.StatusOK)
	io.WriteString(w, "Hello World")
}

func ManifestHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	namespace := vars["namespace"]
	name := vars["name"]

	result := Basebox{}
	collection := session.DB("coeus").C("boxes")

	iter := collection.Find(bson.M{"namespace": namespace, "name": name}).Iter()
	var versions []Version
	for iter.Next(&result) {
		var p []Provider
		p = append(p, Provider{result.Provider, "http://" + r.Host + "/" + namespace + "/boxes/" + name + "/" + result.Version + "/" + result.Provider + ".box"})
		versions = append(versions, Version{"","",result.Version, "active", p})
	}
	msg, err := json.Marshal(Manifest{
		"Generated manifest for " + namespace + "/" + name,
		name,
		namespace + "/" + name,
		versions,
	})
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
	} else {
		w.Header().Add("Content-Type", "application/json; charset=utf-8")
		w.WriteHeader(http.StatusOK)
		w.Write(msg)
	}
}

func ProviderHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	namespace := vars["namespace"]
	name := vars["name"]
	version := vars["version"]
	provider := vars["provider"]

	result := Basebox{}
	collection := session.DB("coeus").C("boxes")

	collection.Find(bson.M{"namespace": namespace, "name": name, "version": version, "provider": provider[0:strings.LastIndex(provider, ".")]}).One(&result)
	file, err := session.DB("coeus").GridFS("coeus").Open(result.File)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
	} else {
		w.Header().Add("Content-Type", "application/octet-stream")
		w.Header().Add("Content-Length",strconv.FormatInt(file.Size(),10))
		w.WriteHeader(http.StatusOK)
		http.ServeContent(w,r,file.Name(),file.UploadDate(),file)
		file.Close()
	}
}

func UploadHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	namespace := vars["namespace"]
	name := vars["name"]
	version := vars["version"]
	provider := vars["provider"]
	basename := namespace + ":" + name + "-" + version + ".box"

	if err := r.ParseMultipartForm(1000000000); err != nil { // Parse using 1Gb chunks
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	if len(r.MultipartForm.File) > 1 {
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	for _, boxes := range r.MultipartForm.File {
		if len(boxes) > 1 {
			w.WriteHeader(http.StatusBadRequest)
			return
		}
		for i, _ := range boxes {
			f, err := boxes[i].Open()
			if err != nil {
				w.WriteHeader(http.StatusInternalServerError)
				return
			}
			defer f.Close()

			if file, err := session.DB("coeus").GridFS("coeus").Create(basename); err != nil {
				w.WriteHeader(http.StatusInternalServerError)
				return
			} else {
				defer file.Close()
				file.SetName(basename)
				if _, err := io.Copy(file, f); err != nil {
					w.WriteHeader(http.StatusInternalServerError)
					return
				}
			}
		}
	}
	collection := session.DB("coeus").C("boxes")
	collection.Insert(&Basebox{namespace, name, version, provider, basename})
	w.WriteHeader(http.StatusOK)
}

func DeleteHandler(w http.ResponseWriter, r *http.Request) {
    vars := mux.Vars(r)
	namespace := vars["namespace"]
	name := vars["name"]
	version := vars["version"]

	// Rightnow we are only supporting virtualbox so this is generated
	// from the above information
	basename := namespace + ":" + name + "-" + version + ".box"
	session.DB("coeus").GridFS("coeus").Remove(basename)

	w.WriteHeader(http.StatusOK)
}

var session *mgo.Session

func init() {
	flag.Parse()
	var err error
	session, err = mgo.Dial("localhost:27017/coeus")
	if err != nil {
		panic(err)
	}

	collection := session.DB("coeus").C("boxes")

	collection.DropIndex("name", "version")
	collection.EnsureIndex(mgo.Index{
		Key:    []string{"namespace", "name", "version"},
		Unique: true,
	})

}

func main() {
	print("Running coeus\n")

	router := mux.NewRouter()
	router.HandleFunc("/", RootHandler)
	router.HandleFunc("/{namespace}/{name}", ManifestHandler)
	router.HandleFunc("/{namespace}/boxes/{name}/{version:[0-9\\.]*}/{provider:.*.box}", ProviderHandler).Methods("GET")
	router.HandleFunc("/{namespace}/{name}/{version:[0-9\\.]*}/{provider:.*.box}", UploadHandler).Methods("POST")
    router.HandleFunc("/{namespace}/{name}/{version:[0-9\\.]*}", DeleteHandler).Methods("DELETE")

	//http.Handle("/", router)
	http.ListenAndServe(*addr, handlers.LoggingHandler(os.Stdout, router))

	session.Close()
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"context"
	"flag"
	"fmt"
	"log"
	"net/http"
	"net/http/httputil"
	"os"
	"strings"
	"time"

	"github.com/digitalocean/godo"
	"github.com/miekg/dns"
	"golang.org/x/oauth2"

	"github.com/abrander/dozone/proxy"
)

const (
	patEnvName = "DIGITALOCEAN_ACCESS_TOKEN"
)

var (
	pat tokenSource

	client    *godo.Client
	debugHTTP = true
	yes       = true
	download  string
)

func init() {
	pat = tokenSource(os.Getenv(patEnvName))

	if pat == "" {
		bail("Please set the environment variable: %s\n", patEnvName)
	}

	flag.BoolVar(&debugHTTP, "debugHTTP", false, "Output Digital Ocean API requests for debugging")
	flag.BoolVar(&yes, "yes", false, "Don't ask before committing")
	flag.StringVar(&download, "download", "", "Download zone")

	flag.Parse()
}

func getClient() *godo.Client {
	if client != nil {
		return client
	}

	oauthClient := oauth2.NewClient(oauth2.NoContext, pat)
	client = godo.NewClient(oauthClient)

	if debugHTTP {
		client.OnRequestCompleted(func(req *http.Request, resp *http.Response) {
			data, err := httputil.DumpRequestOut(req, true)
			if err == nil {
				fmt.Printf("\033[33m%s\033[0m\n", data)
			} else {
				log.Fatalf("\033[33mERROR: %s\033[0m\n", err.Error())
			}

			data, err = httputil.DumpResponse(resp, true)
			if err == nil {
				fmt.Printf("\033[32m%s\033[0m\n", data)
			} else {
				log.Fatalf("\033[32mERROR: %s\033[0m\n", err.Error())
			}
		})
	}

	return client
}

func bail(format string, args ...interface{}) {
	fmt.Fprintf(os.Stderr, format, args...)
	os.Exit(1)
}

func bailIfError(err error) {
	if err != nil {
		bail("Error: %s\n", err.Error())
	}
}

func main() {
	client := getClient()

	if download != "" {
		dom := proxy.NewDomain(proxy.NewZoneName(download))

		err := dom.Find(client)
		bailIfError(err)

		fmt.Printf("%s", dom.ZoneFile)

		os.Exit(0)
	}

	filename := flag.Arg(0)
	r, err := os.Open(filename)
	bailIfError(err)
	defer r.Close()

	var zoneTokens []*tokenContainer
	var zoneName proxy.ZoneName

	for token := range dns.ParseZone(r, "", "") {
		if token.Error != nil {
			bail("Error: %s\n", token.Error.Error())
		}

		switch token.RR.(type) {
		case *dns.A:
			zoneTokens = append(zoneTokens, &tokenContainer{Token: token})
		case *dns.AAAA:
			zoneTokens = append(zoneTokens, &tokenContainer{Token: token})
		case *dns.CNAME:
			zoneTokens = append(zoneTokens, &tokenContainer{Token: token})
		case *dns.MX:
			zoneTokens = append(zoneTokens, &tokenContainer{Token: token})
		case *dns.NS:
			zoneTokens = append(zoneTokens, &tokenContainer{Token: token})
		case *dns.SOA:
			soa := token.RR.(*dns.SOA)
			trimmed := strings.Trim(soa.Header().Name, ".")
			if trimmed != "" {
				zoneName = proxy.NewZoneName(soa.Header().Name)
			}
		case *dns.SRV:
			zoneTokens = append(zoneTokens, &tokenContainer{Token: token})
		case *dns.TXT:
			zoneTokens = append(zoneTokens, &tokenContainer{Token: token})
		default:
			fmt.Printf("%T is not supported\n", token.RR)
		}
	}

	if zoneName.String("") == "" {
		bail("Could not derive zone name from zone file")
	}

	dom := proxy.NewDomain(zoneName)

	err = dom.FindOrAdd(client)
	bailIfError(err)

	err = dom.RefreshRecords(client)
	bailIfError(err)

	// Match the zone with records retrieved from DO.
	for _, rec := range dom.Records {
		for _, token := range zoneTokens {
			if !token.matched && rec.Matches(token.Token) {
				rec.Matched = true
				token.matched = true
			}
		}
	}

	// Find records to delete.
	toDelete := make(map[godo.DomainRecord]bool)
	for _, rec := range dom.Records {
		if !rec.Matched {
			toDelete[rec.DomainRecord] = true
		}
	}

	// Find records to add.
	toAdd := make(map[*tokenContainer]*godo.DomainRecordEditRequest)
	for _, token := range zoneTokens {
		if !token.matched {
			toAdd[token] = token.CreateRequest()
		}
	}

	// Find records to edit
	toEdit := make(map[godo.DomainRecord]*godo.DomainRecordEditRequest)
	for rec := range toDelete {
		for token := range toAdd {
			req := token.CreateRequest()
			if req.Name == zoneName.FQDN(rec.Name) && req.Type == rec.Type {
				toEdit[rec] = token.CreateRequest()

				// Remove from add/delete maps.
				delete(toAdd, token)
				delete(toDelete, rec)
			}
		}
	}

	numChanges := 0

	if !yes {
		// Present work for the user.
		if len(toDelete) > 0 {
			fmt.Printf("Records to delete:\n")
			for r := range toDelete {
				fmt.Printf("%s\n", r.String())
			}
			fmt.Printf("\n")
		}

		numChanges += len(toDelete)

		if len(toAdd) > 0 {
			fmt.Printf("Records to add:\n")
			for _, r := range toAdd {
				fmt.Printf("%s\n", r)
			}
			fmt.Printf("\n")
		}

		numChanges += len(toAdd)

		if len(toEdit) > 0 {
			fmt.Printf("Records to update:\n")
			for from, to := range toEdit {
				fmt.Printf("%s -> %s\n", from, to)
			}
			fmt.Printf("\n")
		}

		numChanges += len(toEdit)

		if numChanges > 0 {
			fmt.Printf("%d change(s). Continue (y/N)? ", numChanges)

			bio := bufio.NewReader(os.Stdin)
			line, _, _ := bio.ReadLine()

			// If we get anything but y/Y we abort.
			if !(string(line) == "y" || string(line) == "Y") {
				bail("Aborting")
			}
		}
	}

	start := time.Now()
	num := 0

	// Delete DO records not present in the zone.
	for rec := range toDelete {
		fmt.Printf("Deleting %+v\n", rec)
		_, err = client.Domains.DeleteRecord(context.TODO(), string(zoneName), rec.ID)
		bailIfError(err)
		num++
		elapsed(start, num, numChanges)
	}

	// Add zone records missing from DO.
	for _, req := range toAdd {
		fmt.Printf("Adding %+v\n", req)
		_, _, err := client.Domains.CreateRecord(context.TODO(), zoneName.String(""), req)
		bailIfError(err)
		num++
		elapsed(start, num, numChanges)
	}

	// Edit records.
	for from, to := range toEdit {
		fmt.Printf("Updating %+v\n", from)
		_, _, err := client.Domains.EditRecord(context.TODO(), zoneName.String(""), from.ID, to)
		bailIfError(err)
		num++
		elapsed(start, num, numChanges)
	}

	fmt.Printf("Zone synced.\n")
}

func elapsed(start time.Time, num int, numChanges int) {
	elapsed := time.Now().Sub(start)
	average := elapsed / time.Duration(num)
	eta := time.Now().Add(average*time.Duration(numChanges-num))
	fmt.Printf("%d/%d - elapsed: %.1fs - eta: %s\n", num, numChanges, elapsed.Seconds(), eta.Truncate(time.Second).String())
}
<commit_msg>'go fmt' love given<commit_after>package main

import (
	"bufio"
	"context"
	"flag"
	"fmt"
	"log"
	"net/http"
	"net/http/httputil"
	"os"
	"strings"
	"time"

	"github.com/digitalocean/godo"
	"github.com/miekg/dns"
	"golang.org/x/oauth2"

	"github.com/abrander/dozone/proxy"
)

const (
	patEnvName = "DIGITALOCEAN_ACCESS_TOKEN"
)

var (
	pat tokenSource

	client    *godo.Client
	debugHTTP = true
	yes       = true
	download  string
)

func init() {
	pat = tokenSource(os.Getenv(patEnvName))

	if pat == "" {
		bail("Please set the environment variable: %s\n", patEnvName)
	}

	flag.BoolVar(&debugHTTP, "debugHTTP", false, "Output Digital Ocean API requests for debugging")
	flag.BoolVar(&yes, "yes", false, "Don't ask before committing")
	flag.StringVar(&download, "download", "", "Download zone")

	flag.Parse()
}

func getClient() *godo.Client {
	if client != nil {
		return client
	}

	oauthClient := oauth2.NewClient(oauth2.NoContext, pat)
	client = godo.NewClient(oauthClient)

	if debugHTTP {
		client.OnRequestCompleted(func(req *http.Request, resp *http.Response) {
			data, err := httputil.DumpRequestOut(req, true)
			if err == nil {
				fmt.Printf("\033[33m%s\033[0m\n", data)
			} else {
				log.Fatalf("\033[33mERROR: %s\033[0m\n", err.Error())
			}

			data, err = httputil.DumpResponse(resp, true)
			if err == nil {
				fmt.Printf("\033[32m%s\033[0m\n", data)
			} else {
				log.Fatalf("\033[32mERROR: %s\033[0m\n", err.Error())
			}
		})
	}

	return client
}

func bail(format string, args ...interface{}) {
	fmt.Fprintf(os.Stderr, format, args...)
	os.Exit(1)
}

func bailIfError(err error) {
	if err != nil {
		bail("Error: %s\n", err.Error())
	}
}

func main() {
	client := getClient()

	if download != "" {
		dom := proxy.NewDomain(proxy.NewZoneName(download))

		err := dom.Find(client)
		bailIfError(err)

		fmt.Printf("%s", dom.ZoneFile)

		os.Exit(0)
	}

	filename := flag.Arg(0)
	r, err := os.Open(filename)
	bailIfError(err)
	defer r.Close()

	var zoneTokens []*tokenContainer
	var zoneName proxy.ZoneName

	for token := range dns.ParseZone(r, "", "") {
		if token.Error != nil {
			bail("Error: %s\n", token.Error.Error())
		}

		switch token.RR.(type) {
		case *dns.A:
			zoneTokens = append(zoneTokens, &tokenContainer{Token: token})
		case *dns.AAAA:
			zoneTokens = append(zoneTokens, &tokenContainer{Token: token})
		case *dns.CNAME:
			zoneTokens = append(zoneTokens, &tokenContainer{Token: token})
		case *dns.MX:
			zoneTokens = append(zoneTokens, &tokenContainer{Token: token})
		case *dns.NS:
			zoneTokens = append(zoneTokens, &tokenContainer{Token: token})
		case *dns.SOA:
			soa := token.RR.(*dns.SOA)
			trimmed := strings.Trim(soa.Header().Name, ".")
			if trimmed != "" {
				zoneName = proxy.NewZoneName(soa.Header().Name)
			}
		case *dns.SRV:
			zoneTokens = append(zoneTokens, &tokenContainer{Token: token})
		case *dns.TXT:
			zoneTokens = append(zoneTokens, &tokenContainer{Token: token})
		default:
			fmt.Printf("%T is not supported\n", token.RR)
		}
	}

	if zoneName.String("") == "" {
		bail("Could not derive zone name from zone file")
	}

	dom := proxy.NewDomain(zoneName)

	err = dom.FindOrAdd(client)
	bailIfError(err)

	err = dom.RefreshRecords(client)
	bailIfError(err)

	// Match the zone with records retrieved from DO.
	for _, rec := range dom.Records {
		for _, token := range zoneTokens {
			if !token.matched && rec.Matches(token.Token) {
				rec.Matched = true
				token.matched = true
			}
		}
	}

	// Find records to delete.
	toDelete := make(map[godo.DomainRecord]bool)
	for _, rec := range dom.Records {
		if !rec.Matched {
			toDelete[rec.DomainRecord] = true
		}
	}

	// Find records to add.
	toAdd := make(map[*tokenContainer]*godo.DomainRecordEditRequest)
	for _, token := range zoneTokens {
		if !token.matched {
			toAdd[token] = token.CreateRequest()
		}
	}

	// Find records to edit
	toEdit := make(map[godo.DomainRecord]*godo.DomainRecordEditRequest)
	for rec := range toDelete {
		for token := range toAdd {
			req := token.CreateRequest()
			if req.Name == zoneName.FQDN(rec.Name) && req.Type == rec.Type {
				toEdit[rec] = token.CreateRequest()

				// Remove from add/delete maps.
				delete(toAdd, token)
				delete(toDelete, rec)
			}
		}
	}

	numChanges := 0

	if !yes {
		// Present work for the user.
		if len(toDelete) > 0 {
			fmt.Printf("Records to delete:\n")
			for r := range toDelete {
				fmt.Printf("%s\n", r.String())
			}
			fmt.Printf("\n")
		}

		numChanges += len(toDelete)

		if len(toAdd) > 0 {
			fmt.Printf("Records to add:\n")
			for _, r := range toAdd {
				fmt.Printf("%s\n", r)
			}
			fmt.Printf("\n")
		}

		numChanges += len(toAdd)

		if len(toEdit) > 0 {
			fmt.Printf("Records to update:\n")
			for from, to := range toEdit {
				fmt.Printf("%s -> %s\n", from, to)
			}
			fmt.Printf("\n")
		}

		numChanges += len(toEdit)

		if numChanges > 0 {
			fmt.Printf("%d change(s). Continue (y/N)? ", numChanges)

			bio := bufio.NewReader(os.Stdin)
			line, _, _ := bio.ReadLine()

			// If we get anything but y/Y we abort.
			if !(string(line) == "y" || string(line) == "Y") {
				bail("Aborting")
			}
		}
	}

	start := time.Now()
	num := 0

	// Delete DO records not present in the zone.
	for rec := range toDelete {
		fmt.Printf("Deleting %+v\n", rec)
		_, err = client.Domains.DeleteRecord(context.TODO(), string(zoneName), rec.ID)
		bailIfError(err)
		num++
		elapsed(start, num, numChanges)
	}

	// Add zone records missing from DO.
	for _, req := range toAdd {
		fmt.Printf("Adding %+v\n", req)
		_, _, err := client.Domains.CreateRecord(context.TODO(), zoneName.String(""), req)
		bailIfError(err)
		num++
		elapsed(start, num, numChanges)
	}

	// Edit records.
	for from, to := range toEdit {
		fmt.Printf("Updating %+v\n", from)
		_, _, err := client.Domains.EditRecord(context.TODO(), zoneName.String(""), from.ID, to)
		bailIfError(err)
		num++
		elapsed(start, num, numChanges)
	}

	fmt.Printf("Zone synced.\n")
}

func elapsed(start time.Time, num int, numChanges int) {
	elapsed := time.Now().Sub(start)
	average := elapsed / time.Duration(num)
	eta := time.Now().Add(average * time.Duration(numChanges-num))
	fmt.Printf("%d/%d - elapsed: %.1fs - eta: %s\n", num, numChanges, elapsed.Seconds(), eta.Truncate(time.Second).String())
}
<|endoftext|>


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

/*
Party is a tool to automate the use of third party packages.

Many existing Go package managers provide solutions to the problem of relying on
other projects' code. Go handles the use of other packages elegantly, but is
prone to problems when that code has breaking changes or is removed from the
Internet. As a solution, the FAQ suggests copying any third party repositories
into your own project and changing your import paths to match. This is a
recursive process, as you must then perform the same procedure for those copied
packages and so on, until all leaf packages have no external imports.

party is a tool that performs all of this work. It:

1. Rewrites all external imports in both your project and the third party
directory from "other.com/user/package" to
"host.com/user/your_project/_third_party/other.com/user/package".

2. Updates or copies files from "$GOPATH/src/other.com/user/package" to
"$GOPATH/src/host.com/user/your_project/_third_party/other.com/user/package".

3. Returns to step 1 until no more rewrites are performed.

Usage

From your project's root directory, for the first run:

	$ party -c

Subsequent invocations can omit -c.

The flags are:
	-c
		create the third party directory if it does not exist
	-u
		run "go get -d -u <pkg>" on packages imported by party for the
		current package
	-d="_third_party"
		set the third party directory
	-v
		enable verbose output
	-n
		dry run: actions are printed instead of run
	-r
		import third party packages as relative, local imports

App Engine and Relative Imports

When working on an App Engine project, use the -r flag. This will cause all
third party imports to be local packages. This is needed because otherwise App
Engine will run init() routines from your .go files twice if your app is also in
your $GOPATH.

Goven

goven (https://github.com/kr/goven) is a precursor to party, and was useful
enough to get a mention in the FAQ. However, goven has suffered from neglect and
so has some bugs, lacks features, and is not cross-platform. party strives to be
an improvement to goven in all ways.

Bugs

There is no guarantee that the source directory exists. For example, a package
may have a OS-specific file (file_windows.go) which imports another package. On
non-Windows, that other package will not have been fetched during "go get" and
will thus not exist. These packages must be fetched using "go get" or some other
method by hand. Or, running party on a Windows machine (in this case) will
correctly copy those files. These cases are reported when running party.

party performs the equivalent of gofmt on any files affected by the import
rewrite, thus the diff may be somewhat larger than just the import lines.

Third party imports that use local (relative) packages will fail, as those
packages are assumed to be part of the standard library. Those packages will not
be copied.

*/
package main

import (
	"bytes"
	"flag"
	"go/format"
	"go/parser"
	"go/printer"
	"go/token"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"

	"code.google.com/p/go.tools/astutil"
)

const dirMode os.FileMode = 0755

var (
	dryrun     = flag.Bool("n", false, "don't perform any action, instead print them")
	create     = flag.Bool("c", false, "create the third party directory if needed")
	relative   = flag.Bool("r", false, "use a relative third party directory (needed on App Engine)")
	verbose    = flag.Bool("v", false, "print actions")
	thirdParty = flag.String("d", "_third_party", "name of third party directory")
	flagUpdate = flag.Bool("u", false, "update (go get -d -u) used packages")

	relpath, gopath, ThirdParty string
)

func main() {
	flag.Parse()
	if *dryrun {
		*verbose = true
	}

	ThirdParty = filepath.Base(*thirdParty)
	if ThirdParty != *thirdParty {
		log.Fatal("third party directory cannot contain path separators")
	}
	if *create {
		os.Mkdir(ThirdParty, dirMode)
	}
	if _, err := os.Open(ThirdParty); err != nil {
		log.Fatalf("could not open %s directory: run with -c or create it manually", ThirdParty)
	}

	pwd, err := os.Getwd()
	if err != nil {
		log.Fatal(err)
	}
	var importSites []string
	for _, s := range filepath.SplitList(os.Getenv("GOPATH")) {
		s, err := filepath.Abs(s)
		if err != nil {
			log.Fatal(err)
		}
		s, err = filepath.EvalSymlinks(s)
		if err != nil {
			log.Fatal(err)
		}
		if sf, err := os.Open(filepath.Join(s, "src")); err == nil {
			names, err := sf.Readdirnames(0)
			if err == nil {
				for _, name := range names {
					importSites = append(importSites, name)
				}
			}
		}
		if !strings.HasPrefix(pwd, s) {
			continue
		}
		gopath = s
		relpath = strings.TrimPrefix(pwd, filepath.Join(s, "src")+string(os.PathSeparator))
		break
	}
	if relpath == "" {
		log.Fatal("couldn't determine current directory relative to $GOPATH")
	}

	if *verbose {
		log.Println("using GOPATH:", gopath)
		log.Println("using relative path:", relpath)
	}
	for {
		update()
		if !rewriteImports(importSites) {
			break
		}
	}
}

func update() {
	paths := make(map[string]struct{})
	reltp := ThirdParty + "/"
	if !*relative {
		reltp = filepath.ToSlash(relpath) + "/" + reltp
	}
	filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
		if err != nil || info.IsDir() {
			return nil
		}
		fset := token.NewFileSet()
		f, err := parser.ParseFile(fset, path, nil, parser.ParseComments)
		if err != nil {
			return nil
		}
		for _, im := range f.Imports {
			v := im.Path.Value[1 : len(im.Path.Value)-1]
			if !strings.HasPrefix(v, reltp) {
				continue
			}
			paths[strings.TrimPrefix(v, reltp)] = struct{}{}
		}
		return nil
	})
	for k := range paths {
		fpath := filepath.Join(gopath, "src", k)
		f, err := os.Open(fpath)
		if err != nil {
			log.Printf("%s required, but could not be found at %s", k, fpath)
			continue
		}
		if *flagUpdate {
			if *verbose {
				log.Printf("go get -d -u %v", k)
			}
			if !*dryrun {
				out, err := exec.Command("go", "get", "-d", "-u", k).CombinedOutput()
				if len(out) > 0 {
					log.Println(string(out))
				}
				if err != nil {
					log.Println("go get", k, "err:", err)
				}
			}
		}
		files, err := f.Readdir(0)
		if err != nil {
			log.Fatal(err)
		}
		f.Close()
		for _, source := range files {
			if source.IsDir() || strings.HasPrefix(source.Name(), ".") {
				continue
			}
			spath := filepath.Join(f.Name(), source.Name())
			destdir := filepath.Join(ThirdParty, k)
			dest := filepath.Join(destdir, source.Name())
			if err := os.MkdirAll(destdir, dirMode); err != nil {
				log.Fatal(err)
			}
			dst, err := os.Open(dest)
			created := false
			newer := false
			if os.IsNotExist(err) {
				if *verbose {
					log.Println("create", dest)
				}
				created = true
			} else if err != nil {
				log.Fatal(err)
			} else {
				destination, err := dst.Stat()
				if err != nil {
					log.Fatal(err)
				}
				newer = source.ModTime().After(destination.ModTime())
				dst.Close()
			}
			if created || newer {
				if *verbose {
					log.Printf("copy %s -> %s\n", spath, dest)
				}
				if !*dryrun {
					src, err := os.Open(spath)
					if err != nil {
						log.Fatal(err)
					}
					dst, err = os.OpenFile(dest, os.O_RDWR|os.O_CREATE|os.O_TRUNC, source.Mode())
					if err != nil {
						log.Fatal(err)
					}
					if _, err := io.Copy(dst, src); err != nil {
						log.Fatal(err)
					}
					src.Close()
					dst.Close()
				}
			}
		}
	}
}

func rewriteImports(importSites []string) (rewritten bool) {
	filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
		if err != nil || info.IsDir() {
			return nil
		}
		fset := token.NewFileSet()
		f, err := parser.ParseFile(fset, path, nil, parser.ParseComments)
		if err != nil {
			return nil
		}
		for _, im := range f.Imports {
			for _, site := range importSites {
				v, err := strconv.Unquote(im.Path.Value)
				if err != nil {
					log.Fatal(err)
				}
				// don't replace ourself
				if v == relpath || strings.HasPrefix(v, relpath+"/") {
					if *verbose {
						log.Printf("skipping %s because it is in %s\n", v, relpath)
					}
					continue
				}
				if strings.HasPrefix(v, site+"/") {
					target := ThirdParty + "/" + v
					if !*relative {
						target = relpath + "/" + target
					}
					if *verbose {
						log.Printf("rewrite %s: %s -> %s\n", path, v, target)
					}
					if *dryrun {
						break
					}
					if !astutil.RewriteImport(fset, f, v, target) {
						log.Fatalf("%s: could not rewrite %s", path, im.Path.Value)
					}
					rewritten = true
					break
				}
			}
		}
		var buf bytes.Buffer
		if err := printer.Fprint(&buf, fset, f); err != nil {
			log.Fatal(err)
		}
		fb, err := format.Source(buf.Bytes())
		if err != nil {
			log.Fatal(err)
		}
		if err := ioutil.WriteFile(path, fb, info.Mode()); err != nil {
			log.Fatal(err)
		}
		return nil
	})
	return
}
<commit_msg>Don't document goven<commit_after>/*
 * Copyright (c) 2014 Matt Jibson <matt.jibson@gmail.com>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/*
Party is a tool to automate the use of third party packages.

Many existing Go package managers provide solutions to the problem of relying on
other projects' code. Go handles the use of other packages elegantly, but is
prone to problems when that code has breaking changes or is removed from the
Internet. As a solution, the FAQ suggests copying any third party repositories
into your own project and changing your import paths to match. This is a
recursive process, as you must then perform the same procedure for those copied
packages and so on, until all leaf packages have no external imports.

party is a tool that performs all of this work. It:

1. Rewrites all external imports in both your project and the third party
directory from "other.com/user/package" to
"host.com/user/your_project/_third_party/other.com/user/package".

2. Updates or copies files from "$GOPATH/src/other.com/user/package" to
"$GOPATH/src/host.com/user/your_project/_third_party/other.com/user/package".

3. Returns to step 1 until no more rewrites are performed.

Usage

From your project's root directory, for the first run:

	$ party -c

Subsequent invocations can omit -c.

The flags are:
	-c
		create the third party directory if it does not exist
	-u
		run "go get -d -u <pkg>" on packages imported by party for the
		current package
	-d="_third_party"
		set the third party directory
	-v
		enable verbose output
	-n
		dry run: actions are printed instead of run
	-r
		import third party packages as relative, local imports

App Engine and Relative Imports

When working on an App Engine project, use the -r flag. This will cause all
third party imports to be local packages. This is needed because otherwise App
Engine will run init() routines from your .go files twice if your app is also in
your $GOPATH.

Bugs

There is no guarantee that the source directory exists. For example, a package
may have a OS-specific file (file_windows.go) which imports another package. On
non-Windows, that other package will not have been fetched during "go get" and
will thus not exist. These packages must be fetched using "go get" or some other
method by hand. Or, running party on a Windows machine (in this case) will
correctly copy those files. These cases are reported when running party.

party performs the equivalent of gofmt on any files affected by the import
rewrite, thus the diff may be somewhat larger than just the import lines.

Third party imports that use local (relative) packages will fail, as those
packages are assumed to be part of the standard library. Those packages will not
be copied.

*/
package main

import (
	"bytes"
	"flag"
	"go/format"
	"go/parser"
	"go/printer"
	"go/token"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"

	"code.google.com/p/go.tools/astutil"
)

const dirMode os.FileMode = 0755

var (
	dryrun     = flag.Bool("n", false, "don't perform any action, instead print them")
	create     = flag.Bool("c", false, "create the third party directory if needed")
	relative   = flag.Bool("r", false, "use a relative third party directory (needed on App Engine)")
	verbose    = flag.Bool("v", false, "print actions")
	thirdParty = flag.String("d", "_third_party", "name of third party directory")
	flagUpdate = flag.Bool("u", false, "update (go get -d -u) used packages")

	relpath, gopath, ThirdParty string
)

func main() {
	flag.Parse()
	if *dryrun {
		*verbose = true
	}

	ThirdParty = filepath.Base(*thirdParty)
	if ThirdParty != *thirdParty {
		log.Fatal("third party directory cannot contain path separators")
	}
	if *create {
		os.Mkdir(ThirdParty, dirMode)
	}
	if _, err := os.Open(ThirdParty); err != nil {
		log.Fatalf("could not open %s directory: run with -c or create it manually", ThirdParty)
	}

	pwd, err := os.Getwd()
	if err != nil {
		log.Fatal(err)
	}
	var importSites []string
	for _, s := range filepath.SplitList(os.Getenv("GOPATH")) {
		s, err := filepath.Abs(s)
		if err != nil {
			log.Fatal(err)
		}
		s, err = filepath.EvalSymlinks(s)
		if err != nil {
			log.Fatal(err)
		}
		if sf, err := os.Open(filepath.Join(s, "src")); err == nil {
			names, err := sf.Readdirnames(0)
			if err == nil {
				for _, name := range names {
					importSites = append(importSites, name)
				}
			}
		}
		if !strings.HasPrefix(pwd, s) {
			continue
		}
		gopath = s
		relpath = strings.TrimPrefix(pwd, filepath.Join(s, "src")+string(os.PathSeparator))
		break
	}
	if relpath == "" {
		log.Fatal("couldn't determine current directory relative to $GOPATH")
	}

	if *verbose {
		log.Println("using GOPATH:", gopath)
		log.Println("using relative path:", relpath)
	}
	for {
		update()
		if !rewriteImports(importSites) {
			break
		}
	}
}

func update() {
	paths := make(map[string]struct{})
	reltp := ThirdParty + "/"
	if !*relative {
		reltp = filepath.ToSlash(relpath) + "/" + reltp
	}
	filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
		if err != nil || info.IsDir() {
			return nil
		}
		fset := token.NewFileSet()
		f, err := parser.ParseFile(fset, path, nil, parser.ParseComments)
		if err != nil {
			return nil
		}
		for _, im := range f.Imports {
			v := im.Path.Value[1 : len(im.Path.Value)-1]
			if !strings.HasPrefix(v, reltp) {
				continue
			}
			paths[strings.TrimPrefix(v, reltp)] = struct{}{}
		}
		return nil
	})
	for k := range paths {
		fpath := filepath.Join(gopath, "src", k)
		f, err := os.Open(fpath)
		if err != nil {
			log.Printf("%s required, but could not be found at %s", k, fpath)
			continue
		}
		if *flagUpdate {
			if *verbose {
				log.Printf("go get -d -u %v", k)
			}
			if !*dryrun {
				out, err := exec.Command("go", "get", "-d", "-u", k).CombinedOutput()
				if len(out) > 0 {
					log.Println(string(out))
				}
				if err != nil {
					log.Println("go get", k, "err:", err)
				}
			}
		}
		files, err := f.Readdir(0)
		if err != nil {
			log.Fatal(err)
		}
		f.Close()
		for _, source := range files {
			if source.IsDir() || strings.HasPrefix(source.Name(), ".") {
				continue
			}
			spath := filepath.Join(f.Name(), source.Name())
			destdir := filepath.Join(ThirdParty, k)
			dest := filepath.Join(destdir, source.Name())
			if err := os.MkdirAll(destdir, dirMode); err != nil {
				log.Fatal(err)
			}
			dst, err := os.Open(dest)
			created := false
			newer := false
			if os.IsNotExist(err) {
				if *verbose {
					log.Println("create", dest)
				}
				created = true
			} else if err != nil {
				log.Fatal(err)
			} else {
				destination, err := dst.Stat()
				if err != nil {
					log.Fatal(err)
				}
				newer = source.ModTime().After(destination.ModTime())
				dst.Close()
			}
			if created || newer {
				if *verbose {
					log.Printf("copy %s -> %s\n", spath, dest)
				}
				if !*dryrun {
					src, err := os.Open(spath)
					if err != nil {
						log.Fatal(err)
					}
					dst, err = os.OpenFile(dest, os.O_RDWR|os.O_CREATE|os.O_TRUNC, source.Mode())
					if err != nil {
						log.Fatal(err)
					}
					if _, err := io.Copy(dst, src); err != nil {
						log.Fatal(err)
					}
					src.Close()
					dst.Close()
				}
			}
		}
	}
}

func rewriteImports(importSites []string) (rewritten bool) {
	filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
		if err != nil || info.IsDir() {
			return nil
		}
		fset := token.NewFileSet()
		f, err := parser.ParseFile(fset, path, nil, parser.ParseComments)
		if err != nil {
			return nil
		}
		for _, im := range f.Imports {
			for _, site := range importSites {
				v, err := strconv.Unquote(im.Path.Value)
				if err != nil {
					log.Fatal(err)
				}
				// don't replace ourself
				if v == relpath || strings.HasPrefix(v, relpath+"/") {
					if *verbose {
						log.Printf("skipping %s because it is in %s\n", v, relpath)
					}
					continue
				}
				if strings.HasPrefix(v, site+"/") {
					target := ThirdParty + "/" + v
					if !*relative {
						target = relpath + "/" + target
					}
					if *verbose {
						log.Printf("rewrite %s: %s -> %s\n", path, v, target)
					}
					if *dryrun {
						break
					}
					if !astutil.RewriteImport(fset, f, v, target) {
						log.Fatalf("%s: could not rewrite %s", path, im.Path.Value)
					}
					rewritten = true
					break
				}
			}
		}
		var buf bytes.Buffer
		if err := printer.Fprint(&buf, fset, f); err != nil {
			log.Fatal(err)
		}
		fb, err := format.Source(buf.Bytes())
		if err != nil {
			log.Fatal(err)
		}
		if err := ioutil.WriteFile(path, fb, info.Mode()); err != nil {
			log.Fatal(err)
		}
		return nil
	})
	return
}
<|endoftext|>


<commit_before>package main

import (
	"archive/zip"
	"html/template"
	"io"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"
	"unicode"

	"github.com/lxn/walk"
	. "github.com/lxn/walk/declarative"
)

const templ = `
<!DOCTYPE html>

    <meta charset="utf-8">
    <title>Manga Read</title>

      {{ range $key, $value := . }}

      {{ end }}

`

var destino, origen string

func init() {
	// Get variable "temp" windows: storage temporal files
	destino = os.Getenv("temp") + "\\mangaread"
}

func main() {
	// Verify parameter with filename
	if len(os.Args) >= 2 {
		origen = os.Args[1]
	} else {
		log.Println("Ha ocurrido un error interno")
		os.Exit(1)
	}

	// Check and delete files on destination path
	if val, _ := exists(destino); val {
		if err := os.RemoveAll(destino); err != nil {
			log.Println("Ha ocurrido un error interno")
			os.Exit(1)
		}
	}

	// Create directory to save the uncompressed images
	os.MkdirAll(destino, 0777)
	err := Unzip(origen, destino)
	if err != nil {
		log.Println("No se ha podido descomprimir")
		os.Exit(1)
	}
	defer os.RemoveAll(destino)

	// Array storage files name (images uncompressed)
	Images := make([]string, 0)

	//
	filepath.Walk(destino, func(path string, info os.FileInfo, err error) error {
		if !info.IsDir() && IsImage(path) {
			strx, _ := filepath.Rel(destino, path)
			strx = filepath.ToSlash(strx)
			Images = append(Images, strx)
		}
		return err
	})

	t, err := template.New("Mangarad template").Parse(templ)
	if err != nil {
		log.Println("Error al Renderizar Manga")
		os.Exit(1)
	}

	fs := http.FileServer(http.Dir(destino))
	http.Handle("/public/", http.StripPrefix("/public/", fs))
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		t.Execute(w, Images)
	})

	// Ejecutar este proceso en paralelo
	http.ListenAndServe(":3000", nil)
	// --

	//var inTE, outTE *walk.TextEdit
	var fmr *walk.MainWindow
	var wv *walk.WebView
	var msg walk.MsgBox

	width, err := exec.Command("wmic", "desktopmonitor", "get", "screenwidth").Output()
	if err != nil {
		msg()
	}
	height, _ := exec.Command("wmic", "desktopmonitor", "get", "screenheight").Output()

	h, _ := strconv.Atoi(strings.Replace(strings.TrimSpace(stringMinifier(string(height))), "ScreenHeight", "", 1))
	w, _ := strconv.Atoi(strings.Replace(strings.TrimSpace(stringMinifier(string(width))), "ScreenWidth", "", 1))

	MainWindow{
		Title:   "MangaRead",
		MinSize: Size{Width: w - 10, Height: h - 50},
		Layout:  VBox{},
		Children: []Widget{
			WebView{
				AssignTo: &wv,
				Name:     "wv",
				URL:      "http://127.0.0.1:3000", // Ojo esta seccion todavía pertenece a otro proyecto
			},
		},
	}.Run()
}

// @write by: Kim Ilyong (http://intogooglego.blogspot.pe)
func stringMinifier(in string) (out string) {
	white := false
	for _, c := range in {
		if unicode.IsSpace(c) {
			if !white {
				out = out + ""
			}
			white = true
		} else {
			out = out + string(c)
			white = false
		}
	}
	return
}

func IsImage(path string) bool {
	output := false
	switch strings.ToUpper(filepath.Ext(path)) {
	case ".JPG", ".JPEG", ".PNG":
		output = true
	}
	return output
}

func exists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return true, err
}

func Unzip(src, dest string) error {
	r, err := zip.OpenReader(src)
	if err != nil {
		return err
	}
	defer func() {
		if err := r.Close(); err != nil {
			panic(err)
		}
	}()

	os.MkdirAll(dest, 0755)

	// Closure to address file descriptors issue with all the deferred .Close() methods
	extractAndWriteFile := func(f *zip.File) error {
		rc, err := f.Open()
		if err != nil {
			return err
		}
		defer func() {
			if err := rc.Close(); err != nil {
				panic(err)
			}
		}()

		path := filepath.Join(dest, f.Name)

		if f.FileInfo().IsDir() {
			os.MkdirAll(path, f.Mode())
		} else {
			f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
			if err != nil {
				return err
			}
			defer func() {
				if err := f.Close(); err != nil {
					panic(err)
				}
			}()

			_, err = io.Copy(f, rc)
			if err != nil {
				return err
			}
		}
		return nil
	}

	for _, f := range r.File {
		err := extractAndWriteFile(f)
		if err != nil {
			return err
		}
	}

	return nil
}
<commit_msg>otros cambios<commit_after>// Write by: Joel Tinx
package main

import (
	"archive/zip"
	"html/template"
	"io"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"
	"unicode"

	"github.com/lxn/walk"
	. "github.com/lxn/walk/declarative"
)

const templ = `
<!DOCTYPE html>

    <meta charset="utf-8">
    <title>Manga Read</title>

      {{ range $key, $value := . }}

      {{ end }}

`

var destino, origen string

func init() {
	// Get variable "temp" windows: storage temporal files
	destino = os.Getenv("temp") + "\\mangaread"
}

func main() {
	// Verify parameter with filename
	if len(os.Args) >= 2 {
		origen = os.Args[1]
	} else {
		log.Println("Ha ocurrido un error interno")
		os.Exit(1)
	}

	// Check and delete files on destination path
	if val, _ := exists(destino); val {
		if err := os.RemoveAll(destino); err != nil {
			log.Println("Ha ocurrido un error interno")
			os.Exit(1)
		}
	}

	// Create directory to save the uncompressed images
	os.MkdirAll(destino, 0777)
	err := Unzip(origen, destino)
	if err != nil {
		log.Println("No se ha podido descomprimir")
		os.Exit(1)
	}
	defer os.RemoveAll(destino)

	// Array storage files name (images uncompressed)
	Images := make([]string, 0)

	//
	filepath.Walk(destino, func(path string, info os.FileInfo, err error) error {
		if !info.IsDir() && IsImage(path) {
			strx, _ := filepath.Rel(destino, path)
			strx = filepath.ToSlash(strx)
			Images = append(Images, strx)
		}
		return err
	})

	t, err := template.New("Mangarad template").Parse(templ)
	if err != nil {
		log.Println("Error al Renderizar Manga")
		os.Exit(1)
	}

	fs := http.FileServer(http.Dir(destino))
	http.Handle("/public/", http.StripPrefix("/public/", fs))
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		t.Execute(w, Images)
	})

	// Ejecutar este proceso en paralelo
	http.ListenAndServe(":3000", nil)
	// --

	//var inTE, outTE *walk.TextEdit
	var fmr *walk.MainWindow
	var wv *walk.WebView
	var msg walk.MsgBox

	width, err := exec.Command("wmic", "desktopmonitor", "get", "screenwidth").Output()
	if err != nil {
		msg()
	}
	height, _ := exec.Command("wmic", "desktopmonitor", "get", "screenheight").Output()

	h, _ := strconv.Atoi(strings.Replace(strings.TrimSpace(stringMinifier(string(height))), "ScreenHeight", "", 1))
	w, _ := strconv.Atoi(strings.Replace(strings.TrimSpace(stringMinifier(string(width))), "ScreenWidth", "", 1))

	MainWindow{
		Title:   "MangaRead",
		MinSize: Size{Width: w - 10, Height: h - 50},
		Layout:  VBox{},
		Children: []Widget{
			WebView{
				AssignTo: &wv,
				Name:     "wv",
				URL:      "http://127.0.0.1:3000", // Ojo esta seccion todavía pertenece a otro proyecto
			},
		},
	}.Run()
}

// @write by: Kim Ilyong (http://intogooglego.blogspot.pe)
func stringMinifier(in string) (out string) {
	white := false
	for _, c := range in {
		if unicode.IsSpace(c) {
			if !white {
				out = out + ""
			}
			white = true
		} else {
			out = out + string(c)
			white = false
		}
	}
	return
}

func IsImage(path string) bool {
	output := false
	switch strings.ToUpper(filepath.Ext(path)) {
	case ".JPG", ".JPEG", ".PNG":
		output = true
	}
	return output
}

func exists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return true, err
}

func Unzip(src, dest string) error {
	r, err := zip.OpenReader(src)
	if err != nil {
		return err
	}
	defer func() {
		if err := r.Close(); err != nil {
			panic(err)
		}
	}()

	os.MkdirAll(dest, 0755)

	// Closure to address file descriptors issue with all the deferred .Close() methods
	extractAndWriteFile := func(f *zip.File) error {
		rc, err := f.Open()
		if err != nil {
			return err
		}
		defer func() {
			if err := rc.Close(); err != nil {
				panic(err)
			}
		}()

		path := filepath.Join(dest, f.Name)

		if f.FileInfo().IsDir() {
			os.MkdirAll(path, f.Mode())
		} else {
			f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
			if err != nil {
				return err
			}
			defer func() {
				if err := f.Close(); err != nil {
					panic(err)
				}
			}()

			_, err = io.Copy(f, rc)
			if err != nil {
				return err
			}
		}
		return nil
	}

	for _, f := range r.File {
		err := extractAndWriteFile(f)
		if err != nil {
			return err
		}
	}

	return nil
}
<|endoftext|>