<commit_before>package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"sync"
)

var files = map[string]string{
	"ChromeStandaloneSetup.exe": "https://dl.google.com/tag/s/appguid%3D%7B8A69D345-D564-463C-AFF1-A69D9E530F96%7D%26iid%3D%7BAF3A54A1-01DD-6358-922D-9F48BABA316B%7D%26lang%3Den%26browser%3D2%26usagestats%3D0%26appname%3DGoogle%2520Chrome%26needsadmin%3Dfalse%26installdataindex%3Ddefaultbrowser/update2/installers/ChromeStandaloneSetup.exe",
	"Mercurial.exe":             "http://mercurial.selenic.com/release/windows/Mercurial-2.3.1.exe",
	"mingw-inst.exe":            "http://superb-dca3.dl.sourceforge.net/project/mingw/Installer/mingw-get-inst/mingw-get-inst-20120426/mingw-get-inst-20120426.exe",
}

var altMain func()

var flagYes = flag.Bool("yes", false, "Run without prompt")

func main() {
	if runtime.GOOS != "windows" {
		altMain()
		return
	}
	flag.Parse()
	if !*flagYes {
		log.Printf("This program will install Go, Mingw, Mercurial, Chrome, etc. Type 'go<enter>' to proceed.")
		if !awaitString("go") {
			log.Printf("Canceled.")
			awaitEnter()
			return
		}
	}

	log.Printf("Downloading files.")
	var wg sync.WaitGroup
	for file, url := range files {
		wg.Add(1)
		go download(file, url, &wg)
	}
	wg.Wait()

	checkMingw()
	checkoutGo()

	runGoMakeBat("386")
	runGoMakeBat("amd64")

	// TODO(bradfitz): run make.bat, build the builder, ming64
	// overlay, etc

	fmt.Println("[ Press enter to exit ]")
	awaitEnter()
}

const (
	mingwBin   = `C:\MingW\bin`
	mingw64Bin = `C:\MingW64\bin`
)

func runGoMakeBat(arch string) {
	if arch != "386" && arch != "amd64" {
		panic("invalid arch " + arch)
	}

	testFile := filepath.Join(goroot(), "pkg", "tool", "windows_"+arch, "api.exe")
	if fileExists(testFile) {
		log.Printf("Skipping make.bat for windows_%s; already built.", arch)
		return
	}

	log.Printf("Running make.bat for arch %s ...", arch)
	cmd := exec.Command(filepath.Join(goroot(), "src", "make.bat"))
	cmd.Dir = filepath.Join(goroot(), "src")
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	gccPath := mingwBin
	if arch == "amd64" {
		gccPath = mingw64Bin
		if err := initMingw64Bin(); err != nil {
			log.Fatalf("failed to init C:\\mingw64\\bin directory: %v", err)
		}
	}

	cmd.Env = append([]string{
		"GOARCH=" + arch,
		"PATH=" + gccPath + ";" + os.Getenv("PATH"),
	}, removeEnvs(os.Environ(), "PATH")...)

	err := cmd.Run()
	if err != nil {
		log.Fatalf("make.bat for arch %s: %v", arch, err)
	}
	log.Printf("ran make.bat for arch %s", arch)
}

func initMingw64Bin() error {
	dstGcc := filepath.Join(mingw64Bin, "gcc.exe")
	dstAr := filepath.Join(mingw64Bin, "ar.exe")
	srcGcc := filepath.Join(mingwBin, "x86_64-w64-mingw32-gcc.exe")
	srcAr := filepath.Join(mingwBin, "x86_64-w64-mingw32-ar.exe")
	if fileExists(dstGcc) && fileExists(dstAr) {
		return nil
	}
	if err := os.MkdirAll(mingw64Bin, 0755); err != nil {
		return err
	}
	if !fileExists(dstGcc) {
		if err := cp(srcGcc, dstGcc); err != nil {
			return err
		}
	}
	if !fileExists(dstAr) {
		if err := cp(srcAr, dstAr); err != nil {
			return err
		}
	}
	return nil
}

func cp(src, dst string) (err error) {
	defer func() {
		if err != nil {
			err = fmt.Errorf("copying from %s to %s: %v", src, dst, err)
		}
	}()
	f, err := os.Open(src)
	if err != nil {
		return
	}
	defer f.Close()
	os.Remove(dst)
	f2, err := os.Create(dst)
	if err != nil {
		return
	}
	_, err = io.Copy(f2, f)
	if err != nil {
		return
	}
	err = f2.Close()
	return
}

func removeEnvs(envs []string, removeKeys ...string) []string {
	var ret []string
	for _, env := range envs {
		include := true
		for _, remove := range removeKeys {
			if strings.HasPrefix(env, remove+"=") {
				include = false
				break
			}
		}
		if include {
			ret = append(ret, env)
		}
	}
	return ret
}

func checkMingw() {
	for !fileExists(mingwBin) {
		log.Printf("%s doesn't exist. Install mingw and then press enter...")
		awaitEnter()
	}
}

func checkoutGo() {
	if fileExists(goroot()) {
		log.Printf("GOROOT %s already exists; skipping hg checkout", goroot())
		return
	}
	log.Printf("Checking out Go source using Mercurial (hg)")
	cmd := exec.Command("hg", "clone", "https://code.google.com/p/go", "goroot")
	cmd.Dir = home()
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	err := cmd.Run()
	if err != nil {
		log.Fatalf("hg clone failed. Is Mercurial installed? Re-run later. Error: %v", err)
	}
	log.Printf("Checked out Go.")
}

func awaitEnter() {
	var buf [1]byte
	os.Stdin.Read(buf[:])
}

func awaitString(want string) bool {
	br := bufio.NewReader(os.Stdin)
	ln, _, _ := br.ReadLine()
	return strings.TrimSpace(string(ln)) == want
}

func fileExists(path string) bool {
	_, err := os.Stat(path)
	return err == nil
}

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

func home() string { return os.Getenv("HOMEPATH") }

func goroot() string { return filepath.Join(home(), "goroot") }

func download(file, url string, wg *sync.WaitGroup) {
	defer wg.Done()

	dst := filepath.Join(home(), "Desktop", file)
	if _, err := os.Stat(dst); err == nil {
		log.Printf("%s already on desktop; skipping", file)
		return
	}

	res, err := http.Get(url)
	if err != nil {
		log.Fatalf("Error fetching %v: %v", url, err)
	}
	tmp := dst + ".tmp"
	os.Remove(tmp)
	os.Remove(dst)
	f, err := os.Create(tmp)
	if err != nil {
		log.Fatal(err)
	}
	n, err := io.Copy(f, res.Body)
	res.Body.Close()
	if err != nil {
		log.Fatalf("Error reading %v: %v", url, err)
	}
	f.Close()
	err = os.Rename(tmp, dst)
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("Downladed %s (%d bytes) to desktop", file, n)
}
<commit_msg>switch to tdc-gcc-64, update download locations<commit_after>package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"sync"
)

var files = map[string]string{
	"ChromeStandaloneSetup.exe": "https://dl.google.com/tag/s/appguid%3D%7B8A69D345-D564-463C-AFF1-A69D9E530F96%7D%26iid%3D%7BC159FD9F-6827-8E7E-0CC8-7783A1335AA5%7D%26lang%3Den%26browser%3D4%26usagestats%3D0%26appname%3DGoogle%2520Chrome%26needsadmin%3Dprefers%26installdataindex%3Ddefaultbrowser/update2/installers/ChromeStandaloneSetup.exe",
	"Mercurial.exe":             "http://mercurial.selenic.com/release/windows/Mercurial-3.1-x64.exe",
	"tdm64-gcc-4.8.1-3.exe":     "http://downloads.sourceforge.net/project/tdm-gcc/TDM-GCC%20Installer/tdm64-gcc-4.8.1-3.exe?r=http%3A%2F%2Ftdm-gcc.tdragon.net%2Fdownload&ts=1407729829&use_mirror=ufpr",
}

var altMain func()

var flagYes = flag.Bool("yes", false, "Run without prompt")

func main() {
	if runtime.GOOS != "windows" {
		altMain()
		return
	}
	flag.Parse()
	if !*flagYes {
		log.Printf("This program will install Go, Mingw, Mercurial, Chrome, etc. Type 'go<enter>' to proceed.")
		if !awaitString("go") {
			log.Printf("Canceled.")
			awaitEnter()
			return
		}
	}

	log.Printf("Downloading files.")
	var wg sync.WaitGroup
	for file, url := range files {
		wg.Add(1)
		go download(file, url, &wg)
	}
	wg.Wait()

	checkGcc()
	checkoutGo()

	runGoMakeBat("386")
	runGoMakeBat("amd64")

	log.Printf(`Installed go to %v, please add %v\bin to your PATH`, goroot(), goroot())

	fmt.Println("[ Press enter to exit ]")
	awaitEnter()
}

const gccPath = `C:\TDM-GCC-64\bin`

func runGoMakeBat(arch string) {
	if arch != "386" && arch != "amd64" {
		panic("invalid arch " + arch)
	}

	testFile := filepath.Join(goroot(), "pkg", "tool", "windows_"+arch, "api.exe")
	if fileExists(testFile) {
		log.Printf("Skipping make.bat for windows_%s; already built.", arch)
		return
	}

	log.Printf("Running make.bat for arch %s ...", arch)
	cmd := exec.Command(filepath.Join(goroot(), "src", "make.bat"))
	cmd.Dir = filepath.Join(goroot(), "src")
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	cmd.Env = append([]string{
		"GOARCH=" + arch,
		"PATH=" + gccPath + ";" + os.Getenv("PATH"),
	}, removeEnvs(os.Environ(), "PATH")...)

	err := cmd.Run()
	if err != nil {
		log.Fatalf("make.bat for arch %s: %v", arch, err)
	}
	log.Printf("ran make.bat for arch %s", arch)
}

func removeEnvs(envs []string, removeKeys ...string) []string {
	var ret []string
	for _, env := range envs {
		include := true
		for _, remove := range removeKeys {
			if strings.HasPrefix(env, remove+"=") {
				include = false
				break
			}
		}
		if include {
			ret = append(ret, env)
		}
	}
	return ret
}

func checkGcc() {
	for !fileExists(gccPath) {
		log.Printf("%s doesn't exist. Install gcc and then press enter...", gccPath)
		awaitEnter()
	}
}

const hgDefaultPath = `C:\Program Files\Mercurial\hg.exe`

func checkoutGo() {
	if fileExists(goroot()) {
		log.Printf("GOROOT %s already exists; skipping hg checkout", goroot())
		return
	}
	log.Printf("Checking out Go source using Mercurial (hg)")

	hgBin, err := exec.LookPath("hg")
	if err != nil {
		hgBin = hgDefaultPath
		log.Printf("Couldn't find hg binary in PATH, trying %v", hgBin)
	}
	cmd := exec.Command(hgBin, "clone", "https://code.google.com/p/go", "goroot")
	cmd.Dir = home()
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	if err := cmd.Run(); err != nil {
		log.Fatalf("hg clone failed. Is Mercurial installed? Re-run later. Error: %v", err)
	}
	log.Printf("Checked out Go.")
}

func awaitEnter() {
	var buf [1]byte
	os.Stdin.Read(buf[:])
}

func awaitString(want string) bool {
	br := bufio.NewReader(os.Stdin)
	ln, _, _ := br.ReadLine()
	return strings.TrimSpace(string(ln)) == want
}

func fileExists(path string) bool {
	_, err := os.Stat(path)
	return err == nil
}

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

func home() string { return os.Getenv("HOMEPATH") }

func goroot() string { return filepath.Join(home(), "goroot") }

func download(file, url string, wg *sync.WaitGroup) {
	defer wg.Done()

	dst := filepath.Join(home(), "Desktop", file)
	if _, err := os.Stat(dst); err == nil {
		log.Printf("%s already on desktop; skipping", file)
		return
	}

	res, err := http.Get(url)
	if err != nil {
		log.Fatalf("Error fetching %v: %v", url, err)
	}
	tmp := dst + ".tmp"
	os.Remove(tmp)
	os.Remove(dst)
	f, err := os.Create(tmp)
	if err != nil {
		log.Fatal(err)
	}
	n, err := io.Copy(f, res.Body)
	res.Body.Close()
	if err != nil {
		log.Fatalf("Error reading %v: %v", url, err)
	}
	f.Close()
	err = os.Rename(tmp, dst)
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("Downladed %s (%d bytes) to desktop", file, n)
}
<|endoftext|>


<commit_before>package killable

import (
	"errors"
	"time"
)

var (
	ErrDying      = errors.New("killable: dying")
	ErrKill       = errors.New("killable: killed")
	ErrKillLocal  = errors.New("killable: local killed")
	ErrStillAlive = errors.New("killable: still alive")
)

type Killable interface {
	// Dying is closed immediatly after Kill is called
	Dying() <-chan struct{}

	// Dead is closed after all executing functions have returned
	// These executing functions must have been started with Do or Go
	Dead() <-chan struct{}

	// Put the Killable into the dying state
	Kill(reason error)

	// Return the error passed to Kill
	// blocks until in dying state
	Err() error

	// add a function to run when dead
	addDefer(func())

	// faster state access
	isDead() bool
	isDying() bool

	// access to underlying WaitGroup
	add()
	done()
	wait()
}

