<commit_before>package models

import (
	"errors"

	"github.com/antihax/evedata/services/conservator"
)

// [BENCHMARK] 0.000 sec / 0.000 sec
func GetShares(characterID int32) ([]conservator.Share, error) {
	shares := []conservator.Share{}
	if err := database.Select(&shares, `
		SELECT S.characterID, S.tokenCharacterID, characterName AS tokenCharacterName, entityID, types, IFNULL(A.name, C.name) AS entityName, IF(A.name IS NULL, "corporation", "alliance") AS entityType
		FROM evedata.sharing S
		INNER JOIN evedata.crestTokens T ON T.tokenCharacterID = S.tokenCharacterID AND T.characterID = S.characterID
		LEFT OUTER JOIN evedata.corporations C ON C.corporationID = S.entityID
		LEFT OUTER JOIN evedata.alliances A ON A.allianceID = S.entityID
		WHERE S.characterID = ?;`, characterID); err != nil {
		return nil, err
	}
	return shares, nil
}

func AddShare(characterID, tokenCharacterID, entityID int32, types string) error {
	if _, err := database.Exec(`
		INSERT INTO evedata.sharing	(characterID, tokenCharacterID, entityID, types)
			VALUES(?,?,?,?)
			ON DUPLICATE KEY UPDATE entityID = entityID, types = VALUES(types)`,
		characterID, tokenCharacterID, entityID, types); err != nil {
		return err
	}
	return nil
}

func DeleteShare(characterID, tokenCharacterID, entityID int32) error {
	if _, err := database.Exec(`DELETE FROM evedata.sharing WHERE characterID = ? AND tokenCharacterID=? AND entityID = ? LIMIT 1`,
		characterID, tokenCharacterID, entityID); err != nil {
		return err
	}
	return nil
}

// [BENCHMARK] 0.000 sec / 0.000 sec
func GetBotServices(characterID int32) ([]conservator.Service, error) {
	services := []conservator.Service{}
	if err := database.Select(&services, `
		SELECT  S.botServiceID, S.name, entityID, address,  type, services, options,
		IFNULL(A.name, C.name) AS entityName, IF(A.name IS NULL, "corporation", "alliance") AS entityType
				FROM evedata.botServices S
				LEFT OUTER JOIN evedata.corporations C ON C.corporationID = S.entityID
				LEFT OUTER JOIN evedata.alliances A ON A.allianceID = S.entityID
				LEFT OUTER JOIN evedata.botDelegate D ON D.botServiceID = S.botServiceID
				LEFT OUTER JOIN evedata.crestTokens T ON FIND_IN_SET("Director", T.roles) AND
					T.characterID = ? AND (A.executorCorpID = T.corporationID OR
					(T.allianceID = 0 AND T.corporationID = S.entityID))
				WHERE D.characterID = ? OR T.characterID = ?
				GROUP BY botServiceID;`, characterID, characterID, characterID); err != nil {
		return nil, err
	}
	return services, nil
}

type BotServiceDetails struct {
	conservator.Service
	Channels []conservator.Channel
	Shares   []conservator.Share
}

// [BENCHMARK] 0.000 sec / 0.000 sec
func GetBotServiceDetails(characterID, serverID int32) (BotServiceDetails, error) {

	// let this perform our authorization checks
	service := BotServiceDetails{}
	row, err := database.Queryx(`
		SELECT  S.botServiceID, S.name, entityID, address,  type, services, options,
		IFNULL(A.name, C.name) AS entityName, IF(A.name IS NULL, "corporation", "alliance") AS entityType
				FROM evedata.botServices S
				LEFT OUTER JOIN evedata.corporations C ON C.corporationID = S.entityID
				LEFT OUTER JOIN evedata.alliances A ON A.allianceID = S.entityID
				LEFT OUTER JOIN evedata.botDelegate D ON D.botServiceID = S.botServiceID
				LEFT OUTER JOIN evedata.crestTokens T ON FIND_IN_SET("Director", T.roles) AND
					T.characterID = ? AND (A.executorCorpID = T.corporationID OR
					(T.allianceID = 0 AND T.corporationID = S.entityID))
				WHERE (D.characterID = ? OR T.characterID = ?) AND S.botServiceID = ?
				GROUP BY botServiceID LIMIT 1;`, characterID, characterID, characterID, serverID)
	if err != nil {
		return service, err
	}
	defer row.Close()

	if !row.Next() {
		return service, errors.New("Bot service unavailable")
	}
	err = row.StructScan(&service)
	if err != nil {
		return service, err
	}

	// not authorized
	if service.BotServiceID == 0 {
		return service, errors.New("character is not authorized")
	}

	err = database.Select(&service.Channels, `
		SELECT botServiceID, channelID, channelName, services, options
		FROM evedata.botChannels
		WHERE botServiceID = ?;`, service.BotServiceID)
	if err != nil {
		return service, err
	}

	err = database.Select(&service.Shares, `
		SELECT characterName AS tokenCharacterName, C.tokenCharacterID, E.corporationID AS entityID, E.name AS entityName, "corporation" AS entityType, B.botServiceID, types, ignored
		FROM evedata.sharing S
		INNER JOIN evedata.botServices B ON B.entityID = S.entityID
        INNER JOIN evedata.crestTokens C ON C.tokenCharacterID = S.tokenCharacterID
        INNER JOIN evedata.corporations E ON C.corporationID = E.corporationID
		WHERE B.botServiceID = ?;`, service.BotServiceID)
	if err != nil {
		return service, err
	}

	return service, nil
}

func AddBotServiceChannel(botServiceID int32, channelID, channelName string) error {
	if _, err := database.Exec(`
		INSERT INTO evedata.botChannels	(botServiceID, channelID, channelName, services, options)
			VALUES(?,?,?,'','')
			ON DUPLICATE KEY UPDATE channelID = channelID`,
		botServiceID, channelID, channelName); err != nil {
		return err
	}

	return nil
}

func DeleteBotServiceChannel(botServiceID int32, channelID string) error {
	if _, err := database.Exec(`
		DELETE  FROM evedata.botChannels
		WHERE botServiceID = ? AND channelID = ?`, botServiceID, channelID); err != nil {
		return err
	}
	return nil
}

func AddDiscordService(characterID, entityID int32, serverID string) error {
	// verify this user is able to create a discord service for this entity
	entities, err := GetEntitiesWithRole(characterID, "Director")
	if err != nil {
		return err
	}

	if !entityInSlice(entityID, entities) {
		return errors.New("character is unauthorized to create this discord entry")
	}

	if _, err := database.Exec(`
		INSERT INTO evedata.botServices	(entityID, address, type, options)
			VALUES(?,?,'discord','')
			ON DUPLICATE KEY UPDATE entityID = entityID`,
		entityID, serverID); err != nil {
		return err
	}

	return nil
}

func DeleteService(characterID, botServiceID int32) error {
	if _, err := database.Exec(`
		DELETE S FROM evedata.botServices S
		LEFT OUTER JOIN evedata.alliances A ON A.allianceID = S.entityID
		LEFT OUTER JOIN evedata.crestTokens T ON FIND_IN_SET("Director", T.roles) AND
		T.characterID = ? AND (A.executorCorpID = T.corporationID OR
		(T.allianceID = 0 AND T.corporationID = S.entityID))
		WHERE botServiceID = ? AND T.characterID = ?
		`,
		characterID, botServiceID, characterID); err != nil {
		return err
	}
	return nil
}

func entityInSlice(a int32, list []Entity) bool {
	for _, b := range list {
		if b.EntityID == a {
			return true
		}
	}
	return false
}
<commit_msg>cleaner<commit_after>package models

import (
	"errors"

	"github.com/antihax/evedata/services/conservator"
)

// [BENCHMARK] 0.000 sec / 0.000 sec
func GetShares(characterID int32) ([]conservator.Share, error) {
	shares := []conservator.Share{}
	if err := database.Select(&shares, `
		SELECT S.characterID, S.tokenCharacterID, characterName AS tokenCharacterName, entityID, types, IFNULL(A.name, C.name) AS entityName, IF(A.name IS NULL, "corporation", "alliance") AS entityType
		FROM evedata.sharing S
		INNER JOIN evedata.crestTokens T ON T.tokenCharacterID = S.tokenCharacterID AND T.characterID = S.characterID
		LEFT OUTER JOIN evedata.corporations C ON C.corporationID = S.entityID
		LEFT OUTER JOIN evedata.alliances A ON A.allianceID = S.entityID
		WHERE S.characterID = ?;`, characterID); err != nil {
		return nil, err
	}
	return shares, nil
}

func AddShare(characterID, tokenCharacterID, entityID int32, types string) error {
	if _, err := database.Exec(`
		INSERT INTO evedata.sharing	(characterID, tokenCharacterID, entityID, types)
			VALUES(?,?,?,?)
			ON DUPLICATE KEY UPDATE entityID = entityID, types = VALUES(types)`,
		characterID, tokenCharacterID, entityID, types); err != nil {
		return err
	}
	return nil
}

func DeleteShare(characterID, tokenCharacterID, entityID int32) error {
	if _, err := database.Exec(`DELETE FROM evedata.sharing WHERE characterID = ? AND tokenCharacterID=? AND entityID = ? LIMIT 1`,
		characterID, tokenCharacterID, entityID); err != nil {
		return err
	}
	return nil
}

// [BENCHMARK] 0.000 sec / 0.000 sec
func GetBotServices(characterID int32) ([]conservator.Service, error) {
	services := []conservator.Service{}
	if err := database.Select(&services, `
		SELECT  S.botServiceID, S.name, entityID, address,  type, services, options,
		IFNULL(A.name, C.name) AS entityName, IF(A.name IS NULL, "corporation", "alliance") AS entityType
				FROM evedata.botServices S
				LEFT OUTER JOIN evedata.corporations C ON C.corporationID = S.entityID
				LEFT OUTER JOIN evedata.alliances A ON A.allianceID = S.entityID
				LEFT OUTER JOIN evedata.botDelegate D ON D.botServiceID = S.botServiceID
				LEFT OUTER JOIN evedata.crestTokens T ON FIND_IN_SET("Director", T.roles) AND
					T.characterID = ? AND (A.executorCorpID = T.corporationID OR
					(T.allianceID = 0 AND T.corporationID = S.entityID))
				WHERE D.characterID = ? OR T.characterID = ?
				GROUP BY botServiceID;`, characterID, characterID, characterID); err != nil {
		return nil, err
	}
	return services, nil
}

type BotServiceDetails struct {
	conservator.Service
	Channels []conservator.Channel
	Shares   []conservator.Share
}

// [BENCHMARK] 0.000 sec / 0.000 sec
func GetBotServiceDetails(characterID, serverID int32) (BotServiceDetails, error) {

	// let this perform our authorization checks
	service := BotServiceDetails{}
	row, err := database.Queryx(`
		SELECT  S.botServiceID, S.name, entityID, address,  type, services, options,
		IFNULL(A.name, C.name) AS entityName, IF(A.name IS NULL, "corporation", "alliance") AS entityType
				FROM evedata.botServices S
				LEFT OUTER JOIN evedata.corporations C ON C.corporationID = S.entityID
				LEFT OUTER JOIN evedata.alliances A ON A.allianceID = S.entityID
				LEFT OUTER JOIN evedata.botDelegate D ON D.botServiceID = S.botServiceID
				LEFT OUTER JOIN evedata.crestTokens T ON FIND_IN_SET("Director", T.roles) AND
					T.characterID = ? AND (A.executorCorpID = T.corporationID OR
					(T.allianceID = 0 AND T.corporationID = S.entityID))
				WHERE (D.characterID = ? OR T.characterID = ?) AND S.botServiceID = ?
				GROUP BY botServiceID LIMIT 1;`, characterID, characterID, characterID, serverID)
	if err != nil {
		return service, err
	}
	defer row.Close()

	if !row.Next() {
		return service, errors.New("Bot service unavailable")
	}
	err = row.StructScan(&service)
	if err != nil {
		return service, err
	}

	// not authorized
	if service.BotServiceID == 0 {
		return service, errors.New("character is not authorized")
	}

	err = database.Select(&service.Channels, `
		SELECT botServiceID, channelID, channelName, services, options
		FROM evedata.botChannels
		WHERE botServiceID = ?;`, service.BotServiceID)
	if err != nil {
		return service, err
	}

	err = database.Select(&service.Shares, `
		SELECT characterName AS tokenCharacterName, C.tokenCharacterID, E.corporationID AS entityID, E.name AS entityName, "corporation" AS entityType, B.botServiceID, types, ignored
		FROM evedata.sharing S
		INNER JOIN evedata.botServices B ON B.entityID = S.entityID
        INNER JOIN evedata.crestTokens C ON C.tokenCharacterID = S.tokenCharacterID
        INNER JOIN evedata.corporations E ON C.corporationID = E.corporationID
		WHERE B.botServiceID = ?;`, service.BotServiceID)
	if err != nil {
		return service, err
	}

	return service, nil
}