func New(killables ...Killable) Killable {
	if len(killables) == 0 {
		return newSingle()
	} else {
		return newGroup(killables...)
	}
}

// Sleep blocks for a specified duration
// If the Killable is marked as dying it will return
// immediatly with ErrDying
func Sleep(k Killable, d time.Duration) error {
	select {
	case <-time.After(d):
		return nil
	case <-k.Dying():
		return ErrDying
	}
}

// Do executes a function and retuns its error value.
// * If the Killable is marked as dying it will return immediatly with ErrDying.
// * The Killable will not be marked as dead until all calls to Do have returned.
func Do(k Killable, fn func() error) error {
	if IsDying(k) {
		return ErrDying
	}
	k.add()
	ch := make(chan error)
	go func() {
		defer k.done()
		select {
		case ch <- fn():
		case <-k.Dying():
		}
	}()
	select {
	case err := <-ch:
		return err
	case <-k.Dying():
		return ErrDying
	}
}

// Go executes a function in a goroutine
// * If the function returns a non-nil error the Killable is killed using that error
// * The Killable will no be marked as dead until all calls to Go have returned
func Go(k Killable, fn func() error) {
	if IsDying(k) {
		return
	}
	k.add()
	go func() {
		defer k.done()
		if err := fn(); err != nil && err != ErrDying {
			k.Kill(err)
		}
	}()
}

// Defer invokes a callback once a Killable is dead.
// deferred functions will execute in the opposite order they were defined in
// if the Killable is already dead, the deferred will be called immediatly
func Defer(k Killable, fn func()) { k.addDefer(fn) }

// IsDying returns true if a Killable is in the dying or dead state
func IsDying(k Killable) bool { return k.isDying() }

// IsDead true if the Killable is in the dead state
func IsDead(k Killable) bool { return k.isDead() }

// IsAlive returns true if the Killable isn't in the dead or dying states
func IsAlive(k Killable) bool { return !IsDying(k) }

// Err returns the Killable error
// If the Killable is alive, it returns ErrStillAlive
func Err(k Killable) error {
	if IsDead(k) {
		return k.Err()
	} else {
		return ErrStillAlive
	}
}
<commit_msg>add more docs<commit_after>package killable

import (
	"errors"
	"time"
)

var (
	// ErrDying is returned when some action was cancelled due
	// to the Dying channel closing
	ErrDying = errors.New("killable: dying")

	// ErrKill is returned from managed goroutines to
	// put the Killable into the dying state
	ErrKill = errors.New("killable: killed")

	// ErrKillLocal is returned from managed goroutines to
	// put the killable into the dying state but without
	// propagating it to parent Killables
	ErrKillLocal = errors.New("killable: local killed")

	// ErrStillAlive is returned by Err if the Killable isn't dying
	ErrStillAlive = errors.New("killable: still alive")
)

type Killable interface {
	// Dying is closed immediatly after Kill is called
	Dying() <-chan struct{}

	// Dead is closed after all executing functions have returned
	// These executing functions must have been started with Do or Go
	Dead() <-chan struct{}

	// Put the Killable into the dying state
	Kill(reason error)

	// Return the error passed to Kill
	// blocks until in dying state
	Err() error

	// add a function to run when dead
	addDefer(func())

	// faster state access
	isDead() bool
	isDying() bool

	// access to underlying WaitGroup
	add()
	done()
	wait()
}

// New creates a new Killable
func New(killables ...Killable) Killable {
	if len(killables) == 0 {
		return newSingle()
	} else {
		return newGroup(killables...)
	}
}

// Sleep blocks for a specified duration
// If the Killable is marked as dying it will return
// immediatly with ErrDying
func Sleep(k Killable, d time.Duration) error {
	select {
	case <-time.After(d):
		return nil
	case <-k.Dying():
		return ErrDying
	}
}

// Do executes a function and retuns its error value.
// * If the Killable is marked as dying it will return immediatly with ErrDying.
// * The Killable will not be marked as dead until all calls to Do have returned.
func Do(k Killable, fn func() error) error {
	if IsDying(k) {
		return ErrDying
	}
	k.add()
	ch := make(chan error)
	go func() {
		defer k.done()
		select {
		case ch <- fn():
		case <-k.Dying():
		}
	}()
	select {
	case err := <-ch:
		return err
	case <-k.Dying():
		return ErrDying
	}
}

// Go executes a function in a goroutine
// * If the function returns a non-nil error the Killable is killed using that error
// * The Killable will no be marked as dead until all calls to Go have returned
func Go(k Killable, fn func() error) {
	if IsDying(k) {
		return
	}
	k.add()
	go func() {
		defer k.done()
		if err := fn(); err != nil && err != ErrDying {
			k.Kill(err)
		}
	}()
}

// Defer invokes a callback once a Killable is dead.
// deferred functions will execute in the opposite order they were defined in
// if the Killable is already dead, the deferred will be called immediatly
func Defer(k Killable, fn func()) { k.addDefer(fn) }

// IsDying returns true if a Killable is in the dying or dead state
func IsDying(k Killable) bool { return k.isDying() }

// IsDead true if the Killable is in the dead state
func IsDead(k Killable) bool { return k.isDead() }

// IsAlive returns true if the Killable isn't in the dead or dying states
func IsAlive(k Killable) bool { return !IsDying(k) }

// Err returns the Killable error
// If the Killable is alive, it returns ErrStillAlive
func Err(k Killable) error {
	if IsDead(k) {
		return k.Err()
	} else {
		return ErrStillAlive
	}
}
<|endoftext|>


<commit_before>package docker

import (
	"crypto/tls"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/containers/image/types"
	"github.com/docker/docker/pkg/homedir"
)

const (
	dockerHostname     = "docker.io"
	dockerRegistry     = "registry-1.docker.io"
	dockerAuthRegistry = "https://index.docker.io/v1/"

	dockerCfg         = ".docker"
	dockerCfgFileName = "config.json"
	dockerCfgObsolete = ".dockercfg"

	baseURL       = "%s://%s/v2/"
	tagsURL       = "%s/tags/list"
	manifestURL   = "%s/manifests/%s"
	blobsURL      = "%s/blobs/%s"
	blobUploadURL = "%s/blobs/uploads/"
)

// dockerClient is configuration for dealing with a single Docker registry.
type dockerClient struct {
	ctx             *types.SystemContext
	registry        string
	username        string
	password        string
	wwwAuthenticate string // Cache of a value set by ping() if scheme is not empty
	scheme          string // Cache of a value returned by a successful ping() if not empty
	client          *http.Client
	signatureBase   signatureStorageBase
}

// newDockerClient returns a new dockerClient instance for refHostname (a host a specified in the Docker image reference, not canonicalized to dockerRegistry)
// “write” specifies whether the client will be used for "write" access (in particular passed to lookaside.go:toplevelFromSection)
func newDockerClient(ctx *types.SystemContext, ref dockerReference, write bool) (*dockerClient, error) {
	registry := ref.ref.Hostname()
	if registry == dockerHostname {
		registry = dockerRegistry
	}
	username, password, err := getAuth(ref.ref.Hostname())
	if err != nil {
		return nil, err
	}
	var tr *http.Transport
	if ctx != nil && (ctx.DockerCertPath != "" || ctx.DockerInsecureSkipTLSVerify) {
		tlsc := &tls.Config{}

		if ctx.DockerCertPath != "" {
			cert, err := tls.LoadX509KeyPair(filepath.Join(ctx.DockerCertPath, "cert.pem"), filepath.Join(ctx.DockerCertPath, "key.pem"))
			if err != nil {
				return nil, fmt.Errorf("Error loading x509 key pair: %s", err)
			}
			tlsc.Certificates = append(tlsc.Certificates, cert)
		}
		tlsc.InsecureSkipVerify = ctx.DockerInsecureSkipTLSVerify
		tr = &http.Transport{
			TLSClientConfig: tlsc,
		}
	}
	client := &http.Client{
		Timeout: 1 * time.Minute,
	}
	if tr != nil {
		client.Transport = tr
	}

	sigBase, err := configuredSignatureStorageBase(ctx, ref, write)
	if err != nil {
		return nil, err
	}

	return &dockerClient{
		ctx:           ctx,
		registry:      registry,
		username:      username,
		password:      password,
		client:        client,
		signatureBase: sigBase,
	}, nil
}

// makeRequest creates and executes a http.Request with the specified parameters, adding authentication and TLS options for the Docker client.
// url is NOT an absolute URL, but a path relative to the /v2/ top-level API path.  The host name and schema is taken from the client or autodetected.
func (c *dockerClient) makeRequest(method, url string, headers map[string][]string, stream io.Reader) (*http.Response, error) {
	if c.scheme == "" {
		pr, err := c.ping()
		if err != nil {
			return nil, err
		}
		c.wwwAuthenticate = pr.WWWAuthenticate
		c.scheme = pr.scheme
	}

	url = fmt.Sprintf(baseURL, c.scheme, c.registry) + url
	return c.makeRequestToResolvedURL(method, url, headers, stream, -1)
}

// makeRequestToResolvedURL creates and executes a http.Request with the specified parameters, adding authentication and TLS options for the Docker client.
// streamLen, if not -1, specifies the length of the data expected on stream.
// makeRequest should generally be preferred.
func (c *dockerClient) makeRequestToResolvedURL(method, url string, headers map[string][]string, stream io.Reader, streamLen int64) (*http.Response, error) {
	req, err := http.NewRequest(method, url, stream)
	if err != nil {
		return nil, err
	}
	if streamLen != -1 { // Do not blindly overwrite if streamLen == -1, http.NewRequest above can figure out the length of bytes.Reader and similar objects without us having to compute it.
		req.ContentLength = streamLen
	}
	req.Header.Set("Docker-Distribution-API-Version", "registry/2.0")
	for n, h := range headers {
		for _, hh := range h {
			req.Header.Add(n, hh)
		}
	}
	if c.wwwAuthenticate != "" {
		if err := c.setupRequestAuth(req); err != nil {
			return nil, err
		}
	}
	logrus.Debugf("%s %s", method, url)
	res, err := c.client.Do(req)
	if err != nil {
		return nil, err
	}
	return res, nil
}

func (c *dockerClient) setupRequestAuth(req *http.Request) error {
	tokens := strings.SplitN(strings.TrimSpace(c.wwwAuthenticate), " ", 2)
	if len(tokens) != 2 {
		return fmt.Errorf("expected 2 tokens in WWW-Authenticate: %d, %s", len(tokens), c.wwwAuthenticate)
	}
	switch tokens[0] {
	case "Basic":
		req.SetBasicAuth(c.username, c.password)
		return nil
	case "Bearer":
		// FIXME? This gets a new token for every API request;
		// we may be easily able to reuse a previous token, e.g.
		// for OpenShift the token only identifies the user and does not vary
		// across operations.  Should we just try the request first, and
		// only get a new token on failure?
		// OTOH what to do with the single-use body stream in that case?

		// Try performing the request, expecting it to fail.
		testReq := *req
		// Do not use the body stream, or we couldn't reuse it for the "real" call later.
		testReq.Body = nil
		testReq.ContentLength = 0
		res, err := c.client.Do(&testReq)
		if err != nil {
			return err
		}
		chs := parseAuthHeader(res.Header)
		if res.StatusCode != http.StatusUnauthorized || chs == nil || len(chs) == 0 {
			// no need for bearer? wtf?
			return nil
		}
		// Arbitrarily use the first challenge, there is no reason to expect more than one.
		challenge := chs[0]
		if challenge.Scheme != "bearer" { // Another artifact of trying to handle WWW-Authenticate before it actually happens.
			return fmt.Errorf("Unimplemented: WWW-Authenticate Bearer replaced by %#v", challenge.Scheme)
		}
		realm, ok := challenge.Parameters["realm"]
		if !ok {
			return fmt.Errorf("missing realm in bearer auth challenge")
		}
		service, _ := challenge.Parameters["service"] // Will be "" if not present
		scope, _ := challenge.Parameters["scope"]     // Will be "" if not present
		token, err := c.getBearerToken(realm, service, scope)
		if err != nil {
			return err
		}
		req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token))
		return nil
	}
	return fmt.Errorf("no handler for %s authentication", tokens[0])
	// support docker bearer with authconfig's Auth string? see docker2aci
}

func (c *dockerClient) getBearerToken(realm, service, scope string) (string, error) {
	authReq, err := http.NewRequest("GET", realm, nil)
	if err != nil {
		return "", err
	}
	getParams := authReq.URL.Query()
	if service != "" {
		getParams.Add("service", service)
	}
	if scope != "" {
		getParams.Add("scope", scope)
	}
	authReq.URL.RawQuery = getParams.Encode()
	if c.username != "" && c.password != "" {
		authReq.SetBasicAuth(c.username, c.password)
	}
	// insecure for now to contact the external token service
	tr := &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}
	client := &http.Client{Transport: tr}
	res, err := client.Do(authReq)
	if err != nil {
		return "", err
	}
	defer res.Body.Close()
	switch res.StatusCode {
	case http.StatusUnauthorized:
		return "", fmt.Errorf("unable to retrieve auth token: 401 unauthorized")
	case http.StatusOK:
		break
	default:
		return "", fmt.Errorf("unexpected http code: %d, URL: %s", res.StatusCode, authReq.URL)
	}
	tokenBlob, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return "", err
	}
	tokenStruct := struct {
		Token string `json:"token"`
	}{}
	if err := json.Unmarshal(tokenBlob, &tokenStruct); err != nil {
		return "", err
	}
	// TODO(runcom): reuse tokens?
	//hostAuthTokens, ok = rb.hostsV2AuthTokens[req.URL.Host]
	//if !ok {
	//hostAuthTokens = make(map[string]string)
	//rb.hostsV2AuthTokens[req.URL.Host] = hostAuthTokens
	//}
	//hostAuthTokens[repo] = tokenStruct.Token
	return tokenStruct.Token, nil
}

func getAuth(hostname string) (string, string, error) {
	// TODO(runcom): get this from *cli.Context somehow
	//if username != "" && password != "" {
	//return username, password, nil
	//}
	if hostname == dockerHostname {
		hostname = dockerAuthRegistry
	}
	dockerCfgPath := filepath.Join(getDefaultConfigDir(".docker"), dockerCfgFileName)
	if _, err := os.Stat(dockerCfgPath); err == nil {
		j, err := ioutil.ReadFile(dockerCfgPath)
		if err != nil {
			return "", "", err
		}
		var dockerAuth dockerConfigFile
		if err := json.Unmarshal(j, &dockerAuth); err != nil {
			return "", "", err
		}
		// try the normal case
		if c, ok := dockerAuth.AuthConfigs[hostname]; ok {
			return decodeDockerAuth(c.Auth)
		}
	} else if os.IsNotExist(err) {
		oldDockerCfgPath := filepath.Join(getDefaultConfigDir(dockerCfgObsolete))
		if _, err := os.Stat(oldDockerCfgPath); err != nil {
			return "", "", nil //missing file is not an error
		}
		j, err := ioutil.ReadFile(oldDockerCfgPath)
		if err != nil {
			return "", "", err
		}
		var dockerAuthOld map[string]dockerAuthConfigObsolete
		if err := json.Unmarshal(j, &dockerAuthOld); err != nil {
			return "", "", err
		}
		if c, ok := dockerAuthOld[hostname]; ok {
			return decodeDockerAuth(c.Auth)
		}
	} else {
		// if file is there but we can't stat it for any reason other
		// than it doesn't exist then stop
		return "", "", fmt.Errorf("%s - %v", dockerCfgPath, err)
	}
	return "", "", nil
}

type apiErr struct {
	Code    string
	Message string
	Detail  interface{}
}

type pingResponse struct {
	WWWAuthenticate string
	APIVersion      string
	scheme          string
	errors          []apiErr
}

func (c *dockerClient) ping() (*pingResponse, error) {
	ping := func(scheme string) (*pingResponse, error) {
		url := fmt.Sprintf(baseURL, scheme, c.registry)
		resp, err := c.client.Get(url)
		logrus.Debugf("Ping %s err %#v", url, err)
		if err != nil {
			return nil, err
		}
		defer resp.Body.Close()
		logrus.Debugf("Ping %s status %d", scheme+"://"+c.registry+"/v2/", resp.StatusCode)
		if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusUnauthorized {
			return nil, fmt.Errorf("error pinging repository, response code %d", resp.StatusCode)
		}
		pr := &pingResponse{}
		pr.WWWAuthenticate = resp.Header.Get("WWW-Authenticate")
		pr.APIVersion = resp.Header.Get("Docker-Distribution-Api-Version")
		pr.scheme = scheme
		if resp.StatusCode == http.StatusUnauthorized {
			type APIErrors struct {
				Errors []apiErr
			}
			errs := &APIErrors{}
			if err := json.NewDecoder(resp.Body).Decode(errs); err != nil {
				return nil, err
			}
			pr.errors = errs.Errors
		}
		return pr, nil
	}
	pr, err := ping("https")
	if err != nil && c.ctx.DockerInsecureSkipTLSVerify {
		pr, err = ping("http")
	}
	return pr, err
}

func getDefaultConfigDir(confPath string) string {
	return filepath.Join(homedir.Get(), confPath)
}

type dockerAuthConfigObsolete struct {
	Auth string `json:"auth"`
}

type dockerAuthConfig struct {
	Auth string `json:"auth,omitempty"`
}

type dockerConfigFile struct {
	AuthConfigs map[string]dockerAuthConfig `json:"auths"`
}

func decodeDockerAuth(s string) (string, string, error) {
	decoded, err := base64.StdEncoding.DecodeString(s)
	if err != nil {
		return "", "", err
	}
	parts := strings.SplitN(string(decoded), ":", 2)
	if len(parts) != 2 {
		// if it's invalid just skip, as docker does
		return "", "", nil
	}
	user := parts[0]
	password := strings.Trim(parts[1], "\x00")
	return user, password, nil
}
<commit_msg>docker: remove client's timeout<commit_after>package docker

import (
	"crypto/tls"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"strings"

	"github.com/Sirupsen/logrus"
	"github.com/containers/image/types"
	"github.com/docker/docker/pkg/homedir"
)

const (
	dockerHostname     = "docker.io"
	dockerRegistry     = "registry-1.docker.io"
	dockerAuthRegistry = "https://index.docker.io/v1/"

	dockerCfg         = ".docker"
	dockerCfgFileName = "config.json"
	dockerCfgObsolete = ".dockercfg"

	baseURL       = "%s://%s/v2/"
	tagsURL       = "%s/tags/list"
	manifestURL   = "%s/manifests/%s"
	blobsURL      = "%s/blobs/%s"
	blobUploadURL = "%s/blobs/uploads/"
)

// dockerClient is configuration for dealing with a single Docker registry.
type dockerClient struct {
	ctx             *types.SystemContext
	registry        string
	username        string
	password        string
	wwwAuthenticate string // Cache of a value set by ping() if scheme is not empty
	scheme          string // Cache of a value returned by a successful ping() if not empty
	client          *http.Client
	signatureBase   signatureStorageBase
}

// newDockerClient returns a new dockerClient instance for refHostname (a host a specified in the Docker image reference, not canonicalized to dockerRegistry)
// “write” specifies whether the client will be used for "write" access (in particular passed to lookaside.go:toplevelFromSection)
func newDockerClient(ctx *types.SystemContext, ref dockerReference, write bool) (*dockerClient, error) {
	registry := ref.ref.Hostname()
	if registry == dockerHostname {
		registry = dockerRegistry
	}
	username, password, err := getAuth(ref.ref.Hostname())
	if err != nil {
		return nil, err
	}
	var tr *http.Transport
	if ctx != nil && (ctx.DockerCertPath != "" || ctx.DockerInsecureSkipTLSVerify) {
		tlsc := &tls.Config{}

		if ctx.DockerCertPath != "" {
			cert, err := tls.LoadX509KeyPair(filepath.Join(ctx.DockerCertPath, "cert.pem"), filepath.Join(ctx.DockerCertPath, "key.pem"))
			if err != nil {
				return nil, fmt.Errorf("Error loading x509 key pair: %s", err)
			}
			tlsc.Certificates = append(tlsc.Certificates, cert)
		}
		tlsc.InsecureSkipVerify = ctx.DockerInsecureSkipTLSVerify
		tr = &http.Transport{
			TLSClientConfig: tlsc,
		}
	}
	client := &http.Client{}
	if tr != nil {
		client.Transport = tr
	}

	sigBase, err := configuredSignatureStorageBase(ctx, ref, write)
	if err != nil {
		return nil, err
	}

	return &dockerClient{
		ctx:           ctx,
		registry:      registry,
		username:      username,
		password:      password,
		client:        client,
		signatureBase: sigBase,
	}, nil
}

// makeRequest creates and executes a http.Request with the specified parameters, adding authentication and TLS options for the Docker client.
// url is NOT an absolute URL, but a path relative to the /v2/ top-level API path.  The host name and schema is taken from the client or autodetected.
func (c *dockerClient) makeRequest(method, url string, headers map[string][]string, stream io.Reader) (*http.Response, error) {
	if c.scheme == "" {
		pr, err := c.ping()
		if err != nil {
			return nil, err
		}
		c.wwwAuthenticate = pr.WWWAuthenticate
		c.scheme = pr.scheme
	}

	url = fmt.Sprintf(baseURL, c.scheme, c.registry) + url
	return c.makeRequestToResolvedURL(method, url, headers, stream, -1)
}

// makeRequestToResolvedURL creates and executes a http.Request with the specified parameters, adding authentication and TLS options for the Docker client.
// streamLen, if not -1, specifies the length of the data expected on stream.
// makeRequest should generally be preferred.
func (c *dockerClient) makeRequestToResolvedURL(method, url string, headers map[string][]string, stream io.Reader, streamLen int64) (*http.Response, error) {
	req, err := http.NewRequest(method, url, stream)
	if err != nil {
		return nil, err
	}
	if streamLen != -1 { // Do not blindly overwrite if streamLen == -1, http.NewRequest above can figure out the length of bytes.Reader and similar objects without us having to compute it.
		req.ContentLength = streamLen
	}
	req.Header.Set("Docker-Distribution-API-Version", "registry/2.0")
	for n, h := range headers {
		for _, hh := range h {
			req.Header.Add(n, hh)
		}
	}
	if c.wwwAuthenticate != "" {
		if err := c.setupRequestAuth(req); err != nil {
			return nil, err
		}
	}
	logrus.Debugf("%s %s", method, url)
	res, err := c.client.Do(req)
	if err != nil {
		return nil, err
	}
	return res, nil
}

func (c *dockerClient) setupRequestAuth(req *http.Request) error {
	tokens := strings.SplitN(strings.TrimSpace(c.wwwAuthenticate), " ", 2)
	if len(tokens) != 2 {
		return fmt.Errorf("expected 2 tokens in WWW-Authenticate: %d, %s", len(tokens), c.wwwAuthenticate)
	}
	switch tokens[0] {
	case "Basic":
		req.SetBasicAuth(c.username, c.password)
		return nil
	case "Bearer":
		// FIXME? This gets a new token for every API request;
		// we may be easily able to reuse a previous token, e.g.
		// for OpenShift the token only identifies the user and does not vary
		// across operations.  Should we just try the request first, and
		// only get a new token on failure?
		// OTOH what to do with the single-use body stream in that case?

		// Try performing the request, expecting it to fail.
		testReq := *req
		// Do not use the body stream, or we couldn't reuse it for the "real" call later.
		testReq.Body = nil
		testReq.ContentLength = 0
		res, err := c.client.Do(&testReq)
		if err != nil {
			return err
		}
		chs := parseAuthHeader(res.Header)
		if res.StatusCode != http.StatusUnauthorized || chs == nil || len(chs) == 0 {
			// no need for bearer? wtf?
			return nil
		}
		// Arbitrarily use the first challenge, there is no reason to expect more than one.
		challenge := chs[0]
		if challenge.Scheme != "bearer" { // Another artifact of trying to handle WWW-Authenticate before it actually happens.
			return fmt.Errorf("Unimplemented: WWW-Authenticate Bearer replaced by %#v", challenge.Scheme)
		}
		realm, ok := challenge.Parameters["realm"]
		if !ok {
			return fmt.Errorf("missing realm in bearer auth challenge")
		}
		service, _ := challenge.Parameters["service"] // Will be "" if not present
		scope, _ := challenge.Parameters["scope"]     // Will be "" if not present
		token, err := c.getBearerToken(realm, service, scope)
		if err != nil {
			return err
		}
		req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token))
		return nil
	}
	return fmt.Errorf("no handler for %s authentication", tokens[0])
	// support docker bearer with authconfig's Auth string? see docker2aci
}

func (c *dockerClient) getBearerToken(realm, service, scope string) (string, error) {
	authReq, err := http.NewRequest("GET", realm, nil)
	if err != nil {
		return "", err
	}
	getParams := authReq.URL.Query()
	if service != "" {
		getParams.Add("service", service)
	}
	if scope != "" {
		getParams.Add("scope", scope)
	}
	authReq.URL.RawQuery = getParams.Encode()
	if c.username != "" && c.password != "" {
		authReq.SetBasicAuth(c.username, c.password)
	}
	// insecure for now to contact the external token service
	tr := &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}
	client := &http.Client{Transport: tr}
	res, err := client.Do(authReq)
	if err != nil {
		return "", err
	}
	defer res.Body.Close()
	switch res.StatusCode {
	case http.StatusUnauthorized:
		return "", fmt.Errorf("unable to retrieve auth token: 401 unauthorized")
	case http.StatusOK:
		break
	default:
		return "", fmt.Errorf("unexpected http code: %d, URL: %s", res.StatusCode, authReq.URL)
	}
	tokenBlob, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return "", err
	}
	tokenStruct := struct {
		Token string `json:"token"`
	}{}
	if err := json.Unmarshal(tokenBlob, &tokenStruct); err != nil {
		return "", err
	}
	// TODO(runcom): reuse tokens?
	//hostAuthTokens, ok = rb.hostsV2AuthTokens[req.URL.Host]
	//if !ok {
	//hostAuthTokens = make(map[string]string)
	//rb.hostsV2AuthTokens[req.URL.Host] = hostAuthTokens
	//}
	//hostAuthTokens[repo] = tokenStruct.Token
	return tokenStruct.Token, nil
}