func AddBotServiceChannel(botServiceID int32, channelID, channelName string) error {
	if _, err := database.Exec(`
		INSERT INTO evedata.botChannels	(botServiceID, channelID, channelName, services, options)
			VALUES(?,?,?,'','')
			ON DUPLICATE KEY UPDATE channelID = channelID`,
		botServiceID, channelID, channelName); err != nil {
		return err
	}

	return nil
}

func DeleteBotServiceChannel(botServiceID int32, channelID string) error {
	if _, err := database.Exec(`
		DELETE FROM evedata.botChannels
		WHERE botServiceID = ? AND channelID = ?`, botServiceID, channelID); err != nil {
		return err
	}
	return nil
}

func AddDiscordService(characterID, entityID int32, serverID string) error {
	// verify this user is able to create a discord service for this entity
	entities, err := GetEntitiesWithRole(characterID, "Director")
	if err != nil {
		return err
	}

	if !entityInSlice(entityID, entities) {
		return errors.New("character is unauthorized to create this discord entry")
	}

	if _, err := database.Exec(`
		INSERT INTO evedata.botServices	(entityID, address, type, options)
			VALUES(?,?,'discord','')
			ON DUPLICATE KEY UPDATE entityID = entityID`,
		entityID, serverID); err != nil {
		return err
	}

	return nil
}

func DeleteService(characterID, botServiceID int32) error {
	if _, err := database.Exec(`
		DELETE S FROM evedata.botServices S
		LEFT OUTER JOIN evedata.alliances A ON A.allianceID = S.entityID
		LEFT OUTER JOIN evedata.crestTokens T ON FIND_IN_SET("Director", T.roles) AND
		T.characterID = ? AND (A.executorCorpID = T.corporationID OR
		(T.allianceID = 0 AND T.corporationID = S.entityID))
		WHERE botServiceID = ? AND T.characterID = ?
		`,
		characterID, botServiceID, characterID); err != nil {
		return err
	}
	return nil
}

func entityInSlice(a int32, list []Entity) bool {
	for _, b := range list {
		if b.EntityID == a {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>package dos

import "os"
import "strings"
import "syscall"
import "unsafe"

var kernel32 = syscall.NewLazyDLL("kernel32")
var procGetModuleFileName = kernel32.NewProc("GetModuleFileNameW")

func GetModuleFileName() (string, error) {
	var path16 [syscall.MAX_PATH]uint16
	result, _, err := procGetModuleFileName.Call(0, uintptr(unsafe.Pointer(&path16[0])), uintptr(len(path16)))
	if result == 0 {
		return os.Args[0], err
	}
	return syscall.UTF16ToString(path16[:]), nil
}

var ExecutableSuffixes = map[string]bool{}

func init() {
	pathExt := os.Getenv("PATHEXT")
	for _, ext := range strings.Split(pathExt, ";") {
		ExecutableSuffixes[strings.ToLower(ext)] = true
	}
}

func IsExecutableSuffix(path string) bool {
	if len(ExecutableSuffixes) <= 0 {
		pathExt := os.Getenv("PATHEXT")
		if pathExt != "" {
			for _, ext := range strings.Split(pathExt, ";") {
				ExecutableSuffixes[strings.ToLower(ext)] = true
			}
		}
	}
	_, ok := ExecutableSuffixes[strings.ToLower(path)]
	return ok
}
<commit_msg>dos.IsExecutableSuffix で PATHEXT を都度解釈するようにした。<commit_after>package dos

import "os"
import "strings"
import "syscall"
import "unsafe"

var kernel32 = syscall.NewLazyDLL("kernel32")
var procGetModuleFileName = kernel32.NewProc("GetModuleFileNameW")

func GetModuleFileName() (string, error) {
	var path16 [syscall.MAX_PATH]uint16
	result, _, err := procGetModuleFileName.Call(0, uintptr(unsafe.Pointer(&path16[0])), uintptr(len(path16)))
	if result == 0 {
		return os.Args[0], err
	}
	return syscall.UTF16ToString(path16[:]), nil
}

var ExecutableSuffixes = map[string]bool{}

func init() {
	pathExt := os.Getenv("PATHEXT")
	for _, ext := range strings.Split(pathExt, ";") {
		ExecutableSuffixes[strings.ToLower(ext)] = true
	}
}

func IsExecutableSuffix(path string) bool {
	pathExt := os.Getenv("PATHEXT")
	if pathExt != "" {
		for _, ext := range strings.Split(pathExt, ";") {
			if strings.EqualFold(ext,path){
				return true
			}
		}
	}
	return false
}
<|endoftext|>


<commit_before>// Copyright 2014 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package bootstrap

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"
	"runtime/debug"
	"runtime/pprof"
	"runtime/trace"

	"github.com/google/blueprint"
	"github.com/google/blueprint/deptools"
)

var (
	outFile        string
	globFile       string
	depFile        string
	docFile        string
	cpuprofile     string
	memprofile     string
	traceFile      string
	runGoTests     bool
	noGC           bool
	moduleListFile string
	emptyNinjaFile bool

	BuildDir      string
	NinjaBuildDir string
	SrcDir        string

	absSrcDir string
)

func init() {
	flag.StringVar(&outFile, "o", "build.ninja", "the Ninja file to output")
	flag.StringVar(&globFile, "globFile", "build-globs.ninja", "the Ninja file of globs to output")
	flag.StringVar(&BuildDir, "b", ".", "the build output directory")
	flag.StringVar(&NinjaBuildDir, "n", "", "the ninja builddir directory")
	flag.StringVar(&depFile, "d", "", "the dependency file to output")
	flag.StringVar(&docFile, "docs", "", "build documentation file to output")
	flag.StringVar(&cpuprofile, "cpuprofile", "", "write cpu profile to file")
	flag.StringVar(&traceFile, "trace", "", "write trace to file")
	flag.StringVar(&memprofile, "memprofile", "", "write memory profile to file")
	flag.BoolVar(&noGC, "nogc", false, "turn off GC for debugging")
	flag.BoolVar(&runGoTests, "t", false, "build and run go tests during bootstrap")
	flag.StringVar(&moduleListFile, "l", "", "file that lists filepaths to parse")
	flag.BoolVar(&emptyNinjaFile, "empty-ninja-file", false, "write out a 0-byte ninja file")
}

func Main(ctx *blueprint.Context, config interface{}, extraNinjaFileDeps ...string) {
	if !flag.Parsed() {
		flag.Parse()
	}

	runtime.GOMAXPROCS(runtime.NumCPU())

	if noGC {
		debug.SetGCPercent(-1)
	}

	absSrcDir = ctx.SrcDir()

	if cpuprofile != "" {
		f, err := os.Create(absolutePath(cpuprofile))
		if err != nil {
			fatalf("error opening cpuprofile: %s", err)
		}
		pprof.StartCPUProfile(f)
		defer f.Close()
		defer pprof.StopCPUProfile()
	}

	if traceFile != "" {
		f, err := os.Create(absolutePath(traceFile))
		if err != nil {
			fatalf("error opening trace: %s", err)
		}
		trace.Start(f)
		defer f.Close()
		defer trace.Stop()
	}

	if flag.NArg() != 1 {
		fatalf("no Blueprints file specified")
	}

	SrcDir = filepath.Dir(flag.Arg(0))
	if moduleListFile != "" {
		ctx.SetModuleListFile(moduleListFile)
		extraNinjaFileDeps = append(extraNinjaFileDeps, moduleListFile)
	} else {
		fatalf("-l <moduleListFile> is required and must be nonempty")
	}
	filesToParse, err := ctx.ListModulePaths(SrcDir)
	if err != nil {
		fatalf("could not enumerate files: %v\n", err.Error())
	}

	if NinjaBuildDir == "" {
		NinjaBuildDir = BuildDir
	}

	stage := StageMain
	if c, ok := config.(ConfigInterface); ok {
		if c.GeneratingPrimaryBuilder() {
			stage = StagePrimary
		}
	}

	bootstrapConfig := &Config{
		stage: stage,

		topLevelBlueprintsFile: flag.Arg(0),
		emptyNinjaFile:         emptyNinjaFile,
		runGoTests:             runGoTests,
		moduleListFile:         moduleListFile,
	}

	ctx.RegisterBottomUpMutator("bootstrap_plugin_deps", pluginDeps)
	ctx.RegisterModuleType("bootstrap_go_package", newGoPackageModuleFactory(bootstrapConfig))
	ctx.RegisterModuleType("bootstrap_go_binary", newGoBinaryModuleFactory(bootstrapConfig, false))
	ctx.RegisterModuleType("blueprint_go_binary", newGoBinaryModuleFactory(bootstrapConfig, true))
	ctx.RegisterSingletonType("bootstrap", newSingletonFactory(bootstrapConfig))

	ctx.RegisterSingletonType("glob", globSingletonFactory(ctx))

	deps, errs := ctx.ParseFileList(filepath.Dir(bootstrapConfig.topLevelBlueprintsFile), filesToParse, config)
	if len(errs) > 0 {
		fatalErrors(errs)
	}

	// Add extra ninja file dependencies
	deps = append(deps, extraNinjaFileDeps...)

	extraDeps, errs := ctx.ResolveDependencies(config)
	if len(errs) > 0 {
		fatalErrors(errs)
	}
	deps = append(deps, extraDeps...)

	if docFile != "" {
		err := writeDocs(ctx, absolutePath(docFile))
		if err != nil {
			fatalErrors([]error{err})
		}
		return
	}

	if c, ok := config.(ConfigStopBefore); ok {
		if c.StopBefore() == StopBeforePrepareBuildActions {
			return
		}
	}

	extraDeps, errs = ctx.PrepareBuildActions(config)
	if len(errs) > 0 {
		fatalErrors(errs)
	}
	deps = append(deps, extraDeps...)

	const outFilePermissions = 0666
	var out io.Writer
	var f *os.File
	var buf *bufio.Writer

	if stage != StageMain || !emptyNinjaFile {
		f, err = os.OpenFile(absolutePath(outFile), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, outFilePermissions)
		if err != nil {
			fatalf("error opening Ninja file: %s", err)
		}
		buf = bufio.NewWriter(f)
		out = buf
	} else {
		out = ioutil.Discard
	}

	if globFile != "" {
		buffer, errs := generateGlobNinjaFile(ctx.Globs)
		if len(errs) > 0 {
			fatalErrors(errs)
		}

		err = ioutil.WriteFile(absolutePath(globFile), buffer, outFilePermissions)
		if err != nil {
			fatalf("error writing %s: %s", globFile, err)
		}
	}

	if depFile != "" {
		err := deptools.WriteDepFile(absolutePath(depFile), outFile, deps)
		if err != nil {
			fatalf("error writing depfile: %s", err)
		}
	}

	err = ctx.WriteBuildFile(out)
	if err != nil {
		fatalf("error writing Ninja file contents: %s", err)
	}

	if buf != nil {
		err = buf.Flush()
		if err != nil {
			fatalf("error flushing Ninja file contents: %s", err)
		}
	}

	if f != nil {
		err = f.Close()
		if err != nil {
			fatalf("error closing Ninja file: %s", err)
		}
	}

	if c, ok := config.(ConfigRemoveAbandonedFilesUnder); ok {
		under, except := c.RemoveAbandonedFilesUnder()
		err := removeAbandonedFilesUnder(ctx, bootstrapConfig, SrcDir, under, except)
		if err != nil {
			fatalf("error removing abandoned files: %s", err)
		}
	}

	if memprofile != "" {
		f, err := os.Create(absolutePath(memprofile))
		if err != nil {
			fatalf("error opening memprofile: %s", err)
		}
		defer f.Close()
		pprof.WriteHeapProfile(f)
	}
}

func fatalf(format string, args ...interface{}) {
	fmt.Printf(format, args...)
	fmt.Print("\n")
	os.Exit(1)
}

func fatalErrors(errs []error) {
	red := "\x1b[31m"
	unred := "\x1b[0m"

	for _, err := range errs {
		switch err := err.(type) {
		case *blueprint.BlueprintError,
			*blueprint.ModuleError,
			*blueprint.PropertyError:
			fmt.Printf("%serror:%s %s\n", red, unred, err.Error())
		default:
			fmt.Printf("%sinternal error:%s %s\n", red, unred, err)
		}
	}
	os.Exit(1)
}

func absolutePath(path string) string {
	if filepath.IsAbs(path) {
		return path
	}
	return filepath.Join(absSrcDir, path)
}
<commit_msg>Actually write an empty ninja file with --empty-ninja-file<commit_after>// Copyright 2014 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package bootstrap

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"
	"runtime/debug"
	"runtime/pprof"
	"runtime/trace"

	"github.com/google/blueprint"
	"github.com/google/blueprint/deptools"
)

var (
	outFile        string
	globFile       string
	depFile        string
	docFile        string
	cpuprofile     string
	memprofile     string
	traceFile      string
	runGoTests     bool
	noGC           bool
	moduleListFile string
	emptyNinjaFile bool

	BuildDir      string
	NinjaBuildDir string
	SrcDir        string

	absSrcDir string
)

func init() {
	flag.StringVar(&outFile, "o", "build.ninja", "the Ninja file to output")
	flag.StringVar(&globFile, "globFile", "build-globs.ninja", "the Ninja file of globs to output")
	flag.StringVar(&BuildDir, "b", ".", "the build output directory")
	flag.StringVar(&NinjaBuildDir, "n", "", "the ninja builddir directory")
	flag.StringVar(&depFile, "d", "", "the dependency file to output")
	flag.StringVar(&docFile, "docs", "", "build documentation file to output")
	flag.StringVar(&cpuprofile, "cpuprofile", "", "write cpu profile to file")
	flag.StringVar(&traceFile, "trace", "", "write trace to file")
	flag.StringVar(&memprofile, "memprofile", "", "write memory profile to file")
	flag.BoolVar(&noGC, "nogc", false, "turn off GC for debugging")
	flag.BoolVar(&runGoTests, "t", false, "build and run go tests during bootstrap")
	flag.StringVar(&moduleListFile, "l", "", "file that lists filepaths to parse")
	flag.BoolVar(&emptyNinjaFile, "empty-ninja-file", false, "write out a 0-byte ninja file")
}

func Main(ctx *blueprint.Context, config interface{}, extraNinjaFileDeps ...string) {
	if !flag.Parsed() {
		flag.Parse()
	}

	runtime.GOMAXPROCS(runtime.NumCPU())

	if noGC {
		debug.SetGCPercent(-1)
	}

	absSrcDir = ctx.SrcDir()

	if cpuprofile != "" {
		f, err := os.Create(absolutePath(cpuprofile))
		if err != nil {
			fatalf("error opening cpuprofile: %s", err)
		}
		pprof.StartCPUProfile(f)
		defer f.Close()
		defer pprof.StopCPUProfile()
	}

	if traceFile != "" {
		f, err := os.Create(absolutePath(traceFile))
		if err != nil {
			fatalf("error opening trace: %s", err)
		}
		trace.Start(f)
		defer f.Close()
		defer trace.Stop()
	}

	if flag.NArg() != 1 {
		fatalf("no Blueprints file specified")
	}

	SrcDir = filepath.Dir(flag.Arg(0))
	if moduleListFile != "" {
		ctx.SetModuleListFile(moduleListFile)
		extraNinjaFileDeps = append(extraNinjaFileDeps, moduleListFile)
	} else {
		fatalf("-l <moduleListFile> is required and must be nonempty")
	}
	filesToParse, err := ctx.ListModulePaths(SrcDir)
	if err != nil {
		fatalf("could not enumerate files: %v\n", err.Error())
	}

	if NinjaBuildDir == "" {
		NinjaBuildDir = BuildDir
	}

	stage := StageMain
	if c, ok := config.(ConfigInterface); ok {
		if c.GeneratingPrimaryBuilder() {
			stage = StagePrimary
		}
	}

	bootstrapConfig := &Config{
		stage: stage,

		topLevelBlueprintsFile: flag.Arg(0),
		emptyNinjaFile:         emptyNinjaFile,
		runGoTests:             runGoTests,
		moduleListFile:         moduleListFile,
	}

	ctx.RegisterBottomUpMutator("bootstrap_plugin_deps", pluginDeps)
	ctx.RegisterModuleType("bootstrap_go_package", newGoPackageModuleFactory(bootstrapConfig))
	ctx.RegisterModuleType("bootstrap_go_binary", newGoBinaryModuleFactory(bootstrapConfig, false))
	ctx.RegisterModuleType("blueprint_go_binary", newGoBinaryModuleFactory(bootstrapConfig, true))
	ctx.RegisterSingletonType("bootstrap", newSingletonFactory(bootstrapConfig))

	ctx.RegisterSingletonType("glob", globSingletonFactory(ctx))

	deps, errs := ctx.ParseFileList(filepath.Dir(bootstrapConfig.topLevelBlueprintsFile), filesToParse, config)
	if len(errs) > 0 {
		fatalErrors(errs)
	}

	// Add extra ninja file dependencies
	deps = append(deps, extraNinjaFileDeps...)

	extraDeps, errs := ctx.ResolveDependencies(config)
	if len(errs) > 0 {
		fatalErrors(errs)
	}
	deps = append(deps, extraDeps...)

	if docFile != "" {
		err := writeDocs(ctx, absolutePath(docFile))
		if err != nil {
			fatalErrors([]error{err})
		}
		return
	}

	if c, ok := config.(ConfigStopBefore); ok {
		if c.StopBefore() == StopBeforePrepareBuildActions {
			return
		}
	}

	extraDeps, errs = ctx.PrepareBuildActions(config)
	if len(errs) > 0 {
		fatalErrors(errs)
	}
	deps = append(deps, extraDeps...)

	const outFilePermissions = 0666
	var out io.Writer
	var f *os.File
	var buf *bufio.Writer

	if emptyNinjaFile {
		if err := ioutil.WriteFile(absolutePath(outFile), []byte(nil), outFilePermissions); err != nil {
			fatalf("error writing empty Ninja file: %s", err)
		}
	}

	if stage != StageMain || !emptyNinjaFile {
		f, err = os.OpenFile(absolutePath(outFile), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, outFilePermissions)
		if err != nil {
			fatalf("error opening Ninja file: %s", err)
		}
		buf = bufio.NewWriter(f)
		out = buf
	} else {
		out = ioutil.Discard
	}

	if globFile != "" {
		buffer, errs := generateGlobNinjaFile(ctx.Globs)
		if len(errs) > 0 {
			fatalErrors(errs)
		}

		err = ioutil.WriteFile(absolutePath(globFile), buffer, outFilePermissions)
		if err != nil {
			fatalf("error writing %s: %s", globFile, err)
		}
	}

	if depFile != "" {
		err := deptools.WriteDepFile(absolutePath(depFile), outFile, deps)
		if err != nil {
			fatalf("error writing depfile: %s", err)
		}
	}

	err = ctx.WriteBuildFile(out)
	if err != nil {
		fatalf("error writing Ninja file contents: %s", err)
	}

	if buf != nil {
		err = buf.Flush()
		if err != nil {
			fatalf("error flushing Ninja file contents: %s", err)
		}
	}

	if f != nil {
		err = f.Close()
		if err != nil {
			fatalf("error closing Ninja file: %s", err)
		}
	}

	if c, ok := config.(ConfigRemoveAbandonedFilesUnder); ok {
		under, except := c.RemoveAbandonedFilesUnder()
		err := removeAbandonedFilesUnder(ctx, bootstrapConfig, SrcDir, under, except)
		if err != nil {
			fatalf("error removing abandoned files: %s", err)
		}
	}

	if memprofile != "" {
		f, err := os.Create(absolutePath(memprofile))
		if err != nil {
			fatalf("error opening memprofile: %s", err)
		}
		defer f.Close()
		pprof.WriteHeapProfile(f)
	}
}

func fatalf(format string, args ...interface{}) {
	fmt.Printf(format, args...)
	fmt.Print("\n")
	os.Exit(1)
}

func fatalErrors(errs []error) {
	red := "\x1b[31m"
	unred := "\x1b[0m"

	for _, err := range errs {
		switch err := err.(type) {
		case *blueprint.BlueprintError,
			*blueprint.ModuleError,
			*blueprint.PropertyError:
			fmt.Printf("%serror:%s %s\n", red, unred, err.Error())
		default:
			fmt.Printf("%sinternal error:%s %s\n", red, unred, err)
		}
	}
	os.Exit(1)
}

func absolutePath(path string) string {
	if filepath.IsAbs(path) {
		return path
	}
	return filepath.Join(absSrcDir, path)
}
<|endoftext|>


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

package server

import (
	"fmt"
	pather "github.com/andreaskoch/allmark/path"
	"io/ioutil"
	"net/http"
	"strings"
)

var itemHandler = func(w http.ResponseWriter, r *http.Request) {
	requestedPath := r.URL.Path
	requestedPath = strings.TrimLeft(requestedPath, "/")

	fmt.Printf("Requested route %q\n", requestedPath)

	filePath, ok := routes[requestedPath]
	if !ok {

		// check for fallbacks before returning a 404
		if fallbackRoute, fallbackRouteFound := getFallbackRoute(requestedPath); fallbackRouteFound {
			redirect(w, r, fallbackRoute)
			return
		}

		error404Handler(w, r)
		return
	}

	data, err := ioutil.ReadFile(filePath)
	if err != nil {
		error404Handler(w, r)
		return
	}

	fmt.Fprintf(w, "%s", data)
}

func getFallbackRoute(requestedPath string) (fallbackRoute string, found bool) {

	requestedPath = pather.StripLeadingUrlDirectorySeperator(requestedPath)

	if len(requestedPath) == 0 {
		fmt.Printf("Fallback for %q is %q\n", requestedPath, pather.WebServerDefaultFilename)
		return pather.WebServerDefaultFilename, true
	}

	if strings.HasSuffix(requestedPath, pather.WebServerDefaultFilename) {
		fmt.Printf("No fallback found for %q\n", requestedPath)
		return "", false
	}

	route := pather.CombineUrlComponents(requestedPath, pather.WebServerDefaultFilename)
	if _, ok := routes[route]; ok {
		fmt.Printf("Fallback for %q is %q\n", requestedPath, route)
		return route, true
	}

	fmt.Printf("No fallback found for %q\n", requestedPath)
	return "", false
}
<commit_msg>Calling request body close in the item handler (see: https://groups.google.com/d/topic/golang-nuts/K9e0tyfU2hY/discussion)<commit_after>// Copyright 2013 Andreas Koch. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package server

import (
	"fmt"
	pather "github.com/andreaskoch/allmark/path"
	"io/ioutil"
	"net/http"
	"strings"
)

var itemHandler = func(w http.ResponseWriter, r *http.Request) {
	requestedPath := r.URL.Path
	requestedPath = strings.TrimLeft(requestedPath, "/")

	fmt.Printf("Requested route %q\n", requestedPath)

	// make sure the request body is closed
	defer r.Body.Close()

	filePath, ok := routes[requestedPath]
	if !ok {

		// check for fallbacks before returning a 404
		if fallbackRoute, fallbackRouteFound := getFallbackRoute(requestedPath); fallbackRouteFound {
			redirect(w, r, fallbackRoute)
			return
		}

		error404Handler(w, r)
		return
	}

	data, err := ioutil.ReadFile(filePath)
	if err != nil {
		error404Handler(w, r)
		return
	}

	fmt.Fprintf(w, "%s", data)
}

func getFallbackRoute(requestedPath string) (fallbackRoute string, found bool) {

	requestedPath = pather.StripLeadingUrlDirectorySeperator(requestedPath)

	if len(requestedPath) == 0 {
		fmt.Printf("Fallback for %q is %q\n", requestedPath, pather.WebServerDefaultFilename)
		return pather.WebServerDefaultFilename, true
	}

	if strings.HasSuffix(requestedPath, pather.WebServerDefaultFilename) {
		fmt.Printf("No fallback found for %q\n", requestedPath)
		return "", false
	}

	route := pather.CombineUrlComponents(requestedPath, pather.WebServerDefaultFilename)
	if _, ok := routes[route]; ok {
		fmt.Printf("Fallback for %q is %q\n", requestedPath, route)
		return route, true
	}

	fmt.Printf("No fallback found for %q\n", requestedPath)
	return "", false
}
<|endoftext|>


<commit_before>package lib

import (
	"bytes"
	"crypto/tls"
	"encoding/json"
	"fmt"
	"github.com/BytemarkHosting/bytemark-client/util/log"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
)

// RequestAlreadyRunError is returned if the Run method was already called for this Request.
type RequestAlreadyRunError struct {
	Request *Request
}

// InsecureConnectionError is returned if the endpoint isn't https but AllowInsecure was not called.
type InsecureConnectionError struct {
	Request *Request
}

func (e RequestAlreadyRunError) Error() string {
	return "A Request was Run twice"
}

func (e InsecureConnectionError) Error() string {
	return "A Request to an insecure endpoint was attempted when AllowInsecure had not been called."
}

// Request is the workhorse of the bytemark-client/lib - it builds up a request, then Run can be called to get its results.
type Request struct {
	authenticate  bool
	client        Client
	endpoint      Endpoint
	url           *url.URL
	method        string
	body          []byte
	allowInsecure bool
	hasRun        bool
}

// GetURL returns the URL that the Request is for.
func (r *Request) GetURL() url.URL {
	if r.url == nil {
		return url.URL{}
	}
	return *r.url
}

// BuildRequestNoAuth creates a new Request with the intention of not authenticating.
func (c *bytemarkClient) BuildRequestNoAuth(method string, endpoint Endpoint, path string, parts ...string) (r *Request, err error) {
	url, err := c.BuildURL(endpoint, path, parts...)
	if err != nil {
		return
	}
	return &Request{
		client:        c,
		endpoint:      endpoint,
		url:           url,
		method:        method,
		allowInsecure: c.allowInsecure,
	}, nil
}

// BuildRequest builds a request that will be authenticated by the endpoint given.
func (c *bytemarkClient) BuildRequest(method string, endpoint Endpoint, path string, parts ...string) (r *Request, err error) {
	url, err := c.BuildURL(endpoint, path, parts...)
	if err != nil {
		return
	}
	return &Request{
		authenticate:  true,
		client:        c,
		endpoint:      endpoint,
		url:           url,
		method:        method,
		allowInsecure: c.allowInsecure,
	}, nil
}

// AllowInsecure tells the Request that it's ok if the endpoint isn't communicated with over HTTPS.
func (r *Request) AllowInsecure() {
	r.allowInsecure = true
}

// mkHTTPClient creates an http.Client for this request. If the staging endpoint is used, InsecureSkipVerify is used because I guess we don't have a good cert for that brain.
func (r *Request) mkHTTPClient() (c *http.Client) {
	c = new(http.Client)
	if r.url.Host == "staging.bigv.io" {
		c.Transport = &http.Transport{
			TLSClientConfig: &tls.Config{
				InsecureSkipVerify: true,
			},
		}
	}
	return c
}

// mkHTTPRequest assembles an http.Request for this Request, adding Authorization headers as needed, setting the Content-Type correctly for whichever endpoint it's talking to.
func (r *Request) mkHTTPRequest(body io.Reader) (req *http.Request, err error) {
	req, err = http.NewRequest(r.method, r.url.String(), body)
	if err != nil {
		return nil, err
	}
	req.Close = true
	req.Header.Add("User-Agent", "bytemark-client-"+Version)

	if r.endpoint == SPPEndpoint {
		req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
	} else {
		req.Header.Add("Accept", "application/json")
		req.Header.Add("Content-Type", "application/json")
	}
	if r.authenticate {
		if r.client.GetSessionToken() == "" {
			return nil, NilAuthError{}
		}
		// if we could settle on a single standard
		// rather than two basically-identical ones that'd be cool
		if r.endpoint == BillingEndpoint {
			req.Header.Add("Authorization", "Token token="+r.client.GetSessionToken())
		} else {
			req.Header.Add("Authorization", "Bearer "+r.client.GetSessionToken())
		}
	}
	return
}

// Run performs the request with the given body, and attempts to unmarshal a successful response into responseObject
func (r *Request) Run(body io.Reader, responseObject interface{}) (statusCode int, response []byte, err error) {
	if r.hasRun {
		err = RequestAlreadyRunError{r}
		return
	}
	r.hasRun = true

	if !r.allowInsecure && r.url.Scheme == "http" {
		err = InsecureConnectionError{r}
		return
	}
	var rb []byte
	if body != nil {

		rb, err = ioutil.ReadAll(body)
		if err != nil {
			return 0, nil, err
		}
		log.Debugf(log.LvlHTTPData, "request body: '%s'\r\n", string(rb))
	}

	cli := r.mkHTTPClient()

	req, err := r.mkHTTPRequest(bytes.NewBuffer(rb))
	if err != nil {
		return
	}
	if len(rb) > 0 {
		req.Header.Add("Content-Length", fmt.Sprintf("%d", len(rb)))
	}
	res, err := cli.Do(req)
	if err != nil {
		return
	}

	statusCode = res.StatusCode

	log.Debugf(log.LvlOutline, "%s %s: %d\r\n", r.method, req.URL, res.StatusCode)

	baseErr := APIError{
		Method:      r.method,
		URL:         req.URL,
		StatusCode:  res.StatusCode,
		RequestBody: string(rb),
	}

	response, err = ioutil.ReadAll(res.Body)
	log.Debugf(log.LvlHTTPData, "response body: '%s'\r\n", response)
	if err != nil {
		return
	}
	baseErr.ResponseBody = string(response)

	switch res.StatusCode {
	case 400:
		// because we need to reference fields specific to BadRequestError later
		err = newBadRequestError(baseErr, response)
	case 403:
		err = NotAuthorizedError{baseErr}
	case 404:
		err = NotFoundError{baseErr}
	case 500:
		err = InternalServerError{baseErr}
	case 503:
		err = ServiceUnavailableError{baseErr}
	default:
		if 200 <= res.StatusCode && res.StatusCode <= 299 {
			if responseObject != nil {
				jsonErr := json.Unmarshal(response, responseObject)
				if jsonErr != nil {
					return statusCode, response, jsonErr
				}
			}
			break
		}
		err = UnknownStatusCodeError{baseErr}
	}
	return
}

// BuildURL pieces together a URL from parts, escaping as necessary..
func (c *bytemarkClient) BuildURL(endpoint Endpoint, format string, args ...string) (*url.URL, error) {
	arr := make([]interface{}, len(args), len(args))
	for i, str := range args {
		arr[i] = url.QueryEscape(str)
	}
	endpointURL := ""
	switch endpoint {
	case BrainEndpoint:
		endpointURL = c.brainEndpoint
	case BillingEndpoint:
		endpointURL = c.billingEndpoint
	case SPPEndpoint:
		endpointURL = c.sppEndpoint
	default:
		return nil, UnsupportedEndpointError(endpoint)
	}
	if !strings.HasPrefix(format, "/") {
		return nil, UnsupportedEndpointError(-1)
	}
	return url.Parse(endpointURL + fmt.Sprintf(format, arr...))
}
<commit_msg>Disable gas linting for InsecureSkipVerify on staging.<commit_after>package lib

import (
	"bytes"
	"crypto/tls"
	"encoding/json"
	"fmt"
	"github.com/BytemarkHosting/bytemark-client/util/log"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
)

// RequestAlreadyRunError is returned if the Run method was already called for this Request.
type RequestAlreadyRunError struct {
	Request *Request
}

// InsecureConnectionError is returned if the endpoint isn't https but AllowInsecure was not called.
type InsecureConnectionError struct {
	Request *Request
}

func (e RequestAlreadyRunError) Error() string {
	return "A Request was Run twice"
}

func (e InsecureConnectionError) Error() string {
	return "A Request to an insecure endpoint was attempted when AllowInsecure had not been called."
}

// Request is the workhorse of the bytemark-client/lib - it builds up a request, then Run can be called to get its results.
type Request struct {
	authenticate  bool
	client        Client
	endpoint      Endpoint
	url           *url.URL
	method        string
	body          []byte
	allowInsecure bool
	hasRun        bool
}

// GetURL returns the URL that the Request is for.
func (r *Request) GetURL() url.URL {
	if r.url == nil {
		return url.URL{}
	}
	return *r.url
}

// BuildRequestNoAuth creates a new Request with the intention of not authenticating.
func (c *bytemarkClient) BuildRequestNoAuth(method string, endpoint Endpoint, path string, parts ...string) (r *Request, err error) {
	url, err := c.BuildURL(endpoint, path, parts...)
	if err != nil {
		return
	}
	return &Request{
		client:        c,
		endpoint:      endpoint,
		url:           url,
		method:        method,
		allowInsecure: c.allowInsecure,
	}, nil
}

// BuildRequest builds a request that will be authenticated by the endpoint given.
func (c *bytemarkClient) BuildRequest(method string, endpoint Endpoint, path string, parts ...string) (r *Request, err error) {
	url, err := c.BuildURL(endpoint, path, parts...)
	if err != nil {
		return
	}
	return &Request{
		authenticate:  true,
		client:        c,
		endpoint:      endpoint,
		url:           url,
		method:        method,
		allowInsecure: c.allowInsecure,
	}, nil
}

// AllowInsecure tells the Request that it's ok if the endpoint isn't communicated with over HTTPS.
func (r *Request) AllowInsecure() {
	r.allowInsecure = true
}

// mkHTTPClient creates an http.Client for this request. If the staging endpoint is used, InsecureSkipVerify is used because I guess we don't have a good cert for that brain.
func (r *Request) mkHTTPClient() (c *http.Client) {
	c = new(http.Client)
	if r.url.Host == "staging.bigv.io" {
		c.Transport = &http.Transport{
			// disable gas lint for this line (gas looks for insecure TLS settings, among other things)
			/* #nosec */
			TLSClientConfig: &tls.Config{
				InsecureSkipVerify: true,
			},
		}
	}
	return c
}

// mkHTTPRequest assembles an http.Request for this Request, adding Authorization headers as needed, setting the Content-Type correctly for whichever endpoint it's talking to.
func (r *Request) mkHTTPRequest(body io.Reader) (req *http.Request, err error) {
	req, err = http.NewRequest(r.method, r.url.String(), body)
	if err != nil {
		return nil, err
	}
	req.Close = true
	req.Header.Add("User-Agent", "bytemark-client-"+Version)

	if r.endpoint == SPPEndpoint {
		req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
	} else {
		req.Header.Add("Accept", "application/json")
		req.Header.Add("Content-Type", "application/json")
	}
	if r.authenticate {
		if r.client.GetSessionToken() == "" {
			return nil, NilAuthError{}
		}
		// if we could settle on a single standard
		// rather than two basically-identical ones that'd be cool
		if r.endpoint == BillingEndpoint {
			req.Header.Add("Authorization", "Token token="+r.client.GetSessionToken())
		} else {
			req.Header.Add("Authorization", "Bearer "+r.client.GetSessionToken())
		}
	}
	return
}

// Run performs the request with the given body, and attempts to unmarshal a successful response into responseObject
func (r *Request) Run(body io.Reader, responseObject interface{}) (statusCode int, response []byte, err error) {
	if r.hasRun {
		err = RequestAlreadyRunError{r}
		return
	}
	r.hasRun = true

	if !r.allowInsecure && r.url.Scheme == "http" {
		err = InsecureConnectionError{r}
		return
	}
	var rb []byte
	if body != nil {

		rb, err = ioutil.ReadAll(body)
		if err != nil {
			return 0, nil, err
		}
		log.Debugf(log.LvlHTTPData, "request body: '%s'\r\n", string(rb))
	}

	cli := r.mkHTTPClient()

	req, err := r.mkHTTPRequest(bytes.NewBuffer(rb))
	if err != nil {
		return
	}
	if len(rb) > 0 {
		req.Header.Add("Content-Length", fmt.Sprintf("%d", len(rb)))
	}
	res, err := cli.Do(req)
	if err != nil {
		return
	}

	statusCode = res.StatusCode

	log.Debugf(log.LvlOutline, "%s %s: %d\r\n", r.method, req.URL, res.StatusCode)

	baseErr := APIError{
		Method:      r.method,
		URL:         req.URL,
		StatusCode:  res.StatusCode,
		RequestBody: string(rb),
	}

	response, err = ioutil.ReadAll(res.Body)
	log.Debugf(log.LvlHTTPData, "response body: '%s'\r\n", response)
	if err != nil {
		return
	}
	baseErr.ResponseBody = string(response)

	switch res.StatusCode {
	case 400:
		// because we need to reference fields specific to BadRequestError later
		err = newBadRequestError(baseErr, response)
	case 403:
		err = NotAuthorizedError{baseErr}
	case 404:
		err = NotFoundError{baseErr}
	case 500:
		err = InternalServerError{baseErr}
	case 503:
		err = ServiceUnavailableError{baseErr}
	default:
		if 200 <= res.StatusCode && res.StatusCode <= 299 {
			if responseObject != nil {
				jsonErr := json.Unmarshal(response, responseObject)
				if jsonErr != nil {
					return statusCode, response, jsonErr
				}
			}
			break
		}
		err = UnknownStatusCodeError{baseErr}
	}
	return
}

// BuildURL pieces together a URL from parts, escaping as necessary..
func (c *bytemarkClient) BuildURL(endpoint Endpoint, format string, args ...string) (*url.URL, error) {
	arr := make([]interface{}, len(args), len(args))
	for i, str := range args {
		arr[i] = url.QueryEscape(str)
	}
	endpointURL := ""
	switch endpoint {
	case BrainEndpoint:
		endpointURL = c.brainEndpoint
	case BillingEndpoint:
		endpointURL = c.billingEndpoint
	case SPPEndpoint:
		endpointURL = c.sppEndpoint
	default:
		return nil, UnsupportedEndpointError(endpoint)
	}
	if !strings.HasPrefix(format, "/") {
		return nil, UnsupportedEndpointError(-1)
	}
	return url.Parse(endpointURL + fmt.Sprintf(format, arr...))
}
<|endoftext|>


<commit_before>package bahn // import "github.com/octo/icestat/bahn"

import (
	"encoding/json"
	"net/http"
	"strconv"
	"time"
)

// PositionURL is the URL of JSONP-encoded information about the train's location and speed.
const PositionURL = "http://www.ombord.info/api/jsonp/position/"

// Position holds the position of the train as well as some other GPS related
// data (speed, #satellites, ...).
type Position struct {
	Version   string
	Time      time.Time
	Latitude  float64
	Longitude float64
	Altitude  float64
	// Speed in km/h.
	Speed      float64
	Satellites int
}

// quotedFloat64 helps parsing quoted strings as floats.
type quotedFloat64 float64

func (f *quotedFloat64) UnmarshalText(text []byte) error {
	parsed, err := strconv.ParseFloat(string(text), 64)
	if err != nil {
		return err
	}

	*f = quotedFloat64(parsed)
	return nil
}

// quotedInt helps parsing quoted strings as ints.
type quotedInt int

func (i *quotedInt) UnmarshalText(text []byte) error {
	parsed, err := strconv.ParseInt(string(text), 0, 0)
	if err != nil {
		return err
	}

	*i = quotedInt(parsed)
	return nil
}

// UnmarshalJSON implements the encoding/json.Unmarshaler interface.
func (p *Position) UnmarshalJSON(b []byte) error {
	var parsed struct {
		Version   string
		Time      quotedInt
		Age       string
		Latitude  quotedFloat64
		Longitude quotedFloat64
		Altitude  quotedFloat64
		// Speed in m/s.
		Speed quotedFloat64
		// Gyroskop?
		CMG        string
		Satellites quotedInt
		Mode       string
	}
	if err := json.Unmarshal(b, &parsed); err != nil {
		return err
	}

	*p = Position{
		Version:   parsed.Version,
		Time:      time.Unix(int64(parsed.Time), 0),
		Latitude:  float64(parsed.Latitude),
		Longitude: float64(parsed.Longitude),
		Altitude:  float64(parsed.Altitude),
		// convert speed from m/s to km/h
		Speed:      float64(parsed.Speed) * 3600.0 / 1000.0,
		Satellites: int(parsed.Satellites),
	}
	return nil
}

// PositionInfo returns information about the train's position and speed.
func PositionInfo() (*Position, error) {
	res, err := http.Get(PositionURL)
	if err != nil {
		return nil, err
	}

	var p Position
	if err := unmarshalJSONP(res.Body, &p); err != nil {
		return nil, err
	}
	return &p, nil
}
<commit_msg>Package bahn: Remove the quoted{Int,Float64} helper classes.<commit_after>package bahn // import "github.com/octo/icestat/bahn"

import (
	"encoding/json"
	"net/http"
	"time"
)

// PositionURL is the URL of JSONP-encoded information about the train's location and speed.
const PositionURL = "http://www.ombord.info/api/jsonp/position/"

// Position holds the position of the train as well as some other GPS related
// data (speed, #satellites, ...).
type Position struct {
	Version   string
	Time      time.Time
	Latitude  float64
	Longitude float64
	Altitude  float64
	// Speed in km/h.
	Speed      float64
	Satellites int
}

// UnmarshalJSON implements the encoding/json.Unmarshaler interface.
func (p *Position) UnmarshalJSON(b []byte) error {
	var parsed struct {
		Version   string
		Time      int `json:",string"`
		Age       string
		Latitude  float64 `json:",string"`
		Longitude float64 `json:",string"`
		Altitude  float64 `json:",string"`
		// Speed in m/s.
		Speed float64 `json:",string"`
		// Gyroskop?
		CMG        string
		Satellites int `json:",string"`
		Mode       string
	}
	if err := json.Unmarshal(b, &parsed); err != nil {
		return err
	}

	*p = Position{
		Version:   parsed.Version,
		Time:      time.Unix(int64(parsed.Time), 0),
		Latitude:  float64(parsed.Latitude),
		Longitude: float64(parsed.Longitude),
		Altitude:  float64(parsed.Altitude),
		// convert speed from m/s to km/h
		Speed:      float64(parsed.Speed) * 3600.0 / 1000.0,
		Satellites: int(parsed.Satellites),
	}
	return nil
}

// PositionInfo returns information about the train's position and speed.
func PositionInfo() (*Position, error) {
	res, err := http.Get(PositionURL)
	if err != nil {
		return nil, err
	}

	var p Position
	if err := unmarshalJSONP(res.Body, &p); err != nil {
		return nil, err
	}
	return &p, nil
}
<|endoftext|>


<commit_before>package morganfield

import "testing"
import "fmt"

type SimpleStruct struct {
	Username string `json:"username"`
}

type SimpleIntegerStruct struct {
	Number1 int `json:"number1"`
	Number2 int `json:"number2"`
	Number3 int `json:"number3"`
}

type SimpleFloatStruct struct {
	Number1 float64 `json:"number1"`
}

// Go's JSON parser will not parse anything with missing brackets
func Test_missing_end_bracket(t *testing.T) {
	instr := "{\"username\": \"test\""
	_, err := UnMarshal(instr, &SimpleStruct{})
	if err == nil {
		t.Error("Test_missing_end_bracket parsed input with missing end bracket!")
	}
}

// Go's JSON parser does not parse unquoted keys
func Test_unquoted_key(t *testing.T) {
	instr := "{ username: justme }"
	_, err := UnMarshal(instr, &SimpleStruct{})
	if err == nil {
		t.Error("Test_unquoted_key parsed unquoted key")
	}
}

// Go's JSON parser does not parse unquoted values
func Test_unquoted_value(t *testing.T) {
	instr := "{ \"username\": justme }"
	_, err := UnMarshal(instr, &SimpleStruct{})
	if err == nil {
		t.Error("Test_unquoted_value parsed unquoted value")
	}
}

// Go's JSON parser does not parse empty input
func Test_whitespace(t *testing.T) {
	instr := "       "
	_, err := UnMarshal(instr, &SimpleStruct{})
	if err == nil {
		t.Error("Test_whitespace parsed empty input")
	}
}

// Go's JSON parser does not parse single quotes
func Test_single_quote(t *testing.T) {
	instr := "{'username':'admin'}"
	_, err := UnMarshal(instr, &SimpleStruct{})
	if err == nil {
		t.Error("Test_single_quote parsed single quotes")
	}
}

// Go's JSON parses converts both hex and octal escapes
func Test_escapes(t *testing.T) {
	// First hex, then octal escape
	instr := "{\"username\":\"test\x61test\141\"}"
	k, err := UnMarshal(instr, &SimpleStruct{})
	if err != nil {
		t.Error(fmt.Sprintf("Test_escapes UnMarshal: %v", err))
	}

	i, err := Marshal(k)
	if err != nil {
		t.Error(fmt.Sprintf("Test_escapes Marshal: %v", err))
	}

	if i != "{\"username\":\"testatesta\"}" {
		t.Error("Test_escapes was not able to convert escapes correctly")
	}
}

// Go's JSON parser will not allow comments
func Test_comments(t *testing.T) {
	instr := "{\n//Comment 1\n\"username\":\"test\"//Comment2\n}"
	_, err := UnMarshal(instr, &SimpleStruct{})
	if err == nil {
		t.Error("Test_comments parsed comments")
	}
}

// Go's JSON parser does not parse Hex or integer literals
func Test_integer_literals(t *testing.T) {
	instr1 := "{ \"number1\": 0xAB}"
	_, err := UnMarshal(instr1, &SimpleIntegerStruct{})
	if err == nil {
		t.Error("Test_integer_literals parsed hex integer literal")
	}

	instr2 := "{ \"number1\": 012 }"
	_, err = UnMarshal(instr2, &SimpleIntegerStruct{})
	if err == nil {
		t.Error("Test_integer_literals parsed octal integer literal")
	}
}

// -0.5 : ok
// +0.5 : fail
//  0.5 : ok
//   .5 : fail
//  +.5 : fail
//  -.5 : fail
func Test_decimal_numbers(t *testing.T) {
	// -0.5 is fine
	instr := "{ \"number1\": -0.5}"
	_, err := UnMarshal(instr, &SimpleFloatStruct{})
	if err != nil {
		t.Error(err)
	}

	instr = "{ \"number1\": +0.5}"
	_, err = UnMarshal(instr, &SimpleFloatStruct{})
	if err == nil {
		t.Error("Test_decimal_numbers parsed +0.5")
	}

	instr = "{ \"number1\": 0.5}"
	_, err = UnMarshal(instr, &SimpleFloatStruct{})
	if err != nil {
		t.Error(err)
	}

	instr = "{ \"number1\": .5}"
	_, err = UnMarshal(instr, &SimpleFloatStruct{})
	if err == nil {
		t.Error("Test_decimal_numbers parsed .5")
	}

	instr = "{ \"number1\": +.5}"
	_, err = UnMarshal(instr, &SimpleFloatStruct{})
	if err == nil {
		t.Error("Test_decimal_numbers parsed +.5")
	}

	instr = "{ \"number1\": -.5}"
	_, err = UnMarshal(instr, &SimpleFloatStruct{})
	if err == nil {
		t.Error("Test_decimal_numbers parsed -.5")
	}
}

// Go's JSON parser does not allow ellisions
func Test_ellisions(t *testing.T) {
	instr := "{ \"number1\": 10,,\"number2\": 20}"
	_, err := UnMarshal(instr, &SimpleIntegerStruct{})
	if err == nil {
		t.Error("Test_ellisions parsed ellision")
	}
}

// Go's JSON parser does not allow trailing commas
func Test_trailing_commas(t *testing.T) {
	instr := "{ \"number1\": 10,\"number2\": 20,}"
	_, err := UnMarshal(instr, &SimpleIntegerStruct{})
	if err == nil {
		t.Error("Test_trailing_commas parsed trailing comma")
	}
}

func Test_grouping_parenthesss(t *testing.T) {
	instr := "{ (\"number1\": 10,\"number2\": 20) }"
	_, err := UnMarshal(instr, &SimpleIntegerStruct{})
	if err == nil {
		t.Error("Test_trailing_commas parsed grouping parentheses")
	}
}

// Extra elements get silently removed
func Test_extra_element(t *testing.T) {
	instr := "{ \"number1\": 10,\"duck\":5,\"number2\": 20 }"
	_, err := UnMarshal(instr, &SimpleIntegerStruct{})
	if err != nil {
		t.Error(err)
	}
}

// Missing elements return default value
func Test_missing_element(t *testing.T) {
	instr := "{ \"number1\": 10,\"duck\":5,\"number2\": 20 }"
	k, err := UnMarshal(instr, &SimpleIntegerStruct{})
	if err != nil {
		t.Error(err)
	}

	x := k.(*SimpleIntegerStruct)
	if x.Number3 != 0 {
		t.Error("Test_missing_element: Number3 was not 0")
	}
}
<commit_msg>Simple test for handling unquoted boolean value<commit_after>package morganfield

import "testing"
import "fmt"

type SimpleStruct struct {
	Username string `json:"username"`
}

type SimpleBooleanStruct struct {
	Testbool bool `json:"testboolean"`
}

type SimpleIntegerStruct struct {
	Number1 int `json:"number1"`
	Number2 int `json:"number2"`
	Number3 int `json:"number3"`
}

type SimpleFloatStruct struct {
	Number1 float64 `json:"number1"`
}

// Go's JSON parser parses unquoted booleans
func Test_bool_handling(t *testing.T) {
	instr := "{\"testboolean\": true}"
	inobj := SimpleBooleanStruct{}
	_, err := UnMarshal(instr, &inobj)
	if err != nil || inobj.Testbool == false {
		t.Errorf("Test_bool_handling failed to parse boolean!")
	}
}

// Go's JSON parser will not parse anything with missing brackets
func Test_missing_end_bracket(t *testing.T) {
	instr := "{\"username\": \"test\""
	_, err := UnMarshal(instr, &SimpleStruct{})
	if err == nil {
		t.Error("Test_missing_end_bracket parsed input with missing end bracket!")
	}
}

// Go's JSON parser does not parse unquoted keys
func Test_unquoted_key(t *testing.T) {
	instr := "{ username: justme }"
	_, err := UnMarshal(instr, &SimpleStruct{})
	if err == nil {
		t.Error("Test_unquoted_key parsed unquoted key")
	}
}

// Go's JSON parser does not parse unquoted values
func Test_unquoted_value(t *testing.T) {
	instr := "{ \"username\": justme }"
	_, err := UnMarshal(instr, &SimpleStruct{})
	if err == nil {
		t.Error("Test_unquoted_value parsed unquoted value")
	}
}

// Go's JSON parser does not parse empty input
func Test_whitespace(t *testing.T) {
	instr := "       "
	_, err := UnMarshal(instr, &SimpleStruct{})
	if err == nil {
		t.Error("Test_whitespace parsed empty input")
	}
}

// Go's JSON parser does not parse single quotes
func Test_single_quote(t *testing.T) {
	instr := "{'username':'admin'}"
	_, err := UnMarshal(instr, &SimpleStruct{})
	if err == nil {
		t.Error("Test_single_quote parsed single quotes")
	}
}

// Go's JSON parses converts both hex and octal escapes
func Test_escapes(t *testing.T) {
	// First hex, then octal escape
	instr := "{\"username\":\"test\x61test\141\"}"
	k, err := UnMarshal(instr, &SimpleStruct{})
	if err != nil {
		t.Error(fmt.Sprintf("Test_escapes UnMarshal: %v", err))
	}

	i, err := Marshal(k)
	if err != nil {
		t.Error(fmt.Sprintf("Test_escapes Marshal: %v", err))
	}

	if i != "{\"username\":\"testatesta\"}" {
		t.Error("Test_escapes was not able to convert escapes correctly")
	}
}

// Go's JSON parser will not allow comments
func Test_comments(t *testing.T) {
	instr := "{\n//Comment 1\n\"username\":\"test\"//Comment2\n}"
	_, err := UnMarshal(instr, &SimpleStruct{})
	if err == nil {
		t.Error("Test_comments parsed comments")
	}
}

// Go's JSON parser does not parse Hex or integer literals
func Test_integer_literals(t *testing.T) {
	instr1 := "{ \"number1\": 0xAB}"
	_, err := UnMarshal(instr1, &SimpleIntegerStruct{})
	if err == nil {
		t.Error("Test_integer_literals parsed hex integer literal")
	}

	instr2 := "{ \"number1\": 012 }"
	_, err = UnMarshal(instr2, &SimpleIntegerStruct{})
	if err == nil {
		t.Error("Test_integer_literals parsed octal integer literal")
	}
}

// -0.5 : ok
// +0.5 : fail
//  0.5 : ok
//   .5 : fail
//  +.5 : fail
//  -.5 : fail
func Test_decimal_numbers(t *testing.T) {
	// -0.5 is fine
	instr := "{ \"number1\": -0.5}"
	_, err := UnMarshal(instr, &SimpleFloatStruct{})
	if err != nil {
		t.Error(err)
	}

	instr = "{ \"number1\": +0.5}"
	_, err = UnMarshal(instr, &SimpleFloatStruct{})
	if err == nil {
		t.Error("Test_decimal_numbers parsed +0.5")
	}

	instr = "{ \"number1\": 0.5}"
	_, err = UnMarshal(instr, &SimpleFloatStruct{})
	if err != nil {
		t.Error(err)
	}

	instr = "{ \"number1\": .5}"
	_, err = UnMarshal(instr, &SimpleFloatStruct{})
	if err == nil {
		t.Error("Test_decimal_numbers parsed .5")
	}

	instr = "{ \"number1\": +.5}"
	_, err = UnMarshal(instr, &SimpleFloatStruct{})
	if err == nil {
		t.Error("Test_decimal_numbers parsed +.5")
	}

	instr = "{ \"number1\": -.5}"
	_, err = UnMarshal(instr, &SimpleFloatStruct{})
	if err == nil {
		t.Error("Test_decimal_numbers parsed -.5")
	}
}

// Go's JSON parser does not allow ellisions
func Test_ellisions(t *testing.T) {
	instr := "{ \"number1\": 10,,\"number2\": 20}"
	_, err := UnMarshal(instr, &SimpleIntegerStruct{})
	if err == nil {
		t.Error("Test_ellisions parsed ellision")
	}
}

// Go's JSON parser does not allow trailing commas
func Test_trailing_commas(t *testing.T) {
	instr := "{ \"number1\": 10,\"number2\": 20,}"
	_, err := UnMarshal(instr, &SimpleIntegerStruct{})
	if err == nil {
		t.Error("Test_trailing_commas parsed trailing comma")
	}
}

func Test_grouping_parenthesss(t *testing.T) {
	instr := "{ (\"number1\": 10,\"number2\": 20) }"
	_, err := UnMarshal(instr, &SimpleIntegerStruct{})
	if err == nil {
		t.Error("Test_trailing_commas parsed grouping parentheses")
	}
}

// Extra elements get silently removed
func Test_extra_element(t *testing.T) {
	instr := "{ \"number1\": 10,\"duck\":5,\"number2\": 20 }"
	_, err := UnMarshal(instr, &SimpleIntegerStruct{})
	if err != nil {
		t.Error(err)
	}
}

// Missing elements return default value
func Test_missing_element(t *testing.T) {
	instr := "{ \"number1\": 10,\"duck\":5,\"number2\": 20 }"
	k, err := UnMarshal(instr, &SimpleIntegerStruct{})
	if err != nil {
		t.Error(err)
	}

	x := k.(*SimpleIntegerStruct)
	if x.Number3 != 0 {
		t.Error("Test_missing_element: Number3 was not 0")
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io"
	"os"
	"path"
	"strings"
	"sync"
	"time"

	"github.com/coreos/fleet/third_party/github.com/codegangsta/cli"

	"github.com/coreos/fleet/job"
	"github.com/coreos/fleet/sign"
)

const (
	unitCheckInterval = 1 * time.Second
)

func newStartUnitCommand() cli.Command {
	return cli.Command{
		Name:  "start",
		Usage: "Schedule and execute one or more units in the cluster",
		Description: `Start one or many units on the cluster. Select units to start by glob matching
for units in the current working directory or matching names of previously
submitted units.

Start a single unit:
fleetctl start foo.service

Start an entire directory of units with glob matching:
fleetctl start myservice/*

You may filter suitable hosts based on metadata provided by the machine.
Machine metadata is located in the fleet configuration file.

Start a unit on any "us-east" machine:
fleetctl start --require region=us-east foo.service`,
		Flags: []cli.Flag{
			cli.StringFlag{"require", "", "Filter suitable hosts with a set of requirements. Format is comma-delimited list of <key>=<value> pairs."},
			cli.BoolFlag{"sign", "Sign unit file signatures using local SSH identities"},
			cli.BoolFlag{"verify", "Verify unit file signatures using local SSH identities"},
			cli.IntFlag{"block-attempts", 10, "Wait until the jobs are scheduled. Perform N attempts before giving up, 10 by default."},
			cli.BoolFlag{"no-block", "Do not wait until the units have been scheduled to exit start."},
		},
		Action: startUnitAction,
	}
}

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

	// If signing is explicitly set to on, verification will be done also.
	toSign := c.Bool("sign")
	var sc *sign.SignatureCreator
	var sv *sign.SignatureVerifier
	if toSign {
		var err error
		sc, err = sign.NewSignatureCreatorFromSSHAgent()
		if err != nil {
			fmt.Fprintf(os.Stderr, "Failed creating SignatureCreator: %v\n", err)
			os.Exit(1)
		}
		sv, err = sign.NewSignatureVerifierFromSSHAgent()
		if err != nil {
			fmt.Fprintf(os.Stderr, "Failed creating SignatureVerifier: %v\n", err)
			os.Exit(1)
		}
	}

	payloads := make([]job.JobPayload, len(c.Args()))
	for i, v := range c.Args() {
		name := path.Base(v)
		payload := registryCtl.GetPayload(name)
		if payload == nil {
			payload, err = getJobPayloadFromFile(v)
			if err != nil {
				fmt.Println(err.Error())
				os.Exit(1)
			}

			err = registryCtl.CreatePayload(payload)
			if err != nil {
				fmt.Fprintf(os.Stderr, "Failed creating payload %s: %v\n", payload.Name, err)
				os.Exit(1)
			}
			if toSign {
				s, err := sc.SignPayload(payload)
				if err != nil {
					fmt.Fprintf(os.Stderr, "Failed creating sign for payload %s: %v\n", payload.Name, err)
					os.Exit(1)
				}
				registryCtl.CreateSignatureSet(s)
			}
		}
		if toSign {
			s := registryCtl.GetSignatureSetOfPayload(name)
			ok, err := sv.VerifyPayload(payload, s)
			if !ok || err != nil {
				fmt.Fprintf(os.Stderr, "Failed checking payload %s: %v\n", payload.Name, err)
				os.Exit(1)
			}
		}

		payloads[i] = *payload
	}

	requirements := parseRequirements(c.String("require"))

	// TODO: This must be done in a transaction!
	registeredJobs := make(map[string]bool)
	for _, jp := range payloads {
		j := job.NewJob(jp.Name, requirements, &jp, nil)
		err := registryCtl.CreateJob(j)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Failed creating job %s: %v\n", j.Name, err)
			os.Exit(1)
		}
		registeredJobs[j.Name] = true
	}

	if !c.Bool("no-block") {
		waitForScheduledUnits(registeredJobs, c.Int("block-attempts"), os.Stdout)
	}
}

func parseRequirements(arg string) map[string][]string {
	reqs := make(map[string][]string, 0)

	add := func(key, val string) {
		vals, ok := reqs[key]
		if !ok {
			vals = make([]string, 0)
			reqs[key] = vals
		}
		vals = append(vals, val)
		reqs[key] = vals
	}

	for _, pair := range strings.Split(arg, ",") {
		parts := strings.SplitN(pair, "=", 2)
		if len(parts) != 2 {
			continue
		}

		key := fmt.Sprintf("MachineMetadata%s", strings.TrimSpace(parts[0]))
		val := strings.TrimSpace(parts[1])
		add(key, val)
	}

	return reqs
}

func waitForScheduledUnits(jobs map[string]bool, maxAttempts int, out io.Writer) {
	var wg sync.WaitGroup

	for jobName, _ := range jobs {
		wg.Add(1)
		go checkJobTarget(jobName, maxAttempts, out, &wg)
	}

	wg.Wait()
}

func checkJobTarget(jobName string, maxAttempts int, out io.Writer, wg *sync.WaitGroup) {
	defer wg.Done()

	for attempts := 0; attempts < maxAttempts; attempts++ {
		ms := registryCtl.GetJobTarget(jobName)

		if ms != nil {
			m := registryCtl.GetMachineState(ms.BootID)
			fmt.Fprintf(out, "Job %s started on %s\n", jobName, machineFullLegend(*m, false))
			return
		}

		time.Sleep(unitCheckInterval)
	}
	fmt.Fprintf(out, "Job %s in queue to be scheduled\n", jobName)
}
<commit_msg>fix(fleetctl): tweak wording of blocking start output<commit_after>package main

import (
	"fmt"
	"io"
	"os"
	"path"
	"strings"
	"sync"
	"time"

	"github.com/coreos/fleet/third_party/github.com/codegangsta/cli"

	"github.com/coreos/fleet/job"
	"github.com/coreos/fleet/sign"
)

const (
	unitCheckInterval = 1 * time.Second
)

func newStartUnitCommand() cli.Command {
	return cli.Command{
		Name:  "start",
		Usage: "Schedule and execute one or more units in the cluster",
		Description: `Start one or many units on the cluster. Select units to start by glob matching
for units in the current working directory or matching names of previously
submitted units.

Start a single unit:
fleetctl start foo.service

Start an entire directory of units with glob matching:
fleetctl start myservice/*

You may filter suitable hosts based on metadata provided by the machine.
Machine metadata is located in the fleet configuration file.

Start a unit on any "us-east" machine:
fleetctl start --require region=us-east foo.service`,
		Flags: []cli.Flag{
			cli.StringFlag{"require", "", "Filter suitable hosts with a set of requirements. Format is comma-delimited list of <key>=<value> pairs."},
			cli.BoolFlag{"sign", "Sign unit file signatures using local SSH identities"},
			cli.BoolFlag{"verify", "Verify unit file signatures using local SSH identities"},
			cli.IntFlag{"block-attempts", 10, "Wait until the jobs are scheduled. Perform N attempts before giving up, 10 by default."},
			cli.BoolFlag{"no-block", "Do not wait until the units have been scheduled to exit start."},
		},
		Action: startUnitAction,
	}
}

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

	// If signing is explicitly set to on, verification will be done also.
	toSign := c.Bool("sign")
	var sc *sign.SignatureCreator
	var sv *sign.SignatureVerifier
	if toSign {
		var err error
		sc, err = sign.NewSignatureCreatorFromSSHAgent()
		if err != nil {
			fmt.Fprintf(os.Stderr, "Failed creating SignatureCreator: %v\n", err)
			os.Exit(1)
		}
		sv, err = sign.NewSignatureVerifierFromSSHAgent()
		if err != nil {
			fmt.Fprintf(os.Stderr, "Failed creating SignatureVerifier: %v\n", err)
			os.Exit(1)
		}
	}

	payloads := make([]job.JobPayload, len(c.Args()))
	for i, v := range c.Args() {
		name := path.Base(v)
		payload := registryCtl.GetPayload(name)
		if payload == nil {
			payload, err = getJobPayloadFromFile(v)
			if err != nil {
				fmt.Println(err.Error())
				os.Exit(1)
			}

			err = registryCtl.CreatePayload(payload)
			if err != nil {
				fmt.Fprintf(os.Stderr, "Failed creating payload %s: %v\n", payload.Name, err)
				os.Exit(1)
			}
			if toSign {
				s, err := sc.SignPayload(payload)
				if err != nil {
					fmt.Fprintf(os.Stderr, "Failed creating sign for payload %s: %v\n", payload.Name, err)
					os.Exit(1)
				}
				registryCtl.CreateSignatureSet(s)
			}
		}
		if toSign {
			s := registryCtl.GetSignatureSetOfPayload(name)
			ok, err := sv.VerifyPayload(payload, s)
			if !ok || err != nil {
				fmt.Fprintf(os.Stderr, "Failed checking payload %s: %v\n", payload.Name, err)
				os.Exit(1)
			}
		}

		payloads[i] = *payload
	}

	requirements := parseRequirements(c.String("require"))

	// TODO: This must be done in a transaction!
	registeredJobs := make(map[string]bool)
	for _, jp := range payloads {
		j := job.NewJob(jp.Name, requirements, &jp, nil)
		err := registryCtl.CreateJob(j)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Failed creating job %s: %v\n", j.Name, err)
			os.Exit(1)
		}
		registeredJobs[j.Name] = true
	}

	if !c.Bool("no-block") {
		waitForScheduledUnits(registeredJobs, c.Int("block-attempts"), os.Stdout)
	}
}