func getAuth(hostname string) (string, string, error) {
	// TODO(runcom): get this from *cli.Context somehow
	//if username != "" && password != "" {
	//return username, password, nil
	//}
	if hostname == dockerHostname {
		hostname = dockerAuthRegistry
	}
	dockerCfgPath := filepath.Join(getDefaultConfigDir(".docker"), dockerCfgFileName)
	if _, err := os.Stat(dockerCfgPath); err == nil {
		j, err := ioutil.ReadFile(dockerCfgPath)
		if err != nil {
			return "", "", err
		}
		var dockerAuth dockerConfigFile
		if err := json.Unmarshal(j, &dockerAuth); err != nil {
			return "", "", err
		}
		// try the normal case
		if c, ok := dockerAuth.AuthConfigs[hostname]; ok {
			return decodeDockerAuth(c.Auth)
		}
	} else if os.IsNotExist(err) {
		oldDockerCfgPath := filepath.Join(getDefaultConfigDir(dockerCfgObsolete))
		if _, err := os.Stat(oldDockerCfgPath); err != nil {
			return "", "", nil //missing file is not an error
		}
		j, err := ioutil.ReadFile(oldDockerCfgPath)
		if err != nil {
			return "", "", err
		}
		var dockerAuthOld map[string]dockerAuthConfigObsolete
		if err := json.Unmarshal(j, &dockerAuthOld); err != nil {
			return "", "", err
		}
		if c, ok := dockerAuthOld[hostname]; ok {
			return decodeDockerAuth(c.Auth)
		}
	} else {
		// if file is there but we can't stat it for any reason other
		// than it doesn't exist then stop
		return "", "", fmt.Errorf("%s - %v", dockerCfgPath, err)
	}
	return "", "", nil
}

type apiErr struct {
	Code    string
	Message string
	Detail  interface{}
}

type pingResponse struct {
	WWWAuthenticate string
	APIVersion      string
	scheme          string
	errors          []apiErr
}

func (c *dockerClient) ping() (*pingResponse, error) {
	ping := func(scheme string) (*pingResponse, error) {
		url := fmt.Sprintf(baseURL, scheme, c.registry)
		resp, err := c.client.Get(url)
		logrus.Debugf("Ping %s err %#v", url, err)
		if err != nil {
			return nil, err
		}
		defer resp.Body.Close()
		logrus.Debugf("Ping %s status %d", scheme+"://"+c.registry+"/v2/", resp.StatusCode)
		if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusUnauthorized {
			return nil, fmt.Errorf("error pinging repository, response code %d", resp.StatusCode)
		}
		pr := &pingResponse{}
		pr.WWWAuthenticate = resp.Header.Get("WWW-Authenticate")
		pr.APIVersion = resp.Header.Get("Docker-Distribution-Api-Version")
		pr.scheme = scheme
		if resp.StatusCode == http.StatusUnauthorized {
			type APIErrors struct {
				Errors []apiErr
			}
			errs := &APIErrors{}
			if err := json.NewDecoder(resp.Body).Decode(errs); err != nil {
				return nil, err
			}
			pr.errors = errs.Errors
		}
		return pr, nil
	}
	pr, err := ping("https")
	if err != nil && c.ctx.DockerInsecureSkipTLSVerify {
		pr, err = ping("http")
	}
	return pr, err
}

func getDefaultConfigDir(confPath string) string {
	return filepath.Join(homedir.Get(), confPath)
}

type dockerAuthConfigObsolete struct {
	Auth string `json:"auth"`
}

type dockerAuthConfig struct {
	Auth string `json:"auth,omitempty"`
}

type dockerConfigFile struct {
	AuthConfigs map[string]dockerAuthConfig `json:"auths"`
}

func decodeDockerAuth(s string) (string, string, error) {
	decoded, err := base64.StdEncoding.DecodeString(s)
	if err != nil {
		return "", "", err
	}
	parts := strings.SplitN(string(decoded), ":", 2)
	if len(parts) != 2 {
		// if it's invalid just skip, as docker does
		return "", "", nil
	}
	user := parts[0]
	password := strings.Trim(parts[1], "\x00")
	return user, password, nil
}
<|endoftext|>


<commit_before>package api

import (
	"encoding/json"
	"io/ioutil"
	"net/http"

	"github.com/wiliamsouza/apollo/customer"
)

type requestUser struct {
	Name     string
	Email    string
	Password string
}

type responseUser struct {
	Name  string `json:"name"`
	Email string `json:"email"`
}

func NewUser(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	b, err := ioutil.ReadAll(r.Body)
	if err != nil {
		http.Error(w, "Error parssing request body: "+err.Error(), http.StatusInternalServerError)
		return
	}
	var u requestUser
	err = json.Unmarshal(b, &u)
	if err != nil {
		http.Error(w, "Error parssing json request: "+err.Error(), http.StatusBadRequest)
		return
	}
	newUser, err := customer.NewUser(u.Name, u.Email, u.Password)
	if err != nil {
		http.Error(w, "Error creating new user: "+err.Error(), http.StatusBadRequest)
		return
	}
	user := responseUser{Name: newUser.Name, Email: newUser.Email}
	result, err := json.Marshal(user)
	if err != nil {
		http.Error(w, "Error generating json result: "+err.Error(), http.StatusInternalServerError)
		return
	}
	w.WriteHeader(http.StatusCreated)
	w.Write(result)
}
<commit_msg>Changed api/user to pass golint<commit_after>package api

import (
	"encoding/json"
	"io/ioutil"
	"net/http"

	"github.com/wiliamsouza/apollo/customer"
)

type requestUser struct {
	Name     string
	Email    string
	Password string
}

type responseUser struct {
	Name  string `json:"name"`
	Email string `json:"email"`
}

// NewUser create new user
func NewUser(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	b, err := ioutil.ReadAll(r.Body)
	if err != nil {
		http.Error(w, "Error parssing request body: "+err.Error(), http.StatusInternalServerError)
		return
	}
	var u requestUser
	err = json.Unmarshal(b, &u)
	if err != nil {
		http.Error(w, "Error parssing json request: "+err.Error(), http.StatusBadRequest)
		return
	}
	newUser, err := customer.NewUser(u.Name, u.Email, u.Password)
	if err != nil {
		http.Error(w, "Error creating new user: "+err.Error(), http.StatusBadRequest)
		return
	}
	user := responseUser{Name: newUser.Name, Email: newUser.Email}
	result, err := json.Marshal(user)
	if err != nil {
		http.Error(w, "Error generating json result: "+err.Error(), http.StatusInternalServerError)
		return
	}
	w.WriteHeader(http.StatusCreated)
	w.Write(result)
}
<|endoftext|>


<commit_before>package main

import (
	"io"
	"io/ioutil"
	"os"
	"testing"

	"github.com/fsouza/go-dockerclient"
	"github.com/stretchr/testify/assert"
)

type TestDockerClient struct {
	containers []docker.APIContainers
	images     []docker.APIImages
}

func (rdc *TestDockerClient) ListContainers() ([]docker.APIContainers, error) {
	return rdc.containers, nil
}

func (rdc *TestDockerClient) ListImages() ([]docker.APIImages, error) {
	return rdc.images, nil
}

func (rdc *TestDockerClient) PullImage(fullImage string, output io.Writer) error {
	return nil
}

func (rdc *TestDockerClient) AddContainer(container docker.APIContainers) error {
	rdc.containers = append(rdc.containers, container)
	return nil
}

func NewTestDockerClient() (*TestDockerClient, error) {

	dockerClient := TestDockerClient{}

	return &dockerClient, nil
}

func TestEnvironments(t *testing.T) {
	assert := assert.New(t)

	tempdir, _ := ioutil.TempDir("", "ddc")
	defer os.RemoveAll(tempdir)

	sc, _ := NewSystemClientWithBase(tempdir)

	dc, _ := NewTestDockerClient()
	dc.AddContainer(
		docker.APIContainers{
			ID:     "foo",
			Names:  []string{"/ddc_foo"},
			Image:  "nate/clojuredev:latest",
			Status: "Up 12 hours",
			Ports: []docker.APIPort{
				{32768, 22, "tcp", "0.0.0.0"},
			},
		},
	)
	key, _ := sc.EnsureSSHKey()
	sc.EnsureEnvironmentDir("foo", key)

	envs, err := Environments(dc, sc)
	assert.Nil(err)
	assert.Equal(
		envs,
		map[string]Environment{
			"foo": Environment{
				"foo",
				&Container{
					"ddc_foo",
					"nate/clojuredev:latest",
					true,
					[]Port{{"0.0.0.0", 22, 32768, "tcp"}},
				},
				"clojure",
			},
		},
	)
}
<commit_msg>add a couple tests<commit_after>package main

import (
	"bytes"
	"io"
	"io/ioutil"
	"os"
	"testing"

	"github.com/fsouza/go-dockerclient"
	"github.com/stretchr/testify/assert"
)

type TestDockerClient struct {
	containers []docker.APIContainers
	images     []docker.APIImages
}

func (rdc *TestDockerClient) ListContainers() ([]docker.APIContainers, error) {
	return rdc.containers, nil
}

func (rdc *TestDockerClient) ListImages() ([]docker.APIImages, error) {
	return rdc.images, nil
}

func (rdc *TestDockerClient) PullImage(fullImage string, output io.Writer) error {
	return nil
}

func (rdc *TestDockerClient) BuildImage(name string, dockerfile string, output io.Writer) error {
	return nil
}
func (rdc *TestDockerClient) CreateContainer(cco CreateContainerOpts) error {
	return nil
}
func (rdc *TestDockerClient) StartContainer(name string) error {
	return nil
}

func (rdc *TestDockerClient) AddContainer(container docker.APIContainers) error {
	rdc.containers = append(rdc.containers, container)
	return nil
}

func (rdc *TestDockerClient) AddImage(image docker.APIImages) error {
	rdc.images = append(rdc.images, image)
	return nil
}

func NewTestDockerClient() (*TestDockerClient, error) {

	dockerClient := TestDockerClient{}

	return &dockerClient, nil
}

func TestEnvironments(t *testing.T) {
	assert := assert.New(t)

	tempdir, _ := ioutil.TempDir("", "ddc")
	defer os.RemoveAll(tempdir)

	sc, _ := NewSystemClientWithBase(tempdir)

	dc, _ := NewTestDockerClient()
	dc.AddContainer(
		docker.APIContainers{
			ID:     "foo",
			Names:  []string{"/ddc_foo"},
			Image:  "nate/clojuredev:latest",
			Status: "Up 12 hours",
			Ports: []docker.APIPort{
				{32768, 22, "tcp", "0.0.0.0"},
			},
		},
	)
	key, _ := sc.EnsureSSHKey()
	sc.EnsureEnvironmentDir("foo", key)

	envs, err := Environments(dc, sc)
	assert.Nil(err)
	assert.Equal(
		envs,
		map[string]Environment{
			"foo": Environment{
				"foo",
				&Container{
					"ddc_foo",
					"nate/clojuredev:latest",
					true,
					[]Port{{"0.0.0.0", 22, 32768, "tcp"}},
				},
				"clojure",
			},
		},
	)
}

func TestBaseImages(t *testing.T) {
	assert := assert.New(t)

	dc, _ := NewTestDockerClient()
	dc.AddImage(
		docker.APIImages{
			RepoTags: []string{
				"dockdev/go:1.6",
			},
		},
	)
	dc.AddImage(
		docker.APIImages{
			RepoTags: []string{
				"dockdev/python:3.4",
			},
		},
	)

	baseImages, err := BaseImages(dc)
	assert.Nil(err)

	assert.Equal(
		baseImages,
		[]*BaseImage{
			{
				"go",
				"Golang Image",
				[]*BaseImageTag{
					{"1.5", false, false},
					{"1.6", true, true},
				},
			},
			{
				"clojure",
				"Clojure image",
				[]*BaseImageTag{
					{"java7", false, true},
				},
			},
			{
				"python",
				"Python base image",
				[]*BaseImageTag{
					{"both", false, true},
					{"2.7", false, false},
					{"3.4", true, false},
				},
			},
		},
	)
}

func TestEnsureImage(t *testing.T) {
	assert := assert.New(t)

	dc, _ := NewTestDockerClient()
	dc.AddImage(
		docker.APIImages{
			RepoTags: []string{
				"dockdev/python:3.4",
			},
		},
	)

	err := EnsureImage(dc, "testimage", bytes.NewBuffer(nil))
	assert.Nil(err)
}
<|endoftext|>


<commit_before>package b2

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"net/url"
	"strings"
	"testing"
)

// TODO replace with parseCreateB2Response test
func Test_CreateB2_Errors(t *testing.T) {
	codes, bodies := errorResponses()
	for i := range codes {
		s, c := setupRequest(codes[i], bodies[i])

		client := &client{Protocol: "http", Client: c}
		b, err := createB2("1", "1", client)
		testErrorResponse(err, codes[i], t)
		if b != nil {
			t.Errorf("Expected b to be empty, instead got %+v", b)
		}

		s.Close()
	}
}

func Test_createB2_HasAuth(t *testing.T) {
	reqChan := make(chan *http.Request, 1)
	s, c := setupMockJsonServer(200, "", reqChan)
	defer s.Close()

	client := &client{Protocol: "http", Client: c}

	createB2("1", "1", client)

	// get the request that the mock server received
	req := <-reqChan

	username, password, ok := req.BasicAuth()
	if !ok {
		t.Fatal("Expected ok to be true, instead got false")
	}
	if username != "1" {
		t.Errorf(`Expected username to be "1", instead got %s`, username)
	}
	if password != "1" {
		t.Errorf(`Expected password to be "1", instead got %s`, password)
	}
}

func Test_parseCreateB2Response(t *testing.T) {
	resp := &http.Response{
		StatusCode: 200,
		Body:       ioutil.NopCloser(strings.NewReader(`{"accountId":"1","authorizationToken":"1","apiUrl":"/","downloadUrl":"/"}`))}

	b := &B2{AccountID: "1", ApplicationKey: "key"}
	b, err := b.parseCreateB2Response(resp)
	if err != nil {
		t.Fatalf("Expected err to be nil, instead got %+v", err)
	}

	if b.AccountID != "1" {
		t.Errorf(`Expected AccountID to be "1", instead got %s`, b.AccountID)
	}
	if b.AuthorizationToken != "1" {
		t.Errorf(`Expected AuthorizationToken to be "1", instead got %s`, b.AuthorizationToken)
	}
	if b.ApiUrl != "/" {
		t.Errorf(`Expected ApiUrl to be "/", instead got %s`, b.ApiUrl)
	}
	if b.DownloadUrl != "/" {
		t.Errorf(`Expected DownloadUrl to be "/", instead got %s`, b.DownloadUrl)
	}
}

func Test_B2_CreateRequest(t *testing.T) {
	b2 := &B2{client: &client{Protocol: "https"}} // set client protocol to default

	methods := []string{
		"GET", "POST", "KITTENS",
		"POST", "BAD METHOD",
	}
	urls := []string{
		"http://example.com", "kittens://example.com", "aoeu://example.com",
		"invalid-url", "http://example.com",
	}
	reqBody := struct {
		a int `json:"a"`
	}{a: 1}

	for i := 0; i < 3; i++ {
		req, err := b2.CreateRequest(methods[i], urls[i], reqBody)
		if err != nil {
			t.Fatalf("Expected err to be nil, instead got %+v", err)
		}
		if req.URL.Scheme != "https" {
			t.Errorf(`Expected url protocol to be "https", instead got %s`, req.URL.Scheme)
		}
		if req.Body == nil {
			t.Error("Expected req.Body to not be nil")
		}
	}
	for i := 3; i < 5; i++ {
		req, err := b2.CreateRequest(methods[i], urls[i], reqBody)
		if req != nil {
			t.Errorf("Expected req to be nil, instead got %+v", req)
		}
		if err == nil {
			t.Fatal("Expected err to exist")
		}
	}
}

func Test_replaceProtocol(t *testing.T) {
	b2s := []B2{
		B2{client: &client{Protocol: "https"}},
		B2{client: &client{Protocol: "http"}},
		B2{client: &client{Protocol: "kittens"}},
	}
	urls := []string{
		"http://localhost", "https://localhost", "http://localhost", "kittens://localhost",
		"https://www.backblaze.com/", "https://www.backblaze.com/",
		"http://www.backblaze.com/", "kittens://www.backblaze.com/",
		"non/url/",
	}

	for i, b := range b2s {
		index, i2, index2 := i+1, i+4, i+5 // make offsets
		// localhost
		url, err := b.replaceProtocol(urls[i])
		if err != nil {
			t.Errorf("Expected no error, instead got %+v", err)
		}
		if url != urls[index] {
			t.Errorf("Expected url to be %s, instead got %s", urls[index], url)
		}

		// www.backblaze.com
		url, err = b.replaceProtocol(urls[i2])
		if err != nil {
			t.Errorf("Expected no error, instead got %+v", err)
		}
		if url != urls[index2] {
			t.Errorf("Expected url to be %s, instead got %s", urls[index2], url)
		}
	}

	url, err := b2s[0].replaceProtocol(urls[len(urls)-1])
	if err == nil {
		t.Errorf("Expected error, instead got nil, url returned was %s", url)
	}
}

func Test_GetBzInfoHeaders(t *testing.T) {
	headers := map[string][]string{
		"Content-Type":      []string{"kittens"},
		"X-Bz-Info-kittens": []string{"yes"},
		"X-Bz-Info-thing":   []string{"one"},
	}
	resp := &http.Response{Header: headers}

	bzHeaders := GetBzInfoHeaders(resp)

	if len(bzHeaders) != 2 {
		t.Fatalf("Expected length of headers to be 2, instead got %d", len(bzHeaders))
	}
	if h, ok := bzHeaders["Content-Type"]; ok {
		t.Errorf("Expected no Content-Type, instead recieved %s", h)
	}
	if h := bzHeaders["kittens"]; h != "yes" {
		t.Errorf(`Expected kittens to be "yes", instead got %s`, h)
	}
	if h := bzHeaders["thing"]; h != "one" {
		t.Errorf(`Expected thing to be "one", instead got %s`, h)
	}
}

// TODO remove
func setupRequest(code int, body string) (*httptest.Server, http.Client) {
	return setupMockJsonServer(code, body, nil)
}

// TODO remove
func setupMockJsonServer(code int, body string, reqChan chan<- *http.Request) (*httptest.Server, http.Client) {
	headers := map[string]string{"Content-Type": "application/json"}
	return setupMockServer(code, body, headers, reqChan)
}

// TODO remove
func setupMockServer(code int, body string, headers map[string]string, reqChan chan<- *http.Request) (*httptest.Server, http.Client) {
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if reqChan != nil {
			reqChan <- r
		}

		for k, v := range headers {
			w.Header().Set(k, v)
		}

		w.WriteHeader(code)
		fmt.Fprintln(w, body)
	}))

	tr := &http.Transport{
		Proxy: func(req *http.Request) (*url.URL, error) {
			return url.Parse(server.URL)
		},
	}

	return server, http.Client{Transport: tr}
}

func createTestResponse(statusCode int, body string) *http.Response {
	return &http.Response{
		StatusCode: statusCode,
		Body:       ioutil.NopCloser(strings.NewReader(body))}
}

func createTestErrorResponses() []*http.Response {
	return []*http.Response{
		createTestResponse(400, `{"status":400,"code":"nope","message":"nope nope"}`),
		createTestResponse(401, `{"status":401,"code":"nope","message":"nope nope"}`),
	}
}

// TODO replace with non-200 *http.Response creator
func errorResponses() ([]int, []string) {
	codes := []int{400, 401}
	bodies := []string{
		`{"status":400,"code":"nope","message":"nope nope"}`,
		`{"status":401,"code":"nope","message":"nope nope"}`,
	}
	return codes, bodies
}

func testErrorResponse(err error, code int, t *testing.T) {
	if err == nil {
		t.Error("Expected error, no error received")
	} else if err.Error() != fmt.Sprintf("Status: %d, Code: nope, Message: nope nope", code) {
		t.Errorf(`Expected "Status: %d, Code: nope, Message: nope nope", instead got %s`, code, err)
	}
}

func makeTestB2(c http.Client) *B2 {
	return &B2{
		AccountID:          "id",
		AuthorizationToken: "token",
		ApiUrl:             "https://api900.backblaze.com",
		DownloadUrl:        "https://f900.backblaze.com",
		client:             &client{Protocol: "http", Client: c},
	}
}
<commit_msg>Combine tests for parseCreateB2Response<commit_after>package b2

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"net/url"
	"strings"
	"testing"
)

func Test_createB2_HasAuth(t *testing.T) {
	reqChan := make(chan *http.Request, 1)
	s, c := setupMockJsonServer(200, "", reqChan)
	defer s.Close()

	client := &client{Protocol: "http", Client: c}

	createB2("1", "1", client)

	// get the request that the mock server received
	req := <-reqChan

	username, password, ok := req.BasicAuth()
	if !ok {
		t.Fatal("Expected ok to be true, instead got false")
	}
	if username != "1" {
		t.Errorf(`Expected username to be "1", instead got %s`, username)
	}
	if password != "1" {
		t.Errorf(`Expected password to be "1", instead got %s`, password)
	}
}

func Test_parseCreateB2Response(t *testing.T) {
	// success
	resp := createTestResponse(200, `{"accountId":"1","authorizationToken":"1","apiUrl":"/","downloadUrl":"/"}`)

	b := &B2{AccountID: "1", ApplicationKey: "key"}
	b, err := b.parseCreateB2Response(resp)
	if err != nil {
		t.Fatalf("Expected err to be nil, instead got %+v", err)
	}

	if b.AccountID != "1" {
		t.Errorf(`Expected AccountID to be "1", instead got %s`, b.AccountID)
	}
	if b.AuthorizationToken != "1" {
		t.Errorf(`Expected AuthorizationToken to be "1", instead got %s`, b.AuthorizationToken)
	}
	if b.ApiUrl != "/" {
		t.Errorf(`Expected ApiUrl to be "/", instead got %s`, b.ApiUrl)
	}
	if b.DownloadUrl != "/" {
		t.Errorf(`Expected DownloadUrl to be "/", instead got %s`, b.DownloadUrl)
	}

	// errors
	resps := createTestErrorResponses()
	for i, resp := range resps {
		b := &B2{AccountID: "1", ApplicationKey: "key"}
		b, err := b.parseCreateB2Response(resp)
		testErrorResponse(err, 400+i, t)
		if b != nil {
			t.Errorf("Expected b to be nil, instead got %+v", b)
		}
	}
}

func Test_B2_CreateRequest(t *testing.T) {
	b2 := &B2{client: &client{Protocol: "https"}} // set client protocol to default

	methods := []string{
		"GET", "POST", "KITTENS",
		"POST", "BAD METHOD",
	}
	urls := []string{
		"http://example.com", "kittens://example.com", "aoeu://example.com",
		"invalid-url", "http://example.com",
	}
	reqBody := struct {
		a int `json:"a"`
	}{a: 1}

	for i := 0; i < 3; i++ {
		req, err := b2.CreateRequest(methods[i], urls[i], reqBody)
		if err != nil {
			t.Fatalf("Expected err to be nil, instead got %+v", err)
		}
		if req.URL.Scheme != "https" {
			t.Errorf(`Expected url protocol to be "https", instead got %s`, req.URL.Scheme)
		}
		if req.Body == nil {
			t.Error("Expected req.Body to not be nil")
		}
	}
	for i := 3; i < 5; i++ {
		req, err := b2.CreateRequest(methods[i], urls[i], reqBody)
		if req != nil {
			t.Errorf("Expected req to be nil, instead got %+v", req)
		}
		if err == nil {
			t.Fatal("Expected err to exist")
		}
	}
}

func Test_replaceProtocol(t *testing.T) {
	b2s := []B2{
		B2{client: &client{Protocol: "https"}},
		B2{client: &client{Protocol: "http"}},
		B2{client: &client{Protocol: "kittens"}},
	}
	urls := []string{
		"http://localhost", "https://localhost", "http://localhost", "kittens://localhost",
		"https://www.backblaze.com/", "https://www.backblaze.com/",
		"http://www.backblaze.com/", "kittens://www.backblaze.com/",
		"non/url/",
	}

	for i, b := range b2s {
		index, i2, index2 := i+1, i+4, i+5 // make offsets
		// localhost
		url, err := b.replaceProtocol(urls[i])
		if err != nil {
			t.Errorf("Expected no error, instead got %+v", err)
		}
		if url != urls[index] {
			t.Errorf("Expected url to be %s, instead got %s", urls[index], url)
		}

		// www.backblaze.com
		url, err = b.replaceProtocol(urls[i2])
		if err != nil {
			t.Errorf("Expected no error, instead got %+v", err)
		}
		if url != urls[index2] {
			t.Errorf("Expected url to be %s, instead got %s", urls[index2], url)
		}
	}

	url, err := b2s[0].replaceProtocol(urls[len(urls)-1])
	if err == nil {
		t.Errorf("Expected error, instead got nil, url returned was %s", url)
	}
}

func Test_GetBzInfoHeaders(t *testing.T) {
	headers := map[string][]string{
		"Content-Type":      []string{"kittens"},
		"X-Bz-Info-kittens": []string{"yes"},
		"X-Bz-Info-thing":   []string{"one"},
	}
	resp := &http.Response{Header: headers}

	bzHeaders := GetBzInfoHeaders(resp)

	if len(bzHeaders) != 2 {
		t.Fatalf("Expected length of headers to be 2, instead got %d", len(bzHeaders))
	}
	if h, ok := bzHeaders["Content-Type"]; ok {
		t.Errorf("Expected no Content-Type, instead recieved %s", h)
	}
	if h := bzHeaders["kittens"]; h != "yes" {
		t.Errorf(`Expected kittens to be "yes", instead got %s`, h)
	}
	if h := bzHeaders["thing"]; h != "one" {
		t.Errorf(`Expected thing to be "one", instead got %s`, h)
	}
}