func parseRequirements(arg string) map[string][]string {
	reqs := make(map[string][]string, 0)

	add := func(key, val string) {
		vals, ok := reqs[key]
		if !ok {
			vals = make([]string, 0)
			reqs[key] = vals
		}
		vals = append(vals, val)
		reqs[key] = vals
	}

	for _, pair := range strings.Split(arg, ",") {
		parts := strings.SplitN(pair, "=", 2)
		if len(parts) != 2 {
			continue
		}

		key := fmt.Sprintf("MachineMetadata%s", strings.TrimSpace(parts[0]))
		val := strings.TrimSpace(parts[1])
		add(key, val)
	}

	return reqs
}

func waitForScheduledUnits(jobs map[string]bool, maxAttempts int, out io.Writer) {
	var wg sync.WaitGroup

	for jobName, _ := range jobs {
		wg.Add(1)
		go checkJobTarget(jobName, maxAttempts, out, &wg)
	}

	wg.Wait()
}

func checkJobTarget(jobName string, maxAttempts int, out io.Writer, wg *sync.WaitGroup) {
	defer wg.Done()

	for attempts := 0; attempts < maxAttempts; attempts++ {
		ms := registryCtl.GetJobTarget(jobName)

		if ms != nil {
			m := registryCtl.GetMachineState(ms.BootID)
			fmt.Fprintf(out, "Job %s scheduled to %s\n", jobName, machineFullLegend(*m, false))
			return
		}

		time.Sleep(unitCheckInterval)
	}
	fmt.Fprintf(out, "Job %s still queued for scheduling\n", jobName)
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// 	https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package hsts

import (
	"strconv"
	"strings"

	"github.com/google/go-safeweb/safehttp"
)

// Plugin implements automatic HSTS functionality.
type Plugin struct {
	maxAge            uint64
	includeSubDomains bool
	preload           bool
}

// NewPlugin creates a new HSTS plugin with safe defaults.
func NewPlugin() Plugin {
	return Plugin{
		maxAge:            63072000, // two years in seconds
		includeSubDomains: true,
		preload:           false,
	}
}

// Before should be executed before the request is sent to the handler.
// The function redirects HTTP requests to HTTPS. When HTTPS traffic
// is received the Strict-Transport-Security header is applied to the
// response.
func (p *Plugin) Before(w safehttp.ResponseWriter, r *safehttp.IncomingRequest) safehttp.Result {
	if r.TLS == nil {
		r.URL.Scheme = "https"
		return w.Redirect(r, r.URL.String(), safehttp.StatusMovedPermanently)
	}

	var value strings.Builder
	value.WriteString("max-age=")
	value.WriteString(strconv.FormatUint(p.maxAge, 10))
	if p.includeSubDomains {
		value.WriteString("; includeSubDomains")
	}
	if p.preload {
		value.WriteString("; preload")
	}
	h := w.Header()
	if err := h.Set("Strict-Transport-Security", value.String()); err != nil {
		// TODO(@mattiasgrenfeldt): Replace the response with an actual saferesponse somehow.
		return w.ServerError(safehttp.StatusInternalServerError, "Internal Server Error")
	}
	// TODO: Implement header claiming.
	h.MarkImmutable("Strict-Transport-Security")
	return safehttp.Result{}
}

// EnablePreload enables the preload directive.
// This should only be enabled if this site should be
// added to the browser HSTS preload list which is supported
// by all major browsers. See https://hstspreload.org/ for
// more info.
func (p *Plugin) EnablePreload() {
	p.preload = true
}

// DisableIncludeSubDomains disables the includeSubDomains
// directive. When includeSubDomains is enabled, all subdomains
// of the domain where this service is hosted will also be added
// to the browsers HSTS list. This method disables this feature.
func (p *Plugin) DisableIncludeSubDomains() {
	p.includeSubDomains = false
}
<commit_msg>Removed setters, simplified constructor<commit_after>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// 	https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package hsts

import (
	"strconv"
	"strings"

	"github.com/google/go-safeweb/safehttp"
)

// Plugin implements automatic HSTS functionality.
type Plugin struct {
	// The time, in seconds, that the browser should remember
	// that a site is only to be accessed using HTTPS.
	MaxAge uint64

	// This field controls the includeSubDomains directive.
	// When DisableIncludeSubDomains is false, all subdomains
	// of the domain where this service is hosted will also be added
	// to the browsers HSTS list.
	DisableIncludeSubDomains bool

	// This field controls the preload directive.
	// This should only be enabled if this site should be
	// added to the browser HSTS preload list, which is supported
	// by all major browsers. See https://hstspreload.org/ for
	// more info.
	Preload bool
}

// NewPlugin creates a new HSTS plugin with safe defaults.
func NewPlugin() Plugin {
	return Plugin{MaxAge: 63072000} // two years in seconds
}

// Before should be executed before the request is sent to the handler.
// The function redirects HTTP requests to HTTPS. When HTTPS traffic
// is received the Strict-Transport-Security header is applied to the
// response.
func (p *Plugin) Before(w safehttp.ResponseWriter, r *safehttp.IncomingRequest) safehttp.Result {
	if r.TLS == nil {
		r.URL.Scheme = "https"
		return w.Redirect(r, r.URL.String(), safehttp.StatusMovedPermanently)
	}

	var value strings.Builder
	value.WriteString("max-age=")
	value.WriteString(strconv.FormatUint(p.MaxAge, 10))
	if !p.DisableIncludeSubDomains {
		value.WriteString("; includeSubDomains")
	}
	if p.Preload {
		value.WriteString("; preload")
	}
	h := w.Header()
	if err := h.Set("Strict-Transport-Security", value.String()); err != nil {
		// TODO(@mattiasgrenfeldt): Replace the response with an actual saferesponse somehow.
		return w.ServerError(safehttp.StatusInternalServerError, "Internal Server Error")
	}
	// TODO: Implement header claiming.
	h.MarkImmutable("Strict-Transport-Security")
	return safehttp.Result{}
}
<|endoftext|>


<commit_before>package server_test

import (
	"bytes"
	"io"
	"io/ioutil"
	"math/rand"
	"net"
	"os"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/travisjeffery/jocko/broker"
	"github.com/travisjeffery/jocko/commitlog"
	"github.com/travisjeffery/jocko/protocol"
	"github.com/travisjeffery/jocko/server"
	"github.com/travisjeffery/simplelog"
)

var (
	dataDir string
)

func init() {
	dataDir, _ = ioutil.TempDir("", "server_test")
}

const (
	clientID = "test_client"
)

func TestBroker_Server(t *testing.T) {
	dir := os.TempDir()
	defer os.RemoveAll(dir)

	assert.NoError(t, os.MkdirAll(dataDir, 0755))

	logger := simplelog.New(os.Stdout, simplelog.DEBUG, "jocko/servertest")
	store, err := broker.New(0,
		broker.DataDir(dataDir),
		broker.LogDir(dataDir),
		broker.BindAddr("127.0.0.1"),
		broker.Port(8000),
		broker.RaftPort(8001),
		broker.Logger(logger))
	assert.NoError(t, err)
	defer store.Shutdown()

	_, err = store.WaitForLeader(10 * time.Second)
	assert.NoError(t, err)

	s := server.New(":8000", store, logger)
	assert.NotNil(t, s)
	assert.NoError(t, s.Start())

	tcpAddr, err := net.ResolveTCPAddr("tcp", ":8000")
	assert.NoError(t, err)

	conn, err := net.DialTCP("tcp", nil, tcpAddr)
	assert.NoError(t, err)
	defer conn.Close()

	var body protocol.Body = &protocol.CreateTopicRequests{
		Requests: []*protocol.CreateTopicRequest{{
			Topic:             "test_topic",
			NumPartitions:     int32(8),
			ReplicationFactor: int16(2),
			ReplicaAssignment: map[int32][]int32{
				0: []int32{1, 2},
			},
			Configs: map[string]string{
				"config_key": "config_val",
			},
		}},
	}
	var req protocol.Encoder = &protocol.Request{
		CorrelationID: rand.Int31(),
		ClientID:      clientID,
		Body:          body,
	}

	b, err := protocol.Encode(req)
	assert.NoError(t, err)

	_, err = conn.Write(b)
	assert.NoError(t, err)

	buf := new(bytes.Buffer)
	_, err = io.CopyN(buf, conn, 8)
	assert.NoError(t, err)

	var header protocol.Response
	protocol.Decode(buf.Bytes(), &header)

	buf.Reset()
	_, err = io.CopyN(buf, conn, int64(header.Size-4))
	assert.NoError(t, err)

	createTopicsResponse := &protocol.CreateTopicsResponse{}
	err = protocol.Decode(buf.Bytes(), createTopicsResponse)
	assert.NoError(t, err)

	assert.Equal(t, 1, len(createTopicsResponse.TopicErrorCodes))
	assert.Equal(t, "test_topic", createTopicsResponse.TopicErrorCodes[0].Topic)
	assert.Equal(t, protocol.ErrNone, createTopicsResponse.TopicErrorCodes[0].ErrorCode)

	body = &protocol.MetadataRequest{
		Topics: []string{"test_topic"},
	}
	req = &protocol.Request{
		CorrelationID: rand.Int31(),
		ClientID:      clientID,
		Body:          body,
	}
	b, err = protocol.Encode(req)
	assert.NoError(t, err)

	_, err = conn.Write(b)
	assert.NoError(t, err)

	buf.Reset()
	_, err = io.CopyN(buf, conn, 8)
	assert.NoError(t, err)
	protocol.Decode(buf.Bytes(), &header)

	buf.Reset()
	_, err = io.CopyN(buf, conn, int64(header.Size-4))
	assert.NoError(t, err)

	metadataResponse := &protocol.MetadataResponse{}
	err = protocol.Decode(buf.Bytes(), metadataResponse)
	assert.NoError(t, err)

	assert.Equal(t, 1, len(metadataResponse.Brokers))
	assert.Equal(t, "test_topic", metadataResponse.TopicMetadata[0].Topic)

	m0 := commitlog.NewMessage([]byte("Hello world!"))
	ms := commitlog.NewMessageSet(0, m0)
	body = &protocol.ProduceRequest{
		TopicData: []*protocol.TopicData{{
			Topic: "test_topic",
			Data: []*protocol.Data{{
				Partition: 0,
				RecordSet: ms,
			}},
		}},
	}
	req = &protocol.Request{
		CorrelationID: rand.Int31(),
		ClientID:      clientID,
		Body:          body,
	}
	b, err = protocol.Encode(req)
	assert.NoError(t, err)
	_, err = conn.Write(b)

	buf.Reset()
	_, err = io.CopyN(buf, conn, 8)
	assert.NoError(t, err)
	protocol.Decode(buf.Bytes(), &header)

	buf.Reset()
	_, err = io.CopyN(buf, conn, int64(header.Size-4))
	produceResponse := &protocol.ProduceResponses{}
	err = protocol.Decode(buf.Bytes(), produceResponse)
	assert.NoError(t, err)

	assert.Equal(t, req.(*protocol.Request).CorrelationID, header.CorrelationID)
	assert.Equal(t, "test_topic", produceResponse.Responses[0].Topic)
	assert.Equal(t, protocol.ErrNone, produceResponse.Responses[0].PartitionResponses[0].ErrorCode)
	assert.NotEqual(t, 0, produceResponse.Responses[0].PartitionResponses[0].Timestamp)

	body = &protocol.FetchRequest{
		MinBytes: 5,
		Topics: []*protocol.FetchTopic{{
			Topic: "test_topic",
			Partitions: []*protocol.FetchPartition{{
				Partition:   int32(0),
				FetchOffset: int64(0),
				MaxBytes:    int32(5000),
			}},
		}},
	}
	req = &protocol.Request{
		CorrelationID: rand.Int31(),
		ClientID:      clientID,
		Body:          body,
	}
	b, err = protocol.Encode(req)
	assert.NoError(t, err)
	_, err = conn.Write(b)
	assert.NoError(t, err)

	buf.Reset()
	_, err = io.CopyN(buf, conn, 8)
	assert.NoError(t, err)
	err = protocol.Decode(buf.Bytes(), &header)
	assert.NoError(t, err)

	buf.Reset()
	_, err = io.CopyN(buf, conn, int64(header.Size-4))
	fetchResponse := &protocol.FetchResponses{}
	err = protocol.Decode(buf.Bytes(), fetchResponse)
	assert.NoError(t, err)

	recordSet := commitlog.MessageSet(fetchResponse.Responses[0].PartitionResponses[0].RecordSet)
	assert.Equal(t, int64(0), recordSet.Offset())
	assert.Equal(t, []byte(m0), recordSet.Payload())
}
<commit_msg>server: add sarama test<commit_after>package server_test

import (
	"bytes"
	"io"
	"io/ioutil"
	"math/rand"
	"net"
	"os"
	"testing"
	"time"

	"github.com/Shopify/sarama"
	"github.com/stretchr/testify/assert"
	"github.com/travisjeffery/jocko/broker"
	"github.com/travisjeffery/jocko/commitlog"
	"github.com/travisjeffery/jocko/protocol"
	"github.com/travisjeffery/jocko/server"
	"github.com/travisjeffery/simplelog"
)

var (
	dataDir string
)

const (
	topic         = "test_topic"
	messageCount  = 15
	clientID      = "test_client"
	numPartitions = int32(1)
)

func init() {
	dataDir, _ = ioutil.TempDir("", "server_test")
}

func TestBroker(t *testing.T) {
	conn, teardown := setup(t)

	t.Run("Server", func(t *testing.T) {
		buf := new(bytes.Buffer)
		var header protocol.Response
		var body protocol.Body

		body = &protocol.MetadataRequest{
			Topics: []string{"test_topic"},
		}
		var req protocol.Encoder = &protocol.Request{
			CorrelationID: rand.Int31(),
			ClientID:      clientID,
			Body:          body,
		}
		b, err := protocol.Encode(req)
		assert.NoError(t, err)

		_, err = conn.Write(b)
		assert.NoError(t, err)

		buf.Reset()
		_, err = io.CopyN(buf, conn, 8)
		assert.NoError(t, err)
		protocol.Decode(buf.Bytes(), &header)

		buf.Reset()
		_, err = io.CopyN(buf, conn, int64(header.Size-4))
		assert.NoError(t, err)

		metadataResponse := &protocol.MetadataResponse{}
		err = protocol.Decode(buf.Bytes(), metadataResponse)
		assert.NoError(t, err)

		assert.Equal(t, 1, len(metadataResponse.Brokers))
		assert.Equal(t, "test_topic", metadataResponse.TopicMetadata[0].Topic)

		m0 := commitlog.NewMessage([]byte("Hello world!"))
		ms := commitlog.NewMessageSet(0, m0)
		body = &protocol.ProduceRequest{
			TopicData: []*protocol.TopicData{{
				Topic: "test_topic",
				Data: []*protocol.Data{{
					Partition: 0,
					RecordSet: ms,
				}},
			}},
		}
		req = &protocol.Request{
			CorrelationID: rand.Int31(),
			ClientID:      clientID,
			Body:          body,
		}
		b, err = protocol.Encode(req)
		assert.NoError(t, err)
		_, err = conn.Write(b)

		buf.Reset()
		_, err = io.CopyN(buf, conn, 8)
		assert.NoError(t, err)
		protocol.Decode(buf.Bytes(), &header)

		buf.Reset()
		_, err = io.CopyN(buf, conn, int64(header.Size-4))
		produceResponse := &protocol.ProduceResponses{}
		err = protocol.Decode(buf.Bytes(), produceResponse)
		assert.NoError(t, err)

		assert.Equal(t, req.(*protocol.Request).CorrelationID, header.CorrelationID)
		assert.Equal(t, "test_topic", produceResponse.Responses[0].Topic)
		assert.Equal(t, protocol.ErrNone, produceResponse.Responses[0].PartitionResponses[0].ErrorCode)
		assert.NotEqual(t, 0, produceResponse.Responses[0].PartitionResponses[0].Timestamp)

		body = &protocol.FetchRequest{
			MinBytes: 5,
			Topics: []*protocol.FetchTopic{{
				Topic: "test_topic",
				Partitions: []*protocol.FetchPartition{{
					Partition:   int32(0),
					FetchOffset: int64(0),
					MaxBytes:    int32(5000),
				}},
			}},
		}
		req = &protocol.Request{
			CorrelationID: rand.Int31(),
			ClientID:      clientID,
			Body:          body,
		}
		b, err = protocol.Encode(req)
		assert.NoError(t, err)
		_, err = conn.Write(b)
		assert.NoError(t, err)

		buf.Reset()
		_, err = io.CopyN(buf, conn, 8)
		assert.NoError(t, err)
		err = protocol.Decode(buf.Bytes(), &header)
		assert.NoError(t, err)

		buf.Reset()
		_, err = io.CopyN(buf, conn, int64(header.Size-4))
		fetchResponse := &protocol.FetchResponses{}
		err = protocol.Decode(buf.Bytes(), fetchResponse)
		assert.NoError(t, err)

		recordSet := commitlog.MessageSet(fetchResponse.Responses[0].PartitionResponses[0].RecordSet)
		assert.Equal(t, int64(0), recordSet.Offset())
		assert.Equal(t, []byte(m0), recordSet.Payload())
	})

	t.Run("Sarama", func(t *testing.T) {
		config := sarama.NewConfig()
		config.ChannelBufferSize = 1
		config.Version = sarama.V0_10_0_1
		config.Producer.Return.Successes = true
		config.Consumer.Offsets.Initial = sarama.OffsetNewest

		brokers := []string{"127.0.0.1:8000"}
		producer, err := sarama.NewSyncProducer(brokers, config)
		if err != nil {
			panic(err)
		}

		bValue := []byte("Hello from Jocko!")
		msgValue := sarama.ByteEncoder(bValue)
		pPartition, offset, err := producer.SendMessage(&sarama.ProducerMessage{
			Topic: topic,
			Value: msgValue,
		})
		assert.NoError(t, err)

		consumer, err := sarama.NewConsumer(brokers, config)
		assert.NoError(t, err)

		cPartition, err := consumer.ConsumePartition(topic, pPartition, 1)
		assert.NoError(t, err)

		select {
		case msg := <-cPartition.Messages():
			assert.Equal(t, msg.Offset, offset)
			assert.Equal(t, pPartition, msg.Partition)
			assert.Equal(t, topic, msg.Topic)
			assert.Equal(t, 0, bytes.Compare(bValue, msg.Value))
		}
	})

	teardown()
}

func setup(t *testing.T) (*net.TCPConn, func()) {
	dir := os.TempDir()

	assert.NoError(t, os.MkdirAll(dataDir, 0755))

	logger := simplelog.New(os.Stdout, simplelog.DEBUG, "jocko/servertest")
	store, err := broker.New(0,
		broker.DataDir(dataDir),
		broker.LogDir(dataDir),
		broker.BindAddr("127.0.0.1"),
		broker.Port(8000),
		broker.RaftPort(8001),
		broker.Logger(logger))
	assert.NoError(t, err)

	_, err = store.WaitForLeader(10 * time.Second)
	assert.NoError(t, err)

	srv := server.New(":8000", store, logger)
	assert.NotNil(t, srv)
	assert.NoError(t, srv.Start())

	tcpAddr, err := net.ResolveTCPAddr("tcp", ":8000")
	assert.NoError(t, err)

	conn, err := net.DialTCP("tcp", nil, tcpAddr)
	assert.NoError(t, err)

	createTopic(t, conn)

	return conn, func() {
		conn.Close()
		srv.Close()
		store.Shutdown()
		os.RemoveAll(dir)
	}
}
func createTopic(t *testing.T, conn *net.TCPConn) {
	buf := new(bytes.Buffer)
	var header protocol.Response
	var body protocol.Body

	body = &protocol.CreateTopicRequests{
		Requests: []*protocol.CreateTopicRequest{{
			Topic:             topic,
			NumPartitions:     int32(1),
			ReplicationFactor: int16(1),
			ReplicaAssignment: map[int32][]int32{
				0: []int32{0, 1},
			},
			Configs: map[string]string{
				"config_key": "config_val",
			},
		}},
	}
	var req protocol.Encoder = &protocol.Request{
		CorrelationID: rand.Int31(),
		ClientID:      clientID,
		Body:          body,
	}

	b, err := protocol.Encode(req)
	assert.NoError(t, err)

	_, err = conn.Write(b)
	assert.NoError(t, err)

	_, err = io.CopyN(buf, conn, 8)
	assert.NoError(t, err)

	protocol.Decode(buf.Bytes(), &header)

	buf.Reset()
	_, err = io.CopyN(buf, conn, int64(header.Size-4))
	assert.NoError(t, err)

	createTopicsResponse := &protocol.CreateTopicsResponse{}
	err = protocol.Decode(buf.Bytes(), createTopicsResponse)
	assert.NoError(t, err)

	assert.Equal(t, 1, len(createTopicsResponse.TopicErrorCodes))
	assert.Equal(t, topic, createTopicsResponse.TopicErrorCodes[0].Topic)
	assert.Equal(t, protocol.ErrNone, createTopicsResponse.TopicErrorCodes[0].ErrorCode)
}
<|endoftext|>