// TODO remove
func setupRequest(code int, body string) (*httptest.Server, http.Client) {
	return setupMockJsonServer(code, body, nil)
}

// TODO remove
func setupMockJsonServer(code int, body string, reqChan chan<- *http.Request) (*httptest.Server, http.Client) {
	headers := map[string]string{"Content-Type": "application/json"}
	return setupMockServer(code, body, headers, reqChan)
}

// TODO remove
func setupMockServer(code int, body string, headers map[string]string, reqChan chan<- *http.Request) (*httptest.Server, http.Client) {
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if reqChan != nil {
			reqChan <- r
		}

		for k, v := range headers {
			w.Header().Set(k, v)
		}

		w.WriteHeader(code)
		fmt.Fprintln(w, body)
	}))

	tr := &http.Transport{
		Proxy: func(req *http.Request) (*url.URL, error) {
			return url.Parse(server.URL)
		},
	}

	return server, http.Client{Transport: tr}
}

func createTestResponse(statusCode int, body string) *http.Response {
	return &http.Response{
		StatusCode: statusCode,
		Body:       ioutil.NopCloser(strings.NewReader(body))}
}

func createTestErrorResponses() []*http.Response {
	return []*http.Response{
		createTestResponse(400, `{"status":400,"code":"nope","message":"nope nope"}`),
		createTestResponse(401, `{"status":401,"code":"nope","message":"nope nope"}`),
	}
}

// TODO replace with non-200 *http.Response creator
func errorResponses() ([]int, []string) {
	codes := []int{400, 401}
	bodies := []string{
		`{"status":400,"code":"nope","message":"nope nope"}`,
		`{"status":401,"code":"nope","message":"nope nope"}`,
	}
	return codes, bodies
}

func testErrorResponse(err error, code int, t *testing.T) {
	if err == nil {
		t.Error("Expected error, no error received")
	} else if err.Error() != fmt.Sprintf("Status: %d, Code: nope, Message: nope nope", code) {
		t.Errorf(`Expected "Status: %d, Code: nope, Message: nope nope", instead got %s`, code, err)
	}
}

func makeTestB2(c http.Client) *B2 {
	return &B2{
		AccountID:          "id",
		AuthorizationToken: "token",
		ApiUrl:             "https://api900.backblaze.com",
		DownloadUrl:        "https://f900.backblaze.com",
		client:             &client{Protocol: "http", Client: c},
	}
}
<|endoftext|>


<commit_before>package messages

import (
	"bytes"
	"sort"
	"time"

	"github.com/cloudfoundry/sonde-go/events"
)

type Metric struct {
	Name      string
	Value     float64
	EventTime time.Time
	Unit      string // TODO Should this be "1" if it's empty?
}

// MetricEvent represents the translation of an events.Envelope into a set
// of Metrics
type MetricEvent struct {
	Labels  map[string]string
	Metrics []*Metric
	Type    events.Envelope_EventType `json:"-"`
}

func (m *MetricEvent) Hash() string {
	var b bytes.Buffer

	// Extract keys to a slice and sort it
	keys := make([]string, len(m.Labels), len(m.Labels))
	for k, _ := range m.Labels {
		keys = append(keys, k)
	}
	sort.Strings(keys)
	for _, k := range keys {
		b.Write([]byte(k))
		b.Write([]byte(m.Labels[k]))
	}
	return b.String()
}
<commit_msg>messages/metric: Don't emit Labels on messages.MetricEvent<commit_after>package messages

import (
	"bytes"
	"sort"
	"time"

	"github.com/cloudfoundry/sonde-go/events"
)

type Metric struct {
	Name      string
	Value     float64
	EventTime time.Time
	Unit      string // TODO Should this be "1" if it's empty?
}

// MetricEvent represents the translation of an events.Envelope into a set
// of Metrics
type MetricEvent struct {
	Labels  map[string]string `json:"-"`
	Metrics []*Metric
	Type    events.Envelope_EventType `json:"-"`
}

func (m *MetricEvent) Hash() string {
	var b bytes.Buffer

	// Extract keys to a slice and sort it
	keys := make([]string, len(m.Labels), len(m.Labels))
	for k, _ := range m.Labels {
		keys = append(keys, k)
	}
	sort.Strings(keys)
	for _, k := range keys {
		b.Write([]byte(k))
		b.Write([]byte(m.Labels[k]))
	}
	return b.String()
}
<|endoftext|>


<commit_before>package apiutils

import (
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"strconv"
)

func RequireParams(form url.Values, params []string) error {
	for _, param := range params {
		if len(form[param]) == 0 {
			return fmt.Errorf("Missing param: %s", param)
		}
	}
	return nil
}

// ReadParams reads in parameters from the request, using the content type.
func ReadParams(r *http.Request) (map[string]interface{}, error) {
	params := make(map[string]interface{})

	if r.Header.Get("Content-Type") == "application/json" {
		decoder := json.NewDecoder(r.Body)
		return params, decoder.Decode(&params)
	} else {
		r.ParseForm()

		if r.Method == "GET" {
			for k, v := range r.Form {
				params[k] = v
			}
		} else {
			for k, v := range r.PostForm {
				params[k] = v
			}
		}
		return params, nil
	}
}

func RequireFormParams(r *http.Request, params []string) error {
	for _, param := range params {
		if len(r.FormValue(param)) == 0 {
			return fmt.Errorf("Missing param: %s", param)
		}
	}
	return nil
}

type ErrorResponse struct {
	Status  int    `json:"status"`
	Message string `json:"message"`
	Error   string `json:"error"`
}

func NewErrorResponse(status int, message string) ErrorResponse {
	return ErrorResponse{
		Status:  status,
		Message: message,
		Error:   http.StatusText(status),
	}
}

func ServeJSON(w http.ResponseWriter, v interface{}) {
	content, err := json.MarshalIndent(v, "", "  ")
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	w.Header().Set("Content-Length", strconv.Itoa(len(content)))
	w.Header().Set("Content-Type", "application/json")
	w.Write(content)
}

func ServeError(w http.ResponseWriter, errRes ErrorResponse) {
	w.WriteHeader(errRes.Status)
	ServeJSON(w, errRes)
}
<commit_msg>read params works for urlencoded<commit_after>package apiutils

import (
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"strconv"
)

func RequireParams(form url.Values, params []string) error {
	for _, param := range params {
		if len(form[param]) == 0 {
			return fmt.Errorf("Missing param: %s", param)
		}
	}
	return nil
}

// ReadParams reads in parameters from the request, using the content type.
func ReadParams(r *http.Request) (map[string]interface{}, error) {
	params := make(map[string]interface{})

	if r.Header.Get("Content-Type") == "application/json" {
		decoder := json.NewDecoder(r.Body)
		return params, decoder.Decode(&params)
	} else {
		r.ParseForm()

		// Take first argument, equivalent to Get()
		for k, v := range r.Form {
			params[k] = v[0]
		}

		return params, nil
	}
}

func RequireFormParams(r *http.Request, params []string) error {
	for _, param := range params {
		if len(r.FormValue(param)) == 0 {
			return fmt.Errorf("Missing param: %s", param)
		}
	}
	return nil
}

type ErrorResponse struct {
	Status  int    `json:"status"`
	Message string `json:"message"`
	Error   string `json:"error"`
}

func NewErrorResponse(status int, message string) ErrorResponse {
	return ErrorResponse{
		Status:  status,
		Message: message,
		Error:   http.StatusText(status),
	}
}

func ServeJSON(w http.ResponseWriter, v interface{}) {
	content, err := json.MarshalIndent(v, "", "  ")
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	w.Header().Set("Content-Length", strconv.Itoa(len(content)))
	w.Header().Set("Content-Type", "application/json")
	w.Write(content)
}

func ServeError(w http.ResponseWriter, errRes ErrorResponse) {
	w.WriteHeader(errRes.Status)
	ServeJSON(w, errRes)
}
<|endoftext|>


<commit_before>// Package scipipe is a library for writing scientific workflows (sometimes
// also called "pipelines") of shell commands that depend on each other, in the
// Go programming languages. It was initially designed for problems in
// cheminformatics and bioinformatics, but should apply equally well to any
// domain involving complex pipelines of interdependent shell commands.
package scipipe

import (
	"sync"
)

// ----------------------------------------------------------------------------
// Workflow
// ----------------------------------------------------------------------------

// Workflow is the centerpiece of the functionality in SciPipe, and is a
// container for a pipeline of processes making up a workflow. It has various
// methods for coordination the execution of the pipeline as a whole, such as
// keeping track of the maxiumum number of concurrent tasks, as well as helper
// methods for creating new processes, that automatically gets plugged in to the
// workflow on creation
type Workflow struct {
	name              string
	procs             map[string]WorkflowProcess
	concurrentTasks   chan struct{}
	concurrentTasksMx sync.Mutex
	sink              *Sink
	driver            WorkflowProcess
}

// NewWorkflow returns a new Workflow
func NewWorkflow(name string, maxConcurrentTasks int) *Workflow {
	InitLogInfo()
	wf := &Workflow{
		name:            name,
		procs:           map[string]WorkflowProcess{},
		concurrentTasks: make(chan struct{}, maxConcurrentTasks),
	}
	sink := NewSink(wf, name+"_default_sink")
	wf.sink = sink
	wf.driver = sink
	return wf
}

// WorkflowProcess is an interface for processes to be handled by Workflow
type WorkflowProcess interface {
	Name() string
	InPorts() map[string]*InPort
	OutPorts() map[string]*OutPort
	ParamInPorts() map[string]*ParamInPort
	ParamOutPorts() map[string]*ParamOutPort
	Connected() bool
	Run()
}

// Name returns the name of the workflow
func (wf *Workflow) Name() string {
	return wf.name
}

// AddProc adds a Process to the workflow, to be run when the workflow runs
func (wf *Workflow) AddProc(proc WorkflowProcess) {
	if wf.procs[proc.Name()] != nil {
		Failf(wf.name+" workflow: A process with name '%s' already exists in the workflow! Use a more unique name!\n", proc.Name())
	}
	wf.procs[proc.Name()] = proc
}

// AddProcs takes one or many Processes and adds them to the workflow, to be run
// when the workflow runs.
func (wf *Workflow) AddProcs(procs ...WorkflowProcess) {
	for _, proc := range procs {
		wf.AddProc(proc)
	}
}

// NewProc returns a new process based on a commandPattern (See the
// documentation for scipipe.NewProcess for more details about the pattern) and
// connects the process to the workflow
func (wf *Workflow) NewProc(procName string, commandPattern string) *Process {
	proc := NewProc(wf, procName, commandPattern)
	return proc
}

// Proc returns the process with name procName from the workflow
func (wf *Workflow) Proc(procName string) WorkflowProcess {
	if _, ok := wf.procs[procName]; !ok {
		Failf("No process named '%s' in workflow '%s'", procName, wf.Name())
	}
	return wf.procs[procName]
}

// Procs returns a map of all processes keyed by their names in the workflow
func (wf *Workflow) Procs() map[string]WorkflowProcess {
	return wf.procs
}

// Sink returns the sink process of the workflow
func (wf *Workflow) Sink() *Sink {
	return wf.sink
}

// SetSink sets the sink of the workflow to the provided sink process
func (wf *Workflow) SetSink(sink *Sink) {
	if wf.sink.Connected() {
		Fail("Trying to replace a sink which is already connected. Are you combining SetSink() with ConnectFinalOutPort()? That is not allowed!")
	}
	wf.sink = sink
}

// IncConcurrentTasks increases the conter for how many concurrent tasks are
// currently running in the workflow
func (wf *Workflow) IncConcurrentTasks(slots int) {
	// We must lock so that multiple processes don't end up with partially "filled slots"
	wf.concurrentTasksMx.Lock()
	for i := 0; i < slots; i++ {
		wf.concurrentTasks <- struct{}{}
		Debug.Println("Increased concurrent tasks")
	}
	wf.concurrentTasksMx.Unlock()
}

// DecConcurrentTasks decreases the conter for how many concurrent tasks are
// currently running in the workflow
func (wf *Workflow) DecConcurrentTasks(slots int) {
	for i := 0; i < slots; i++ {
		<-wf.concurrentTasks
		Debug.Println("Decreased concurrent tasks")
	}
}

func (wf *Workflow) readyToRun(procs map[string]WorkflowProcess) bool {
	if len(procs) == 0 {
		Error.Println(wf.name + ": The workflow is empty. Did you forget to add the processes to it?")
		return false
	}
	if wf.sink == nil {
		Error.Println(wf.name + ": sink is nil!")
		return false
	}
	for _, proc := range procs {
		if !proc.Connected() {
			Error.Println(wf.name + ": Not everything connected. Workflow shutting down.")
			return false
		}
	}
	return true
}

// runProcs runs a specified set of processes only
func (wf *Workflow) runProcs(procs map[string]WorkflowProcess) {
	wf.reconnectDeadEndConnections(procs)

	if !wf.readyToRun(procs) {
		Fail("Workflow not ready to run, due to previously reported errors, so exiting.")
	}

	for _, proc := range procs {
		Debug.Printf(wf.name+": Starting process %s in new go-routine", proc.Name())
		go proc.Run()
	}

	Debug.Printf(wf.name + ": Starting driver process in main go-routine")
	wf.driver.Run()
}

// reconnectDeadEndConnections disonnects connections to processes which are not
// in the set of processes to be run, and, if an out-port for a process that is supposed to be
// run becomes disconnected, it is connected to the sink instead
func (wf *Workflow) reconnectDeadEndConnections(procs map[string]WorkflowProcess) {
	foundNewDriverProc := false

	for pname, proc := range procs {
		// OutPorts
		for _, opt := range proc.OutPorts() {
			for iptName, ipt := range opt.RemotePorts {
				// If the remotely connected process is not among the ones to run ...
				if ipt.Process() == nil {
					Debug.Printf("Disconnecting in-port %s from out-port %s", ipt.Name(), opt.Name())
					opt.Disconnect(iptName)
				} else if _, ok := procs[ipt.Process().Name()]; !ok {
					Debug.Printf("Disconnecting in-port %s from out-port %s", ipt.Name(), opt.Name())
					opt.Disconnect(iptName)
				}
			}
			if !opt.Connected() {
				Debug.Printf("Connecting disconnected out-port %s of process %s to workflow sink", opt.Name(), opt.Process().Name())
				wf.sink.Connect(opt)
			}
		}

		// ParamOutPorts
		for _, pop := range proc.ParamOutPorts() {
			for rppName, rpp := range pop.RemotePorts {
				// If the remotely connected process is not among the ones to run ...
				if rpp.Process() == nil {
					Debug.Printf("Disconnecting in-port %s from out-port %s", rpp.Name(), pop.Name())
					pop.Disconnect(rppName)
				} else if _, ok := procs[rpp.Process().Name()]; !ok {
					Debug.Printf("Disconnecting in-port %s from out-port %s", rpp.Name(), pop.Name())
					pop.Disconnect(rppName)
				}
			}
			if !pop.Connected() {
				Debug.Printf("Connecting disconnected out-port %s of process %s to workflow sink", pop.Name(), pop.Process().Name())
				wf.sink.ConnectParam(pop)
			}
		}

		if len(proc.OutPorts()) == 0 && len(proc.ParamOutPorts()) == 0 {
			if foundNewDriverProc {
				Failf("Found more than one process without out-ports nor out-param ports. Cannot use both as drivers (One of them being '%s'). Adapt your workflow accordingly.", proc.Name())
			}
			foundNewDriverProc = true
			wf.driver = proc
			delete(wf.procs, pname) // A process can't both be the driver, and be included in the main procs map
		}
	}
}

// RunProcsByName runs a specified set of processes only, specified by their
// names as strings
func (wf *Workflow) RunProcsByName(procNames ...string) {
	procs := map[string]WorkflowProcess{}
	for _, procName := range procNames {
		procs[procName] = wf.Proc(procName)
	}
	wf.runProcs(procs)
}

// RunTo runs all processes upstream of, and including, the process with
// names provided as arguments
func (wf *Workflow) RunTo(finalProcNames ...string) {
	procs := []WorkflowProcess{}
	for _, procName := range finalProcNames {
		procs = append(procs, wf.Proc(procName))
	}
	wf.RunToProcs(procs...)
}

// RunToProcs runs all processes upstream of, and including, the process strucs
// provided as arguments
func (wf *Workflow) RunToProcs(finalProcs ...WorkflowProcess) {
	procsToRun := map[string]WorkflowProcess{}
	for _, finalProc := range finalProcs {
		procsToRun = mergeWFMaps(procsToRun, upstreamProcsForProc(finalProc))
		procsToRun[finalProc.Name()] = finalProc
	}
	wf.runProcs(procsToRun)
}

// upstreamProcsForProc returns all processes it is connected to, either
// directly or indirectly, via its in-ports and param-in-ports
func upstreamProcsForProc(proc WorkflowProcess) map[string]WorkflowProcess {
	procs := map[string]WorkflowProcess{}
	for _, inp := range proc.InPorts() {
		for _, rpt := range inp.RemotePorts {
			procs[rpt.Process().Name()] = rpt.Process()
			mergeWFMaps(procs, upstreamProcsForProc(rpt.Process()))
		}
	}
	for _, pip := range proc.ParamInPorts() {
		for _, rpp := range pip.RemotePorts {
			procs[rpp.Process().Name()] = rpp.Process()
			mergeWFMaps(procs, upstreamProcsForProc(rpp.Process()))
		}
	}
	return procs
}

func mergeWFMaps(a map[string]WorkflowProcess, b map[string]WorkflowProcess) map[string]WorkflowProcess {
	for k, v := range b {
		a[k] = v
	}
	return a
}

// Run runs the workflow
func (wf *Workflow) Run() {
	wf.runProcs(wf.procs)
}
<commit_msg>Add new method RunToRegex()<commit_after>// Package scipipe is a library for writing scientific workflows (sometimes
// also called "pipelines") of shell commands that depend on each other, in the
// Go programming languages. It was initially designed for problems in
// cheminformatics and bioinformatics, but should apply equally well to any
// domain involving complex pipelines of interdependent shell commands.
package scipipe

import (
	"fmt"
	"regexp"
	"sync"
)

// ----------------------------------------------------------------------------
// Workflow
// ----------------------------------------------------------------------------

// Workflow is the centerpiece of the functionality in SciPipe, and is a
// container for a pipeline of processes making up a workflow. It has various
// methods for coordination the execution of the pipeline as a whole, such as
// keeping track of the maxiumum number of concurrent tasks, as well as helper
// methods for creating new processes, that automatically gets plugged in to the
// workflow on creation
type Workflow struct {
	name              string
	procs             map[string]WorkflowProcess
	concurrentTasks   chan struct{}
	concurrentTasksMx sync.Mutex
	sink              *Sink
	driver            WorkflowProcess
}

// NewWorkflow returns a new Workflow
func NewWorkflow(name string, maxConcurrentTasks int) *Workflow {
	InitLogInfo()
	wf := &Workflow{
		name:            name,
		procs:           map[string]WorkflowProcess{},
		concurrentTasks: make(chan struct{}, maxConcurrentTasks),
	}
	sink := NewSink(wf, name+"_default_sink")
	wf.sink = sink
	wf.driver = sink
	return wf
}

// WorkflowProcess is an interface for processes to be handled by Workflow
type WorkflowProcess interface {
	Name() string
	InPorts() map[string]*InPort
	OutPorts() map[string]*OutPort
	ParamInPorts() map[string]*ParamInPort
	ParamOutPorts() map[string]*ParamOutPort
	Connected() bool
	Run()
}

// Name returns the name of the workflow
func (wf *Workflow) Name() string {
	return wf.name
}

// AddProc adds a Process to the workflow, to be run when the workflow runs
func (wf *Workflow) AddProc(proc WorkflowProcess) {
	if wf.procs[proc.Name()] != nil {
		Failf(wf.name+" workflow: A process with name '%s' already exists in the workflow! Use a more unique name!\n", proc.Name())
	}
	wf.procs[proc.Name()] = proc
}

// AddProcs takes one or many Processes and adds them to the workflow, to be run
// when the workflow runs.
func (wf *Workflow) AddProcs(procs ...WorkflowProcess) {
	for _, proc := range procs {
		wf.AddProc(proc)
	}
}

// NewProc returns a new process based on a commandPattern (See the
// documentation for scipipe.NewProcess for more details about the pattern) and
// connects the process to the workflow
func (wf *Workflow) NewProc(procName string, commandPattern string) *Process {
	proc := NewProc(wf, procName, commandPattern)
	return proc
}

// Proc returns the process with name procName from the workflow
func (wf *Workflow) Proc(procName string) WorkflowProcess {
	if _, ok := wf.procs[procName]; !ok {
		Failf("No process named '%s' in workflow '%s'", procName, wf.Name())
	}
	return wf.procs[procName]
}

// Procs returns a map of all processes keyed by their names in the workflow
func (wf *Workflow) Procs() map[string]WorkflowProcess {
	return wf.procs
}

// Sink returns the sink process of the workflow
func (wf *Workflow) Sink() *Sink {
	return wf.sink
}

// SetSink sets the sink of the workflow to the provided sink process
func (wf *Workflow) SetSink(sink *Sink) {
	if wf.sink.Connected() {
		Fail("Trying to replace a sink which is already connected. Are you combining SetSink() with ConnectFinalOutPort()? That is not allowed!")
	}
	wf.sink = sink
}

// IncConcurrentTasks increases the conter for how many concurrent tasks are
// currently running in the workflow
func (wf *Workflow) IncConcurrentTasks(slots int) {
	// We must lock so that multiple processes don't end up with partially "filled slots"
	wf.concurrentTasksMx.Lock()
	for i := 0; i < slots; i++ {
		wf.concurrentTasks <- struct{}{}
		Debug.Println("Increased concurrent tasks")
	}
	wf.concurrentTasksMx.Unlock()
}

// DecConcurrentTasks decreases the conter for how many concurrent tasks are
// currently running in the workflow
func (wf *Workflow) DecConcurrentTasks(slots int) {
	for i := 0; i < slots; i++ {
		<-wf.concurrentTasks
		Debug.Println("Decreased concurrent tasks")
	}
}

func (wf *Workflow) readyToRun(procs map[string]WorkflowProcess) bool {
	if len(procs) == 0 {
		Error.Println(wf.name + ": The workflow is empty. Did you forget to add the processes to it?")
		return false
	}
	if wf.sink == nil {
		Error.Println(wf.name + ": sink is nil!")
		return false
	}
	for _, proc := range procs {
		if !proc.Connected() {
			Error.Println(wf.name + ": Not everything connected. Workflow shutting down.")
			return false
		}
	}
	return true
}

// runProcs runs a specified set of processes only
func (wf *Workflow) runProcs(procs map[string]WorkflowProcess) {
	wf.reconnectDeadEndConnections(procs)

	if !wf.readyToRun(procs) {
		Fail("Workflow not ready to run, due to previously reported errors, so exiting.")
	}

	for _, proc := range procs {
		Debug.Printf(wf.name+": Starting process %s in new go-routine", proc.Name())
		go proc.Run()
	}

	Debug.Printf(wf.name + ": Starting driver process in main go-routine")
	wf.driver.Run()
}

// reconnectDeadEndConnections disonnects connections to processes which are not
// in the set of processes to be run, and, if an out-port for a process that is supposed to be
// run becomes disconnected, it is connected to the sink instead
func (wf *Workflow) reconnectDeadEndConnections(procs map[string]WorkflowProcess) {
	foundNewDriverProc := false

	for pname, proc := range procs {
		// OutPorts
		for _, opt := range proc.OutPorts() {
			for iptName, ipt := range opt.RemotePorts {
				// If the remotely connected process is not among the ones to run ...
				if ipt.Process() == nil {
					Debug.Printf("Disconnecting in-port %s from out-port %s", ipt.Name(), opt.Name())
					opt.Disconnect(iptName)
				} else if _, ok := procs[ipt.Process().Name()]; !ok {
					Debug.Printf("Disconnecting in-port %s from out-port %s", ipt.Name(), opt.Name())
					opt.Disconnect(iptName)
				}
			}
			if !opt.Connected() {
				Debug.Printf("Connecting disconnected out-port %s of process %s to workflow sink", opt.Name(), opt.Process().Name())
				wf.sink.Connect(opt)
			}
		}

		// ParamOutPorts
		for _, pop := range proc.ParamOutPorts() {
			for rppName, rpp := range pop.RemotePorts {
				// If the remotely connected process is not among the ones to run ...
				if rpp.Process() == nil {
					Debug.Printf("Disconnecting in-port %s from out-port %s", rpp.Name(), pop.Name())
					pop.Disconnect(rppName)
				} else if _, ok := procs[rpp.Process().Name()]; !ok {
					Debug.Printf("Disconnecting in-port %s from out-port %s", rpp.Name(), pop.Name())
					pop.Disconnect(rppName)
				}
			}
			if !pop.Connected() {
				Debug.Printf("Connecting disconnected out-port %s of process %s to workflow sink", pop.Name(), pop.Process().Name())
				wf.sink.ConnectParam(pop)
			}
		}

		if len(proc.OutPorts()) == 0 && len(proc.ParamOutPorts()) == 0 {
			if foundNewDriverProc {
				Failf("Found more than one process without out-ports nor out-param ports. Cannot use both as drivers (One of them being '%s'). Adapt your workflow accordingly.", proc.Name())
			}
			foundNewDriverProc = true
			wf.driver = proc
			delete(wf.procs, pname) // A process can't both be the driver, and be included in the main procs map
		}
	}
}

// RunProcsByName runs a specified set of processes only, specified by their
// names as strings
func (wf *Workflow) RunProcsByName(procNames ...string) {
	procs := map[string]WorkflowProcess{}
	for _, procName := range procNames {
		procs[procName] = wf.Proc(procName)
	}
	wf.runProcs(procs)
}

// RunToRegex runs all processes upstream of, and including, the process
// whose name matches any of the provided regexp patterns
func (wf *Workflow) RunToRegex(procNamePatterns ...string) {
	procsToRun := []WorkflowProcess{}
	for procName, proc := range wf.Procs() {
		for _, pattern := range procNamePatterns {
			matches, err := regexp.MatchString(pattern, procName)
			CheckWithMsg(err, fmt.Sprintf("Regex pattern doesn't work: %s", pattern))
			if matches {
				procsToRun = append(procsToRun, proc)
			}
		}
	}
	wf.RunToProcs(procsToRun...)
}

// RunTo runs all processes upstream of, and including, the process with
// names provided as arguments
func (wf *Workflow) RunTo(finalProcNames ...string) {
	procs := []WorkflowProcess{}
	for _, procName := range finalProcNames {
		procs = append(procs, wf.Proc(procName))
	}
	wf.RunToProcs(procs...)
}

// RunToProcs runs all processes upstream of, and including, the process strucs
// provided as arguments
func (wf *Workflow) RunToProcs(finalProcs ...WorkflowProcess) {
	procsToRun := map[string]WorkflowProcess{}
	for _, finalProc := range finalProcs {
		procsToRun = mergeWFMaps(procsToRun, upstreamProcsForProc(finalProc))
		procsToRun[finalProc.Name()] = finalProc
	}
	wf.runProcs(procsToRun)
}

// upstreamProcsForProc returns all processes it is connected to, either
// directly or indirectly, via its in-ports and param-in-ports
func upstreamProcsForProc(proc WorkflowProcess) map[string]WorkflowProcess {
	procs := map[string]WorkflowProcess{}
	for _, inp := range proc.InPorts() {
		for _, rpt := range inp.RemotePorts {
			procs[rpt.Process().Name()] = rpt.Process()
			mergeWFMaps(procs, upstreamProcsForProc(rpt.Process()))
		}
	}
	for _, pip := range proc.ParamInPorts() {
		for _, rpp := range pip.RemotePorts {
			procs[rpp.Process().Name()] = rpp.Process()
			mergeWFMaps(procs, upstreamProcsForProc(rpp.Process()))
		}
	}
	return procs
}

func mergeWFMaps(a map[string]WorkflowProcess, b map[string]WorkflowProcess) map[string]WorkflowProcess {
	for k, v := range b {
		a[k] = v
	}
	return a
}

// Run runs the workflow
func (wf *Workflow) Run() {
	wf.runProcs(wf.procs)
}
<|endoftext|>


<commit_before>// Copyright 2013 Flo Lauber <dev@qatfy.at>.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// TODO(flo):
//   - support password protected MUC rooms
//   - cleanup signatures of join/leave functions
package xmpp

import (
	"fmt"
	"time"
	"errors"
)

const (
	nsMUC     = "http://jabber.org/protocol/muc"
	nsMUCUser = "http://jabber.org/protocol/muc#user"
	NoHistory = 0
	CharHistory = 1
	StanzaHistory = 2
	SecondsHistory = 3
	SinceHistory = 4
)

// Send sends room topic wrapped inside an XMPP message stanza body.
func (c *Client) SendTopic(chat Chat) (n int, err error) {
	return fmt.Fprintf(c.conn, "<message to='%s' type='%s' xml:lang='en'>"+"<subject>%s</subject></message>",
		xmlEscape(chat.Remote), xmlEscape(chat.Type), xmlEscape(chat.Text))
}

func (c *Client) JoinMUCNoHistory(jid, nick string) (n int, err error) {
	if nick == "" {
		nick = c.jid
	}
	return fmt.Fprintf(c.conn, "<presence to='%s/%s'>\n"+
		"<x xmlns='%s'>"+
		"<history maxchars='0'/></x>\n"+
		"</presence>",
		xmlEscape(jid), xmlEscape(nick), nsMUC)
}

// xep-0045 7.2
func (c *Client) JoinMUC(jid, nick string, history_type, history int, history_date *time.Time) (n int, err error) {
	if nick == "" {
		nick = c.jid
	}
	switch history_type {
	case NoHistory:
		return fmt.Fprintf(c.conn, "<presence to='%s/%s'>\n" +
			"<x xmlns='%s' /></x>\n" +
			"</presence>",
				xmlEscape(jid), xmlEscape(nick), nsMUC)
	case CharHistory:
		return fmt.Fprintf(c.conn, "<presence to='%s/%s'>\n" +
			"<x xmlns='%s'>\n" +
			"<history maxchars='%d'/></x>\n"+
			"</presence>",
				xmlEscape(jid), xmlEscape(nick), nsMUC, history)
	case StanzaHistory:
		return fmt.Fprintf(c.conn, "<presence to='%s/%s'>\n" +
			"<x xmlns='%s'>\n" +
			"<history maxstanzas='%d'/></x>\n"+
			"</presence>",
				xmlEscape(jid), xmlEscape(nick), nsMUC, history)
	case SecondsHistory:
		return fmt.Fprintf(c.conn, "<presence to='%s/%s'>\n" +
			"<x xmlns='%s'>\n" +
			"<history seconds='%d'/></x>\n"+
			"</presence>",
				xmlEscape(jid), xmlEscape(nick), nsMUC, history)
	case SinceHistory:
		if history_date != nil {
			return fmt.Fprintf(c.conn, "<presence to='%s/%s'>\n" +
				"<x xmlns='%s'>\n" +
				"<history since='%s'/></x>\n" +
				"</presence>",
					xmlEscape(jid), xmlEscape(nick), nsMUC, history_date.Format(time.RFC3339))
		}
	}
	return 0, errors.New("Unknown history option")
}

// xep-0045 7.2.6
func (c *Client) JoinProtectedMUC(jid, nick string, password string, history_type, history int, history_date *time.Time) (n int, err error) {
	if nick == "" {
		nick = c.jid
	}
	switch history_type {
	case NoHistory:
		return fmt.Fprintf(c.conn, "<presence to='%s/%s'>\n" +
			"<x xmlns='%s'>\n" +
			"<password>%s</password></x>\n"+
			"</presence>",
				xmlEscape(jid), xmlEscape(nick), nsMUC, xmlEscape(password))
	case CharHistory:
		return fmt.Fprintf(c.conn, "<presence to='%s/%s'>\n" +
			"<x xmlns='%s'>\n" +
			"<password>%s</password>\n"+
			"<history maxchars='%d'/></x>\n"+
			"</presence>",
				xmlEscape(jid), xmlEscape(nick), nsMUC, xmlEscape(password), history)
	case StanzaHistory:
		return fmt.Fprintf(c.conn, "<presence to='%s/%s'>\n" +
			"<x xmlns='%s'>\n" +
			"<password>%s</password>\n"+
			"<history maxstanzas='%d'/></x>\n"+
			"</presence>",
				xmlEscape(jid), xmlEscape(nick), nsMUC, xmlEscape(password), history)
	case SecondsHistory:
		return fmt.Fprintf(c.conn, "<presence to='%s/%s'>\n" +
			"<x xmlns='%s'>\n" +
			"<password>%s</password>\n"+
			"<history seconds='%d'/></x>\n"+
			"</presence>",
				xmlEscape(jid), xmlEscape(nick), nsMUC, xmlEscape(password), history)
	case SinceHistory:
		if history_date != nil {
			return fmt.Fprintf(c.conn, "<presence to='%s/%s'>\n" +
				"<x xmlns='%s'>\n" +
				"<password>%s</password>\n"+
				"<history since='%s'/></x>\n" +
				"</presence>",
					xmlEscape(jid), xmlEscape(nick), nsMUC, xmlEscape(password), history_date.Format(time.RFC3339))
		}
	}
	return 0, errors.New("Unknown history option")
}

// xep-0045 7.14
func (c *Client) LeaveMUC(jid string) (n int, err error) {
	return fmt.Fprintf(c.conn, "<presence from='%s' to='%s' type='unavailable' />",
		c.jid, xmlEscape(jid))
}
<commit_msg>Reformat fix for MUC NoHistory<commit_after>// Copyright 2013 Flo Lauber <dev@qatfy.at>.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// TODO(flo):
//   - support password protected MUC rooms
//   - cleanup signatures of join/leave functions
package xmpp

import (
	"fmt"
	"time"
	"errors"
)

const (
	nsMUC     = "http://jabber.org/protocol/muc"
	nsMUCUser = "http://jabber.org/protocol/muc#user"
	NoHistory = 0
	CharHistory = 1
	StanzaHistory = 2
	SecondsHistory = 3
	SinceHistory = 4
)

// Send sends room topic wrapped inside an XMPP message stanza body.
func (c *Client) SendTopic(chat Chat) (n int, err error) {
	return fmt.Fprintf(c.conn, "<message to='%s' type='%s' xml:lang='en'>"+"<subject>%s</subject></message>",
		xmlEscape(chat.Remote), xmlEscape(chat.Type), xmlEscape(chat.Text))
}

func (c *Client) JoinMUCNoHistory(jid, nick string) (n int, err error) {
	if nick == "" {
		nick = c.jid
	}
	return fmt.Fprintf(c.conn, "<presence to='%s/%s'>\n"+
		"<x xmlns='%s'>"+
		"<history maxchars='0'/></x>\n"+
		"</presence>",
		xmlEscape(jid), xmlEscape(nick), nsMUC)
}

// xep-0045 7.2
func (c *Client) JoinMUC(jid, nick string, history_type, history int, history_date *time.Time) (n int, err error) {
	if nick == "" {
		nick = c.jid
	}
	switch history_type {
	case NoHistory:
		return fmt.Fprintf(c.conn, "<presence to='%s/%s'>\n" +
			"<x xmlns='%s' />\n" +
			"</presence>",
				xmlEscape(jid), xmlEscape(nick), nsMUC)
	case CharHistory:
		return fmt.Fprintf(c.conn, "<presence to='%s/%s'>\n" +
			"<x xmlns='%s'>\n" +
			"<history maxchars='%d'/></x>\n"+
			"</presence>",
				xmlEscape(jid), xmlEscape(nick), nsMUC, history)
	case StanzaHistory:
		return fmt.Fprintf(c.conn, "<presence to='%s/%s'>\n" +
			"<x xmlns='%s'>\n" +
			"<history maxstanzas='%d'/></x>\n"+
			"</presence>",
				xmlEscape(jid), xmlEscape(nick), nsMUC, history)
	case SecondsHistory:
		return fmt.Fprintf(c.conn, "<presence to='%s/%s'>\n" +
			"<x xmlns='%s'>\n" +
			"<history seconds='%d'/></x>\n"+
			"</presence>",
				xmlEscape(jid), xmlEscape(nick), nsMUC, history)
	case SinceHistory:
		if history_date != nil {
			return fmt.Fprintf(c.conn, "<presence to='%s/%s'>\n" +
				"<x xmlns='%s'>\n" +
				"<history since='%s'/></x>\n" +
				"</presence>",
					xmlEscape(jid), xmlEscape(nick), nsMUC, history_date.Format(time.RFC3339))
		}
	}
	return 0, errors.New("Unknown history option")
}

// xep-0045 7.2.6
func (c *Client) JoinProtectedMUC(jid, nick string, password string, history_type, history int, history_date *time.Time) (n int, err error) {
	if nick == "" {
		nick = c.jid
	}
	switch history_type {
	case NoHistory:
		return fmt.Fprintf(c.conn, "<presence to='%s/%s'>\n" +
			"<x xmlns='%s'>\n" +
			"<password>%s</password>" +
			"</x>\n" +
			"</presence>",
				xmlEscape(jid), xmlEscape(nick), nsMUC, xmlEscape(password))
	case CharHistory:
		return fmt.Fprintf(c.conn, "<presence to='%s/%s'>\n" +
			"<x xmlns='%s'>\n" +
			"<password>%s</password>\n"+
			"<history maxchars='%d'/></x>\n"+
			"</presence>",
				xmlEscape(jid), xmlEscape(nick), nsMUC, xmlEscape(password), history)
	case StanzaHistory:
		return fmt.Fprintf(c.conn, "<presence to='%s/%s'>\n" +
			"<x xmlns='%s'>\n" +
			"<password>%s</password>\n"+
			"<history maxstanzas='%d'/></x>\n"+
			"</presence>",
				xmlEscape(jid), xmlEscape(nick), nsMUC, xmlEscape(password), history)
	case SecondsHistory:
		return fmt.Fprintf(c.conn, "<presence to='%s/%s'>\n" +
			"<x xmlns='%s'>\n" +
			"<password>%s</password>\n"+
			"<history seconds='%d'/></x>\n"+
			"</presence>",
				xmlEscape(jid), xmlEscape(nick), nsMUC, xmlEscape(password), history)
	case SinceHistory:
		if history_date != nil {
			return fmt.Fprintf(c.conn, "<presence to='%s/%s'>\n" +
				"<x xmlns='%s'>\n" +
				"<password>%s</password>\n"+
				"<history since='%s'/></x>\n" +
				"</presence>",
					xmlEscape(jid), xmlEscape(nick), nsMUC, xmlEscape(password), history_date.Format(time.RFC3339))
		}
	}
	return 0, errors.New("Unknown history option")
}

// xep-0045 7.14
func (c *Client) LeaveMUC(jid string) (n int, err error) {
	return fmt.Fprintf(c.conn, "<presence from='%s' to='%s' type='unavailable' />",
		c.jid, xmlEscape(jid))
}
<|endoftext|>