<commit_before>/*
 * Copyright 2016 The Kythe Authors. 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.
 */

// bazel_go_extractor is a Bazel extra action that extracts Go compilations.
package main

import (
	"context"
	"flag"
	"fmt"
	"log"
	"os"
	"path/filepath"
	"strings"

	"kythe.io/kythe/go/extractors/bazel"
	"kythe.io/kythe/go/extractors/govname"
	"kythe.io/kythe/go/util/ptypes"
	"kythe.io/kythe/go/util/vnameutil"

	apb "kythe.io/kythe/proto/analysis_go_proto"
	gopb "kythe.io/kythe/proto/go_go_proto"
)

var (
	corpus = flag.String("corpus", "kythe", "The corpus label to assign (required)")
)

const baseUsage = `Usage: %[1]s [flags] <extra-action> <output-file> <vname-config>`

func init() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, baseUsage+`

Extract a Kythe compilation record for Go from a Bazel extra action.

Arguments:
 <extra-action> is a file containing a wire format ExtraActionInfo protobuf.
 <output-file>  is the path where the output kindex file is written.
 <vname-config> is the path of a VName configuration JSON file.

Flags:
`, filepath.Base(os.Args[0]))
		flag.PrintDefaults()
	}
}

func main() {
	flag.Parse()
	if flag.NArg() != 3 {
		log.Fatalf(baseUsage+` [run "%[1]s --help" for details]`, filepath.Base(os.Args[0]))
	}
	extraActionFile := flag.Arg(0)
	outputFile := flag.Arg(1)
	vnameRuleFile := flag.Arg(2)

	info, err := bazel.LoadAction(extraActionFile)
	if err != nil {
		log.Fatalf("Error loading extra action: %v", err)
	}
	if m := info.GetMnemonic(); m != "GoCompilePkg" {
		log.Fatalf("Extractor is not applicable to this action: %q", m)
	}

	// Load vname rewriting rules. We handle this directly, becaues the Bazel
	// Go rules have some pathological symlink handling that the normal rules
	// need to be patched for.
	rules, err := vnameutil.LoadRules(vnameRuleFile)
	if err != nil {
		log.Fatalf("Error loading vname rules: %v", err)
	}

	ext := &extractor{rules: rules}
	config := &bazel.Config{
		Corpus:      *corpus,
		Language:    govname.Language,
		Rules:       rules,
		CheckAction: ext.checkAction,
		CheckInput:  ext.checkInput,
		CheckEnv:    ext.checkEnv,
		IsSource:    ext.isSource,
		FixUnit:     ext.fixup,
	}
	ai, err := bazel.SpawnAction(info)
	if err != nil {
		log.Fatalf("Invalid extra action: %v", err)
	}

	ctx := context.Background()
	if err := config.ExtractToKzip(ctx, ai, outputFile); err != nil {
		log.Fatalf("Extraction failed: %v", err)
	}
}

type extractor struct {
	rules       vnameutil.Rules
	compileArgs *compileArgs

	goos, goarch, goroot string
	cgoEnabled           bool
}

func (e *extractor) checkAction(_ context.Context, info *bazel.ActionInfo) error {
	e.compileArgs = parseCompileArgs(info.Arguments)
	for name, value := range info.Environment {
		switch name {
		case "GOOS":
			e.goos = value
		case "GOARCH":
			e.goarch = value
		case "GOROOT":
			e.goroot = value
		case "CGO_ENABLED":
			e.cgoEnabled = value == "1"
		}
	}

	// The standard library packages aren't included explicitly.
	// Walk the os_arch subdirectory of GOROOT to find them.
	libRoot := filepath.Join(e.goroot, "pkg", e.goos+"_"+e.goarch)
	return filepath.Walk(libRoot, func(path string, fi os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if !fi.IsDir() && filepath.Ext(path) == ".a" {
			info.Inputs = append(info.Inputs, path)
		}
		return nil
	})
}

func (e *extractor) checkInput(path string) (string, bool) {
	switch filepath.Ext(path) {
	case ".go", ".a":
		return path, true // keep source files, archives
	}
	return path, false
}

func (*extractor) isSource(name string) bool { return filepath.Ext(name) == ".go" }

func (*extractor) checkEnv(name, _ string) bool { return name != "PATH" }

func (e *extractor) fixup(unit *apb.CompilationUnit) error {
	// Add GoPackageInfo to record canonical import paths of packages.
	for _, ri := range unit.RequiredInput {
		if ip, ok := e.compileArgs.archiveImportMap[ri.Info.Path]; ok {
			any, err := ptypes.MarshalAny(&gopb.GoPackageInfo{
				ImportPath: ip,
			})
			if err != nil {
				return fmt.Errorf("error adding GoPackageInfo details: %v", err)
			}
			ri.Details = append(ri.Details, any)
		}
	}

	// Try to infer a unit vname from the output.
	if vname, ok := e.rules.Apply(e.compileArgs.outputPath); ok {
		vname.Language = govname.Language
		unit.VName = vname
	}
	return bazel.AddDetail(unit, &gopb.GoDetails{
		Goos:       e.goos,
		Goarch:     e.goarch,
		Goroot:     e.goroot,
		CgoEnabled: e.cgoEnabled,
		Compiler:   "gc",
	})
}

// compileArgs records the build information extracted from the GoCompilePkg
// action's argument list.
type compileArgs struct {
	original         []string          // the original args, as provided
	srcs             []string          // source file to be compiled
	deps             []string          // import paths of direct dependencies
	tags             []string          // build tags to assert
	importMap        map[string]string // import map for direct dependencies
	archiveImportMap map[string]string // import map for direct dependencies of archives
	outputPath       string            // output object file
	packageList      string            // file containing the list of standard library packages
	include          []string          // additional include directories
	importPath       string            // output package import path
	trimPrefix       string            // prefix to trim from source paths
}

func parseCompileArgs(args []string) *compileArgs {
	c := &compileArgs{
		original:         args,
		importMap:        make(map[string]string),
		archiveImportMap: make(map[string]string),
	}

	var tail []string // left-over non-flag arguments
	flag := ""
	for i, arg := range args {
		if arg == "--" {
			// An explicit "--" ends builder flag parsing.
			tail = args[i+1:]
			break
		} else if flag == "" && strings.HasPrefix(arg, "-") {
			// Record the name of a flag we want an argument for.
			flag = strings.TrimLeft(arg, "-")
			continue
		}

		// At this point we have the argument for a flag.  These are the
		// relevant flags from the toolchain's compile command.
		switch flag {
		case "dep":
			c.deps = append(c.deps, arg)
		case "importmap":
			// Only record the mappings that change something.
			ps := strings.SplitN(arg, "=", 2)
			if len(ps) == 2 && ps[0] != ps[1] {
				c.importMap[ps[0]] = ps[1]
			}
		case "arc":
			// Example -arc arg:
			//   "github.com/google/subcommands=github.com/google/subcommands=bazel-out/k8-fastbuild/bin/external/com_github_google_subcommands/linux_amd64_stripped/go_default_library%/github.com/google/subcommands.a=",
			//
			// Only record the mappings that change something.
			ps := strings.SplitN(strings.TrimSuffix(arg, "="), "=", 3)
			if len(ps) == 3 {
				// map from file path to desired importpath
				c.archiveImportMap[ps[2]] = ps[1]
			}

		case "o":
			c.outputPath = arg
		case "package_list":
			c.packageList = arg
		case "src":
			c.srcs = append(c.srcs, arg)
		case "tags":
			c.tags = append(c.tags, arg)
		}
		flag = "" // reset
	}

	// Any remaining arguments are for consumption by the go tool.
	// Pull out include paths and other useful stuff.
	flag = ""
	for _, arg := range tail {
		if flag == "" && strings.HasPrefix(arg, "-") {
			flag = strings.TrimLeft(arg, "-")
			continue
		}

		// These are the relevant flags for the "go tool compile" command.
		switch flag {
		case "I":
			c.include = append(c.include, arg)
		case "p":
			c.importPath = arg
		case "trimpath":
			c.trimPrefix = arg
		}
		flag = "" // reset
	}

	return c
}
<commit_msg>fix(bazel_go_extractor): include .x files in required input (#4874)<commit_after>/*
 * Copyright 2016 The Kythe Authors. 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.
 */

// bazel_go_extractor is a Bazel extra action that extracts Go compilations.
package main

import (
	"context"
	"flag"
	"fmt"
	"log"
	"os"
	"path/filepath"
	"strings"

	"kythe.io/kythe/go/extractors/bazel"
	"kythe.io/kythe/go/extractors/govname"
	"kythe.io/kythe/go/util/ptypes"
	"kythe.io/kythe/go/util/vnameutil"

	apb "kythe.io/kythe/proto/analysis_go_proto"
	gopb "kythe.io/kythe/proto/go_go_proto"
)

var (
	corpus = flag.String("corpus", "kythe", "The corpus label to assign (required)")
)

const baseUsage = `Usage: %[1]s [flags] <extra-action> <output-file> <vname-config>`

func init() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, baseUsage+`

Extract a Kythe compilation record for Go from a Bazel extra action.

Arguments:
 <extra-action> is a file containing a wire format ExtraActionInfo protobuf.
 <output-file>  is the path where the output kindex file is written.
 <vname-config> is the path of a VName configuration JSON file.

Flags:
`, filepath.Base(os.Args[0]))
		flag.PrintDefaults()
	}
}

func main() {
	flag.Parse()
	if flag.NArg() != 3 {
		log.Fatalf(baseUsage+` [run "%[1]s --help" for details]`, filepath.Base(os.Args[0]))
	}
	extraActionFile := flag.Arg(0)
	outputFile := flag.Arg(1)
	vnameRuleFile := flag.Arg(2)

	info, err := bazel.LoadAction(extraActionFile)
	if err != nil {
		log.Fatalf("Error loading extra action: %v", err)
	}
	if m := info.GetMnemonic(); m != "GoCompilePkg" {
		log.Fatalf("Extractor is not applicable to this action: %q", m)
	}

	// Load vname rewriting rules. We handle this directly, becaues the Bazel
	// Go rules have some pathological symlink handling that the normal rules
	// need to be patched for.
	rules, err := vnameutil.LoadRules(vnameRuleFile)
	if err != nil {
		log.Fatalf("Error loading vname rules: %v", err)
	}

	ext := &extractor{rules: rules}
	config := &bazel.Config{
		Corpus:      *corpus,
		Language:    govname.Language,
		Rules:       rules,
		CheckAction: ext.checkAction,
		CheckInput:  ext.checkInput,
		CheckEnv:    ext.checkEnv,
		IsSource:    ext.isSource,
		FixUnit:     ext.fixup,
	}
	ai, err := bazel.SpawnAction(info)
	if err != nil {
		log.Fatalf("Invalid extra action: %v", err)
	}

	ctx := context.Background()
	if err := config.ExtractToKzip(ctx, ai, outputFile); err != nil {
		log.Fatalf("Extraction failed: %v", err)
	}
}

type extractor struct {
	rules       vnameutil.Rules
	compileArgs *compileArgs

	goos, goarch, goroot string
	cgoEnabled           bool
}

func (e *extractor) checkAction(_ context.Context, info *bazel.ActionInfo) error {
	e.compileArgs = parseCompileArgs(info.Arguments)
	for name, value := range info.Environment {
		switch name {
		case "GOOS":
			e.goos = value
		case "GOARCH":
			e.goarch = value
		case "GOROOT":
			e.goroot = value
		case "CGO_ENABLED":
			e.cgoEnabled = value == "1"
		}
	}

	// The standard library packages aren't included explicitly.
	// Walk the os_arch subdirectory of GOROOT to find them.
	libRoot := filepath.Join(e.goroot, "pkg", e.goos+"_"+e.goarch)
	return filepath.Walk(libRoot, func(path string, fi os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if !fi.IsDir() && filepath.Ext(path) == ".a" {
			info.Inputs = append(info.Inputs, path)
		}
		return nil
	})
}

func (e *extractor) checkInput(path string) (string, bool) {
	switch filepath.Ext(path) {
	case ".go", ".a", ".x":
		return path, true // keep source files, archives, and export info
	}
	return path, false
}

func (*extractor) isSource(name string) bool { return filepath.Ext(name) == ".go" }

func (*extractor) checkEnv(name, _ string) bool { return name != "PATH" }

func (e *extractor) fixup(unit *apb.CompilationUnit) error {
	// Add GoPackageInfo to record canonical import paths of packages.
	for _, ri := range unit.RequiredInput {
		if ip, ok := e.compileArgs.archiveImportMap[ri.Info.Path]; ok {
			any, err := ptypes.MarshalAny(&gopb.GoPackageInfo{
				ImportPath: ip,
			})
			if err != nil {
				return fmt.Errorf("error adding GoPackageInfo details: %v", err)
			}
			ri.Details = append(ri.Details, any)
		}
	}

	// Try to infer a unit vname from the output.
	if vname, ok := e.rules.Apply(e.compileArgs.outputPath); ok {
		vname.Language = govname.Language
		unit.VName = vname
	}
	return bazel.AddDetail(unit, &gopb.GoDetails{
		Goos:       e.goos,
		Goarch:     e.goarch,
		Goroot:     e.goroot,
		CgoEnabled: e.cgoEnabled,
		Compiler:   "gc",
	})
}

// compileArgs records the build information extracted from the GoCompilePkg
// action's argument list.
type compileArgs struct {
	original         []string          // the original args, as provided
	srcs             []string          // source file to be compiled
	deps             []string          // import paths of direct dependencies
	tags             []string          // build tags to assert
	importMap        map[string]string // import map for direct dependencies
	archiveImportMap map[string]string // import map for direct dependencies of archives
	outputPath       string            // output object file
	packageList      string            // file containing the list of standard library packages
	include          []string          // additional include directories
	importPath       string            // output package import path
	trimPrefix       string            // prefix to trim from source paths
}

func parseCompileArgs(args []string) *compileArgs {
	c := &compileArgs{
		original:         args,
		importMap:        make(map[string]string),
		archiveImportMap: make(map[string]string),
	}

	var tail []string // left-over non-flag arguments
	flag := ""
	for i, arg := range args {
		if arg == "--" {
			// An explicit "--" ends builder flag parsing.
			tail = args[i+1:]
			break
		} else if flag == "" && strings.HasPrefix(arg, "-") {
			// Record the name of a flag we want an argument for.
			flag = strings.TrimLeft(arg, "-")
			continue
		}

		// At this point we have the argument for a flag.  These are the
		// relevant flags from the toolchain's compile command.
		switch flag {
		case "dep":
			c.deps = append(c.deps, arg)
		case "importmap":
			// Only record the mappings that change something.
			ps := strings.SplitN(arg, "=", 2)
			if len(ps) == 2 && ps[0] != ps[1] {
				c.importMap[ps[0]] = ps[1]
			}
		case "arc":
			// Example -arc arg:
			//   "github.com/google/subcommands=github.com/google/subcommands=bazel-out/k8-fastbuild/bin/external/com_github_google_subcommands/linux_amd64_stripped/go_default_library%/github.com/google/subcommands.a=",
			//
			// Only record the mappings that change something.
			ps := strings.SplitN(strings.TrimSuffix(arg, "="), "=", 3)
			if len(ps) == 3 {
				// map from file path to desired importpath
				c.archiveImportMap[ps[2]] = ps[1]
			}

		case "o":
			c.outputPath = arg
		case "package_list":
			c.packageList = arg
		case "src":
			c.srcs = append(c.srcs, arg)
		case "tags":
			c.tags = append(c.tags, arg)
		}
		flag = "" // reset
	}

	// Any remaining arguments are for consumption by the go tool.
	// Pull out include paths and other useful stuff.
	flag = ""
	for _, arg := range tail {
		if flag == "" && strings.HasPrefix(arg, "-") {
			flag = strings.TrimLeft(arg, "-")
			continue
		}

		// These are the relevant flags for the "go tool compile" command.
		switch flag {
		case "I":
			c.include = append(c.include, arg)
		case "p":
			c.importPath = arg
		case "trimpath":
			c.trimPrefix = arg
		}
		flag = "" // reset
	}

	return c
}
<|endoftext|>


<commit_before>package main

import (
	"board"
	"color"
	"enemy"
	"fmt"
	"io"
	"matrix"
	"os"
	"piece"
)

func scanMove() (*matrix.Move, error) {
	var file byte
	var rank int

	_, err := fmt.Scanf("%c%d", &file, &rank)
	return matrix.NewMove(file, rank), err
}

func main() {
	var player color.Color
	if len(os.Args) == 1 {
		player = color.White
	} else {
		player = color.ParseColor(os.Args[1])
		if player == color.Unknown {
			fmt.Printf("Invalid color: %s\n", os.Args[1])
			return
		}
	}
	chessboard := board.NewBoard()
	finish := false
	now := color.White

	for finish == false {
		success := false

		chessboard.Print()
		if chessboard.IsCheckMate(now) {
			fmt.Println("Checkmate")
			break
		} else if chessboard.IsChecked(now) {
			fmt.Println("Your king is checked")
		}

		var from, to matrix.Point
		var err error
		for success == false {
			if now != player {
				from, to = enemy.NewEnemy(chessboard, now).RandomizedSelect()
				fmt.Printf("%c%d %c%d\n", byte(from.X+'a'), 8-from.Y, byte(to.X+'a'), 8-to.Y)
			} else {
				var move *matrix.Move
				move, err = scanMove()
				if err == io.EOF {
					finish = true
					break
				} else if err != nil {
					fmt.Println(err)
					continue
				} else {
					from = move.ToPoint()
				}
				move, err = scanMove()
				if err == io.EOF {
					finish = true
					break
				} else if err != nil {
					fmt.Println(err)
					continue
				} else {
					to = move.ToPoint()
				}
			}
			canMove, err := chessboard.CanMove(from, to, now)
			success = canMove
			if canMove {
				success = true
				chessboard.Move(from, to, chessboard.IsCastling(from, to))
				isPawn := piece.Pawn.IsSymbol(chessboard.Matrix[to.Y][to.X])
				if isPawn && matrix.IsDeepest(to, now) {
					fmt.Print("Promotion: ")
					var choice string
					fmt.Scan(&choice)
					p := piece.WhichPiece([]byte(choice)[0])
					for piece.CanPromotionTo(p) == false {
						fmt.Println("Invalid symbol")
						fmt.Print("Promotion: ")
						fmt.Scan(&choice)
						p = piece.WhichPiece([]byte(choice)[0])
					}
					chessboard.Promotion(to, p, now)
				}
			} else {
				fmt.Println(err)
			}
		}
		fmt.Println()
		now = now.Enemy()
	}
}
<commit_msg>Promotion to Queen when enemy pawns promote<commit_after>package main

import (
	"board"
	"color"
	"enemy"
	"fmt"
	"io"
	"matrix"
	"os"
	"piece"
)

func scanMove() (*matrix.Move, error) {
	var file byte
	var rank int

	_, err := fmt.Scanf("%c%d", &file, &rank)
	return matrix.NewMove(file, rank), err
}

func main() {
	var player color.Color
	if len(os.Args) == 1 {
		player = color.White
	} else {
		player = color.ParseColor(os.Args[1])
		if player == color.Unknown {
			fmt.Printf("Invalid color: %s\n", os.Args[1])
			return
		}
	}
	chessboard := board.NewBoard()
	finish := false
	now := color.White

	for finish == false {
		success := false

		chessboard.Print()
		if chessboard.IsCheckMate(now) {
			fmt.Println("Checkmate")
			break
		} else if chessboard.IsChecked(now) {
			fmt.Println("Your king is checked")
		}

		var from, to matrix.Point
		var err error
		for success == false {
			if now != player {
				from, to = enemy.NewEnemy(chessboard, now).RandomizedSelect()
				fmt.Printf("%c%d %c%d\n", byte(from.X+'a'), 8-from.Y, byte(to.X+'a'), 8-to.Y)
			} else {
				var move *matrix.Move
				move, err = scanMove()
				if err == io.EOF {
					finish = true
					break
				} else if err != nil {
					fmt.Println(err)
					continue
				} else {
					from = move.ToPoint()
				}
				move, err = scanMove()
				if err == io.EOF {
					finish = true
					break
				} else if err != nil {
					fmt.Println(err)
					continue
				} else {
					to = move.ToPoint()
				}
			}
			canMove, err := chessboard.CanMove(from, to, now)
			success = canMove
			if canMove {
				success = true
				chessboard.Move(from, to, chessboard.IsCastling(from, to))
				isPawn := piece.Pawn.IsSymbol(chessboard.Matrix[to.Y][to.X])
				if isPawn && matrix.IsDeepest(to, now) {
					fmt.Print("Promotion: ")
					var choice string
					if now == player {
						fmt.Scan(&choice)
					} else {
						choice = "Queen"
						fmt.Println(choice)
					}

					p := piece.WhichPiece([]byte(choice)[0])
					for piece.CanPromotionTo(p) == false {
						fmt.Println("Invalid symbol")
						fmt.Print("Promotion: ")
						fmt.Scan(&choice)
						p = piece.WhichPiece([]byte(choice)[0])
					}
					chessboard.Promotion(to, p, now)
				}
			} else {
				fmt.Println(err)
			}
		}
		fmt.Println()
		now = now.Enemy()
	}
}
<|endoftext|>


<commit_before>package handler

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

	"github.com/drone/drone/server/worker"
	"github.com/drone/drone/server/worker/director"
	"github.com/drone/drone/server/worker/pool"
	"github.com/goji/context"
	"github.com/zenazn/goji/web"
)

// GetWorkers accepts a request to retrieve the list
// of registered workers and return the results
// in JSON format.
//
//     GET /api/workers
//
func GetWorkers(c web.C, w http.ResponseWriter, r *http.Request) {
	ctx := context.FromC(c)
	workers := pool.FromContext(ctx).List()
	json.NewEncoder(w).Encode(workers)
}

// GetWorkPending accepts a request to retrieve the list
// of pending work and returns in JSON format.
//
//     GET /api/work/pending
//
func GetWorkPending(c web.C, w http.ResponseWriter, r *http.Request) {
	ctx := context.FromC(c)
	d := worker.FromContext(ctx).(*director.Director)
	json.NewEncoder(w).Encode(d.GetPending())
}

// GetWorkStarted accepts a request to retrieve the list
// of started work and returns in JSON format.
//
//     GET /api/work/started
//
func GetWorkStarted(c web.C, w http.ResponseWriter, r *http.Request) {
	ctx := context.FromC(c)
	d := worker.FromContext(ctx).(*director.Director)
	json.NewEncoder(w).Encode(d.GetStarted())
}

// GetWorkAssigned accepts a request to retrieve the list
// of started work and returns in JSON format.
//
//     GET /api/work/assignments
//
func GetWorkAssigned(c web.C, w http.ResponseWriter, r *http.Request) {
	ctx := context.FromC(c)
	d := worker.FromContext(ctx).(*director.Director)
	json.NewEncoder(w).Encode(d.GetAssignemnts())
}
<commit_msg>endpoint to post a new worker to the pool<commit_after>package handler

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

	"github.com/drone/drone/server/worker"
	"github.com/drone/drone/server/worker/director"
	"github.com/drone/drone/server/worker/docker"
	"github.com/drone/drone/server/worker/pool"
	"github.com/goji/context"
	"github.com/zenazn/goji/web"
)

// GetWorkers accepts a request to retrieve the list
// of registered workers and return the results
// in JSON format.
//
//     GET /api/workers
//
func GetWorkers(c web.C, w http.ResponseWriter, r *http.Request) {
	ctx := context.FromC(c)
	workers := pool.FromContext(ctx).List()
	json.NewEncoder(w).Encode(workers)
}

// PostWorker accepts a request to allocate a new
// worker to the pool.
//
//     POST /api/workers
//
func PostWorker(c web.C, w http.ResponseWriter, r *http.Request) {
	ctx := context.FromC(c)
	workers := pool.FromContext(ctx)
	node := r.FormValue("node")
	workers.Allocate(docker.NewHost(node))
	w.WriteHeader(http.StatusOK)
}

// GetWorkPending accepts a request to retrieve the list
// of pending work and returns in JSON format.
//
//     GET /api/work/pending
//
func GetWorkPending(c web.C, w http.ResponseWriter, r *http.Request) {
	ctx := context.FromC(c)
	d := worker.FromContext(ctx).(*director.Director)
	json.NewEncoder(w).Encode(d.GetPending())
}

// GetWorkStarted accepts a request to retrieve the list
// of started work and returns in JSON format.
//
//     GET /api/work/started
//
func GetWorkStarted(c web.C, w http.ResponseWriter, r *http.Request) {
	ctx := context.FromC(c)
	d := worker.FromContext(ctx).(*director.Director)
	json.NewEncoder(w).Encode(d.GetStarted())
}

// GetWorkAssigned accepts a request to retrieve the list
// of started work and returns in JSON format.
//
//     GET /api/work/assignments
//
func GetWorkAssigned(c web.C, w http.ResponseWriter, r *http.Request) {
	ctx := context.FromC(c)
	d := worker.FromContext(ctx).(*director.Director)
	json.NewEncoder(w).Encode(d.GetAssignemnts())
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"path"
	"path/filepath"
	"sync"
	"time"

	"github.com/skia-dev/glog"
	"go.skia.org/infra/go/auth"
	"go.skia.org/infra/go/common"
	"go.skia.org/infra/go/swarming"
	"go.skia.org/infra/go/util"

	swarmingapi "github.com/luci/luci-go/common/api/swarming/swarming/v1"
)

/*
	List/Cancel/Retry all swarming tasks that match the specified tags.
*/

const (
	LIST_CMD         = "list"
	CANCEL_CMD       = "cancel"
	RETRY_CMD        = "retry"
	WORKER_POOL_SIZE = 20
	// Number of tasks to display before displaying confirmation of whether to
	// proceed.
	CONFIRMATION_DISPLAY_LIMIT = 5
)

var (
	cmd     = flag.String("cmd", "", "Which swarming operation to use. Eg: list, cancel, retry.")
	tags    = common.NewMultiStringFlag("tag", nil, "Colon-separated key/value pair, eg: \"runid:testing\" Tags with which to find matching tasks. Can specify multiple times.")
	pool    = flag.String("pool", "", "Which Swarming pool to use.")
	workdir = flag.String("workdir", ".", "Working directory. Optional, but recommended not to use CWD.")
	state   = flag.String("state", "PENDING", "State the matching tasks should be in. Possible values are: ALL, BOT_DIED, CANCELED, COMPLETED, COMPLETED_FAILURE, COMPLETED_SUCCESS, DEDUPED, EXPIRED, PENDING, PENDING_RUNNING, RUNNING, TIMED_OUT")

	supportedCmds = map[string]bool{
		LIST_CMD:   true,
		CANCEL_CMD: true,
		RETRY_CMD:  true,
	}
)

func main() {
	// Setup, parse args.
	defer common.LogPanic()
	common.Init()

	if _, ok := supportedCmds[*cmd]; !ok {
		glog.Fatalf("--cmd must be one of %v", supportedCmds)
	}
	if tags.String() == "" {
		glog.Fatal("Atleast one --tag is required.")
	}
	if *pool == "" {
		glog.Fatal("--pool is required.")
	}

	var err error
	*workdir, err = filepath.Abs(*workdir)
	if err != nil {
		glog.Fatal(err)
	}

	// Authenticated HTTP client.
	oauthCacheFile := path.Join(*workdir, "google_storage_token.data")
	httpClient, err := auth.NewClient(true, oauthCacheFile, swarming.AUTH_SCOPE)
	if err != nil {
		glog.Fatal(err)
	}

	// Swarming API client.
	swarmApi, err := swarming.NewApiClient(httpClient)
	if err != nil {
		glog.Fatal(err)
	}

	// Obtain the list of tasks.
	tagsWithPool := []string{fmt.Sprintf("pool:%s", *pool)}
	for _, t := range *tags {
		tagsWithPool = append(tagsWithPool, t)
	}
	tasks, err := swarmApi.ListTasks(time.Time{}, time.Time{}, tagsWithPool, *state)
	if err != nil {
		glog.Fatal(err)
	}
	if len(tasks) == 0 {
		glog.Info("Found no matching tasks.")
		return
	}

	if *cmd == LIST_CMD {
		glog.Infof("Found %d tasks...", len(tasks))
		for _, t := range tasks {
			glog.Infof("  %s", getTaskStr(t))
		}

	} else if *cmd == CANCEL_CMD {
		resp, err := displayTasksAndConfirm(tasks, "canceling")
		if err != nil {
			glog.Fatal(err)
		}
		if resp {
			glog.Infof("Starting cancelation of %d tasks...", len(tasks))
			tasksChannel := getClosedTasksChannel(tasks, false /* dedupNames */)
			var wg sync.WaitGroup
			// Loop through workers in the worker pool.
			for i := 0; i < WORKER_POOL_SIZE; i++ {
				// Increment the WaitGroup counter.
				wg.Add(1)
				// Create and run a goroutine closure that cancels tasks.
				go func() {
					// Decrement the WaitGroup counter when the goroutine completes.
					defer wg.Done()

					for t := range tasksChannel {
						if err := swarmApi.CancelTask(t.TaskId); err != nil {
							glog.Errorf("Could not delete %s: %s", getTaskStr(t), err)
							continue
						}
						glog.Infof("Deleted  %s", getTaskStr(t))
					}
				}()
			}
			// Wait for all spawned goroutines to complete
			wg.Wait()

			glog.Infof("Cancelled %d tasks.", len(tasks))
		}

	} else if *cmd == RETRY_CMD {
		resp, err := displayTasksAndConfirm(tasks, "retrying")
		if err != nil {
			glog.Fatal(err)
		}
		if resp {
			glog.Infof("Starting retries of %d tasks...", len(tasks))
			tasksChannel := getClosedTasksChannel(tasks, true /* dedupNames */)

			var wg sync.WaitGroup
			// Loop through workers in the worker pool.
			for i := 0; i < WORKER_POOL_SIZE; i++ {
				// Increment the WaitGroup counter.
				wg.Add(1)
				// Create and run a goroutine closure that retries tasks.
				go func() {
					// Decrement the WaitGroup counter when the goroutine completes.
					defer wg.Done()

					for t := range tasksChannel {
						if _, err := swarmApi.RetryTask(t); err != nil {
							glog.Errorf("Could not retry %s: %s", getTaskStr(t), err)
							continue
						}
						glog.Infof("Retried  %s", getTaskStr(t))
					}
				}()
			}
			// Wait for all spawned goroutines to complete
			wg.Wait()

			glog.Infof("Retried %d tasks.", len(tasks))
		}
	}
}

func displayTasksAndConfirm(tasks []*swarmingapi.SwarmingRpcsTaskRequestMetadata, verb string) (bool, error) {
	glog.Infof("Found %d tasks. Displaying the first %d:", len(tasks), CONFIRMATION_DISPLAY_LIMIT)
	for _, t := range tasks[:util.MinInt(CONFIRMATION_DISPLAY_LIMIT, len(tasks))] {
		glog.Infof("  %s", getTaskStr(t))
	}
	glog.Infof("Would you like to proceed with %s %d tasks? ('y' or 'n')", verb, len(tasks))
	return askForConfirmation()
}

func askForConfirmation() (bool, error) {
	var response string
	if _, err := fmt.Scanln(&response); err != nil {
		return false, err
	}
	if response == "y" {
		return true, nil
	} else if response == "n" {
		return false, nil
	} else {
		glog.Info("Please type 'y' or 'n' and then press enter:")
		return askForConfirmation()
	}
}

func getClosedTasksChannel(tasks []*swarmingapi.SwarmingRpcsTaskRequestMetadata, dedupNames bool) chan *swarmingapi.SwarmingRpcsTaskRequestMetadata {
	// Create channel that contains specified tasks. This channel will
	// be consumed by the worker pool.
	tasksChannel := make(chan *swarmingapi.SwarmingRpcsTaskRequestMetadata, len(tasks))
	// Dictionary that will be used for deduping by names if dedupNames is true.
	taskNames := map[string]bool{}

	for _, t := range tasks {
		if dedupNames {
			if _, ok := taskNames[t.Request.Name]; ok {
				// Already encountered this task. Continue.
				glog.Errorf("Found another %s: %s", t.Request.Name, t.TaskId)
				continue
			}
		}
		tasksChannel <- t
		taskNames[t.Request.Name] = true
	}
	close(tasksChannel)
	return tasksChannel
}

func getTaskStr(t *swarmingapi.SwarmingRpcsTaskRequestMetadata) string {
	return fmt.Sprintf("Task id: %s  Created: %s  Name: %s", t.TaskId, t.Request.CreatedTs, t.Request.Name)
}
<commit_msg>Add missing output when listing tasks<commit_after>package main

import (
	"flag"
	"fmt"
	"path"
	"path/filepath"
	"sync"
	"time"

	"github.com/skia-dev/glog"
	"go.skia.org/infra/go/auth"
	"go.skia.org/infra/go/common"
	"go.skia.org/infra/go/swarming"
	"go.skia.org/infra/go/util"

	swarmingapi "github.com/luci/luci-go/common/api/swarming/swarming/v1"
)

/*
	List/Cancel/Retry all swarming tasks that match the specified tags.
*/

const (
	LIST_CMD         = "list"
	CANCEL_CMD       = "cancel"
	RETRY_CMD        = "retry"
	WORKER_POOL_SIZE = 20
	// Number of tasks to display before displaying confirmation of whether to
	// proceed.
	CONFIRMATION_DISPLAY_LIMIT = 5
)

var (
	cmd     = flag.String("cmd", "", "Which swarming operation to use. Eg: list, cancel, retry.")
	tags    = common.NewMultiStringFlag("tag", nil, "Colon-separated key/value pair, eg: \"runid:testing\" Tags with which to find matching tasks. Can specify multiple times.")
	pool    = flag.String("pool", "", "Which Swarming pool to use.")
	workdir = flag.String("workdir", ".", "Working directory. Optional, but recommended not to use CWD.")
	state   = flag.String("state", "PENDING", "State the matching tasks should be in. Possible values are: ALL, BOT_DIED, CANCELED, COMPLETED, COMPLETED_FAILURE, COMPLETED_SUCCESS, DEDUPED, EXPIRED, PENDING, PENDING_RUNNING, RUNNING, TIMED_OUT")

	supportedCmds = map[string]bool{
		LIST_CMD:   true,
		CANCEL_CMD: true,
		RETRY_CMD:  true,
	}
)

func main() {
	// Setup, parse args.
	defer common.LogPanic()
	common.Init()

	if _, ok := supportedCmds[*cmd]; !ok {
		glog.Fatalf("--cmd must be one of %v", supportedCmds)
	}
	if tags.String() == "" {
		glog.Fatal("Atleast one --tag is required.")
	}
	if *pool == "" {
		glog.Fatal("--pool is required.")
	}

	var err error
	*workdir, err = filepath.Abs(*workdir)
	if err != nil {
		glog.Fatal(err)
	}

	// Authenticated HTTP client.
	oauthCacheFile := path.Join(*workdir, "google_storage_token.data")
	httpClient, err := auth.NewClient(true, oauthCacheFile, swarming.AUTH_SCOPE)
	if err != nil {
		glog.Fatal(err)
	}

	// Swarming API client.
	swarmApi, err := swarming.NewApiClient(httpClient)
	if err != nil {
		glog.Fatal(err)
	}

	// Obtain the list of tasks.
	tagsWithPool := []string{fmt.Sprintf("pool:%s", *pool)}
	for _, t := range *tags {
		tagsWithPool = append(tagsWithPool, t)
	}
	tasks, err := swarmApi.ListTasks(time.Time{}, time.Time{}, tagsWithPool, *state)
	if err != nil {
		glog.Fatal(err)
	}
	if len(tasks) == 0 {
		glog.Info("Found no matching tasks.")
		return
	}

	if *cmd == LIST_CMD {
		glog.Infof("Found %d tasks...", len(tasks))
		for _, t := range tasks {
			glog.Infof("  %s", getTaskStr(t))
		}
		glog.Infof("Listed %d tasks.", len(tasks))

	} else if *cmd == CANCEL_CMD {
		resp, err := displayTasksAndConfirm(tasks, "canceling")
		if err != nil {
			glog.Fatal(err)
		}
		if resp {
			glog.Infof("Starting cancelation of %d tasks...", len(tasks))
			tasksChannel := getClosedTasksChannel(tasks, false /* dedupNames */)
			var wg sync.WaitGroup
			// Loop through workers in the worker pool.
			for i := 0; i < WORKER_POOL_SIZE; i++ {
				// Increment the WaitGroup counter.
				wg.Add(1)
				// Create and run a goroutine closure that cancels tasks.
				go func() {
					// Decrement the WaitGroup counter when the goroutine completes.
					defer wg.Done()

					for t := range tasksChannel {
						if err := swarmApi.CancelTask(t.TaskId); err != nil {
							glog.Errorf("Could not delete %s: %s", getTaskStr(t), err)
							continue
						}
						glog.Infof("Deleted  %s", getTaskStr(t))
					}
				}()
			}
			// Wait for all spawned goroutines to complete
			wg.Wait()

			glog.Infof("Cancelled %d tasks.", len(tasks))
		}

	} else if *cmd == RETRY_CMD {
		resp, err := displayTasksAndConfirm(tasks, "retrying")
		if err != nil {
			glog.Fatal(err)
		}
		if resp {
			glog.Infof("Starting retries of %d tasks...", len(tasks))
			tasksChannel := getClosedTasksChannel(tasks, true /* dedupNames */)

			var wg sync.WaitGroup
			// Loop through workers in the worker pool.
			for i := 0; i < WORKER_POOL_SIZE; i++ {
				// Increment the WaitGroup counter.
				wg.Add(1)
				// Create and run a goroutine closure that retries tasks.
				go func() {
					// Decrement the WaitGroup counter when the goroutine completes.
					defer wg.Done()

					for t := range tasksChannel {
						if _, err := swarmApi.RetryTask(t); err != nil {
							glog.Errorf("Could not retry %s: %s", getTaskStr(t), err)
							continue
						}
						glog.Infof("Retried  %s", getTaskStr(t))
					}
				}()
			}
			// Wait for all spawned goroutines to complete
			wg.Wait()

			glog.Infof("Retried %d tasks.", len(tasks))
		}
	}
}

func displayTasksAndConfirm(tasks []*swarmingapi.SwarmingRpcsTaskRequestMetadata, verb string) (bool, error) {
	glog.Infof("Found %d tasks. Displaying the first %d:", len(tasks), CONFIRMATION_DISPLAY_LIMIT)
	for _, t := range tasks[:util.MinInt(CONFIRMATION_DISPLAY_LIMIT, len(tasks))] {
		glog.Infof("  %s", getTaskStr(t))
	}
	glog.Infof("Would you like to proceed with %s %d tasks? ('y' or 'n')", verb, len(tasks))
	return askForConfirmation()
}

func askForConfirmation() (bool, error) {
	var response string
	if _, err := fmt.Scanln(&response); err != nil {
		return false, err
	}
	if response == "y" {
		return true, nil
	} else if response == "n" {
		return false, nil
	} else {
		glog.Info("Please type 'y' or 'n' and then press enter:")
		return askForConfirmation()
	}
}

func getClosedTasksChannel(tasks []*swarmingapi.SwarmingRpcsTaskRequestMetadata, dedupNames bool) chan *swarmingapi.SwarmingRpcsTaskRequestMetadata {
	// Create channel that contains specified tasks. This channel will
	// be consumed by the worker pool.
	tasksChannel := make(chan *swarmingapi.SwarmingRpcsTaskRequestMetadata, len(tasks))
	// Dictionary that will be used for deduping by names if dedupNames is true.
	taskNames := map[string]bool{}

	for _, t := range tasks {
		if dedupNames {
			if _, ok := taskNames[t.Request.Name]; ok {
				// Already encountered this task. Continue.
				glog.Errorf("Found another %s: %s", t.Request.Name, t.TaskId)
				continue
			}
		}
		tasksChannel <- t
		taskNames[t.Request.Name] = true
	}
	close(tasksChannel)
	return tasksChannel
}

func getTaskStr(t *swarmingapi.SwarmingRpcsTaskRequestMetadata) string {
	return fmt.Sprintf("Task id: %s  Created: %s  Name: %s", t.TaskId, t.Request.CreatedTs, t.Request.Name)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"

	"github.com/venicegeo/pzsvc-exec/pzse"
	"github.com/venicegeo/pzsvc-exec/pzsvc"
	"github.com/venicegeo/pzsvc-exec/worker/config"
	"github.com/venicegeo/pzsvc-exec/worker/log"
	"github.com/venicegeo/pzsvc-exec/worker/workerexec"

	cli "gopkg.in/urfave/cli.v1"
)

var cliApp *cli.App

func init() {
	cliApp = cli.NewApp()
	cliApp.Name = "pzsvc-worker"
	cliApp.Usage = "run a one-off piazza job in its own process"
	cliApp.Action = runCmd

	cliApp.Flags = []cli.Flag{
		cli.StringFlag{Name: "config", Usage: "JSON pzsvc-exec configuration file (required)"},
		cli.StringFlag{Name: "cliExtra", Usage: "supplemental command arguments to run the Piazza job"},
		cli.StringFlag{Name: "piazzaBaseURL", Usage: "base URL for querying Piazza API (required if not PZ_ADDR)"},
		cli.StringFlag{Name: "piazzaAPIKey", Usage: "API key for use for communicating with Piazza (required if not in vcap)"},
		cli.StringFlag{Name: "userID", Usage: "key authentication string (required)"},
		cli.StringFlag{Name: "serviceID", Usage: "piazza service ID (algorithm name) (required)"},
		cli.StringFlag{Name: "jobID", Usage: "job ID for this run, used for logging"},
		cli.StringSliceFlag{Name: "input, i", Usage: "input source specification (as \"filename:URL\")"},
		cli.StringSliceFlag{Name: "output, o", Usage: "output file name (usable multiple times; at least one required)"},
	}
}

func runCmd(ctx *cli.Context) error {
	cfg := config.WorkerConfig{
		Session:         &pzsvc.Session{AppName: "pzsvc-worker", SessionID: "startup", LogRootDir: "pzsvc-exec"},
		CLICommandExtra: ctx.String("cliExtra"),
		PiazzaBaseURL:   ctx.String("piazzaBaseURL"),
		PiazzaAPIKey:    ctx.String("piazzaAPIKey"),
		PiazzaServiceID: ctx.String("serviceID"),
		UserID:          ctx.String("userID"),
		JobID:           ctx.String("jobID"),
		Inputs:          []config.InputSource{},
		Outputs:         ctx.StringSlice("output"),
		PzSEConfig:      pzse.ConfigType{},
	}
	workerlog.Info(cfg, "startup")

	if ctx.String("config") == "" {
		return cli.NewExitError("pzsvc-exec config file is required", 1)
	}
	if err := cfg.ReadPzSEConfig(ctx.String("config")); err != nil {
		return cli.NewExitError(err, 1)
	}

	if cfg.PiazzaServiceID == "" {
		return cli.NewExitError("Service ID is required", 1)
	}

	if cfg.PiazzaBaseURL == "" {
		cfg.PiazzaBaseURL = os.Getenv(cfg.PzSEConfig.PzAddrEnVar)
	}
	if cfg.PiazzaBaseURL == "" {
		return cli.NewExitError("Piazza base URL is required", 1)
	}
	cfg.Session.PzAddr = cfg.PiazzaBaseURL

	if cfg.PiazzaAPIKey == "" {
		cfg.PiazzaAPIKey = os.Getenv((cfg.PzSEConfig.APIKeyEnVar))
	}
	if cfg.PiazzaAPIKey == "" {
		return cli.NewExitError("Piazza API key is required", 1)
	}
	cfg.Session.PzAuth = cfg.PiazzaAPIKey

	if len(cfg.Outputs) == 0 {
		return cli.NewExitError("1 or more output files are required", 1)
	}

	for _, sourceString := range ctx.StringSlice("input") {
		inFile, err := config.ParseInputSource(sourceString)
		if err != nil {
			return cli.NewExitError(err, 1)
		}
		cfg.Inputs = append(cfg.Inputs, *inFile)
	}

	workerlog.Info(cfg, fmt.Sprintf("config validated: %s", cfg.Serialize()))

	workerlog.Info(cfg, "Starting actual worker execution")
	err := workerexec.WorkerExec(cfg)
	if err != nil {
		workerlog.SimpleErr(cfg, "execution error, quitting with status 1", err)
		return cli.NewExitError(err, 1)
	}

	workerlog.Info(cfg, "worker done, exiting")
	return nil
}

func main() {
	cliApp.Run(os.Args)
}
<commit_msg>Set PzAuth value to header value, not key<commit_after>package main

import (
	"encoding/base64"
	"fmt"
	"os"

	"github.com/venicegeo/pzsvc-exec/pzse"
	"github.com/venicegeo/pzsvc-exec/pzsvc"
	"github.com/venicegeo/pzsvc-exec/worker/config"
	"github.com/venicegeo/pzsvc-exec/worker/log"
	"github.com/venicegeo/pzsvc-exec/worker/workerexec"

	cli "gopkg.in/urfave/cli.v1"
)

var cliApp *cli.App

func init() {
	cliApp = cli.NewApp()
	cliApp.Name = "pzsvc-worker"
	cliApp.Usage = "run a one-off piazza job in its own process"
	cliApp.Action = runCmd

	cliApp.Flags = []cli.Flag{
		cli.StringFlag{Name: "config", Usage: "JSON pzsvc-exec configuration file (required)"},
		cli.StringFlag{Name: "cliExtra", Usage: "supplemental command arguments to run the Piazza job"},
		cli.StringFlag{Name: "piazzaBaseURL", Usage: "base URL for querying Piazza API (required if not PZ_ADDR)"},
		cli.StringFlag{Name: "piazzaAPIKey", Usage: "API key for use for communicating with Piazza (required if not in vcap)"},
		cli.StringFlag{Name: "userID", Usage: "key authentication string (required)"},
		cli.StringFlag{Name: "serviceID", Usage: "piazza service ID (algorithm name) (required)"},
		cli.StringFlag{Name: "jobID", Usage: "job ID for this run, used for logging"},
		cli.StringSliceFlag{Name: "input, i", Usage: "input source specification (as \"filename:URL\")"},
		cli.StringSliceFlag{Name: "output, o", Usage: "output file name (usable multiple times; at least one required)"},
	}
}

func runCmd(ctx *cli.Context) error {
	cfg := config.WorkerConfig{
		Session:         &pzsvc.Session{AppName: "pzsvc-worker", SessionID: "startup", LogRootDir: "pzsvc-exec"},
		CLICommandExtra: ctx.String("cliExtra"),
		PiazzaBaseURL:   ctx.String("piazzaBaseURL"),
		PiazzaAPIKey:    ctx.String("piazzaAPIKey"),
		PiazzaServiceID: ctx.String("serviceID"),
		UserID:          ctx.String("userID"),
		JobID:           ctx.String("jobID"),
		Inputs:          []config.InputSource{},
		Outputs:         ctx.StringSlice("output"),
		PzSEConfig:      pzse.ConfigType{},
	}
	workerlog.Info(cfg, "startup")

	if ctx.String("config") == "" {
		return cli.NewExitError("pzsvc-exec config file is required", 1)
	}
	if err := cfg.ReadPzSEConfig(ctx.String("config")); err != nil {
		return cli.NewExitError(err, 1)
	}

	if cfg.PiazzaServiceID == "" {
		return cli.NewExitError("Service ID is required", 1)
	}

	if cfg.PiazzaBaseURL == "" {
		cfg.PiazzaBaseURL = os.Getenv(cfg.PzSEConfig.PzAddrEnVar)
	}
	if cfg.PiazzaBaseURL == "" {
		return cli.NewExitError("Piazza base URL is required", 1)
	}
	cfg.Session.PzAddr = cfg.PiazzaBaseURL

	if cfg.PiazzaAPIKey == "" {
		cfg.PiazzaAPIKey = os.Getenv((cfg.PzSEConfig.APIKeyEnVar))
	}
	if cfg.PiazzaAPIKey == "" {
		return cli.NewExitError("Piazza API key is required", 1)
	}
	cfg.Session.PzAuth = "Basic " + base64.StdEncoding.EncodeToString([]byte(cfg.PiazzaAPIKey+":"))

	if len(cfg.Outputs) == 0 {
		return cli.NewExitError("1 or more output files are required", 1)
	}

	for _, sourceString := range ctx.StringSlice("input") {
		inFile, err := config.ParseInputSource(sourceString)
		if err != nil {
			return cli.NewExitError(err, 1)
		}
		cfg.Inputs = append(cfg.Inputs, *inFile)
	}

	workerlog.Info(cfg, fmt.Sprintf("config validated: %s", cfg.Serialize()))

	workerlog.Info(cfg, "Starting actual worker execution")
	err := workerexec.WorkerExec(cfg)
	if err != nil {
		workerlog.SimpleErr(cfg, "execution error, quitting with status 1", err)
		return cli.NewExitError(err, 1)
	}

	workerlog.Info(cfg, "worker done, exiting")
	return nil
}

func main() {
	cliApp.Run(os.Args)
}
<|endoftext|>


<commit_before>// Package lm2log implements a commit log on top of lm2.
package lm2log

import (
	"errors"
	"strconv"

	"github.com/Preetam/lm2"
)

const (
	preparedKey  = "prepared"
	committedKey = "committed"
)

var (
	ErrNotFound = errors.New("lm2log: not found")
)

// Log is a commit log.
type Log struct {
	col *lm2.Collection
}

// New initializes a commit log in an lm2 collection.
func New(col *lm2.Collection) (*Log, error) {
	l := &Log{
		col: col,
	}

	wb := lm2.NewWriteBatch()
	wb.Set(committedKey, "0")
	wb.Delete(preparedKey)
	_, err := col.Update(wb)

	return l, err
}

// Open opens an existing commit log in an lm2 collection.
func Open(col *lm2.Collection) (*Log, error) {
	l := &Log{
		col: col,
	}

	cur, err := col.NewCursor()
	if err != nil {
		return nil, err
	}

	// Check committedKey
	_, err = cursorGet(cur, committedKey)
	if err != nil {
		return nil, err
	}

	return l, nil
}

// Prepare durably prepares data in the log.
func (l *Log) Prepare(data string) error {
	cur, err := l.col.NewCursor()
	if err != nil {
		return err
	}

	// Check if something is already prepared.
	if _, err := cursorGet(cur, preparedKey); err == nil {
		return errors.New("lm2col: already prepared data")
	}

	// Prepare
	committedStr, err := cursorGet(cur, committedKey)
	committed, err := strconv.ParseUint(committedStr, 10, 64)
	if err != nil {
		return err
	}

	wb := lm2.NewWriteBatch()
	nextRecordNum := strconv.FormatUint(committed+1, 10)
	wb.Set(nextRecordNum, data)
	wb.Set(preparedKey, nextRecordNum)
	_, err = l.col.Update(wb)
	return err
}

// Rollback clears any prepared data.
func (l *Log) Rollback() error {
	cur, err := l.col.NewCursor()
	if err != nil {
		return err
	}

	if _, err = cursorGet(cur, preparedKey); err != nil {
		if err == ErrNotFound {
			return nil
		}
		return err
	}

	wb := lm2.NewWriteBatch()
	wb.Delete(preparedKey)
	_, err = l.col.Update(wb)
	return err
}

// Commit marks the prepared data as committed.
func (l *Log) Commit() error {
	cur, err := l.col.NewCursor()
	if err != nil {
		return err
	}

	// Check if something is already prepared.
	prepared, err := cursorGet(cur, preparedKey)
	if err != nil {
		return errors.New("lm2col: couldn't get prepared data")
	}

	// Commit
	wb := lm2.NewWriteBatch()
	wb.Set(committedKey, prepared)
	wb.Delete(preparedKey)
	_, err = l.col.Update(wb)

	return err
}

// Prepared returns the currently prepared record number.
func (l *Log) Prepared() (uint64, error) {
	cur, err := l.col.NewCursor()
	if err != nil {
		return 0, err
	}

	// Check if something is already prepared.
	prepared, err := cursorGet(cur, preparedKey)
	if err != nil {
		return 0, errors.New("lm2col: couldn't get prepared data")
	}

	return strconv.ParseUint(prepared, 10, 64)
}

// Committed returns the latest committed record number.
func (l *Log) Committed() (uint64, error) {
	cur, err := l.col.NewCursor()
	if err != nil {
		return 0, err
	}

	committed, err := cursorGet(cur, committedKey)
	if err != nil {
		return 0, errors.New("lm2col: couldn't get committed data")
	}

	return strconv.ParseUint(committed, 10, 64)
}

// Get retrieves data in the commit log associated with the given record number.
func (l *Log) Get(record uint64) (string, error) {
	cur, err := l.col.NewCursor()
	if err != nil {
		return "", err
	}

	// Check if something is already prepared.
	data, err := cursorGet(cur, strconv.FormatUint(record, 10))
	if err != nil {
		return "", errors.New("lm2col: couldn't get record")
	}
	return data, nil
}

// SetCommitted updates the data at the given record number and updates
// any internal state accordingly.
func (l *Log) SetCommitted(record uint64, data string) error {
	cur, err := l.col.NewCursor()
	if err != nil {
		return err
	}

	wb := lm2.NewWriteBatch()
	recordStr := strconv.FormatUint(record, 10)
	committedStr, err := cursorGet(cur, committedKey)
	committed, err := strconv.ParseUint(committedStr, 10, 64)
	if err != nil {
		return err
	}
	if committed < record {
		wb.Set(committedStr, recordStr)
	}

	wb.Set(recordStr, data)
	_, err = l.col.Update(wb)
	return err
}

func cursorGet(cur *lm2.Cursor, key string) (string, error) {
	cur.Seek(key)
	for cur.Next() {
		if cur.Key() > key {
			break
		}
		if cur.Key() == key {
			return cur.Value(), nil
		}
	}
	return "", ErrNotFound
}
<commit_msg>handle ErrNotFound in Commit and Prepared<commit_after>// Package lm2log implements a commit log on top of lm2.
package lm2log

import (
	"errors"
	"strconv"

	"github.com/Preetam/lm2"
)

const (
	preparedKey  = "prepared"
	committedKey = "committed"
)

var (
	ErrNotFound = errors.New("lm2log: not found")
)

// Log is a commit log.
type Log struct {
	col *lm2.Collection
}

// New initializes a commit log in an lm2 collection.
func New(col *lm2.Collection) (*Log, error) {
	l := &Log{
		col: col,
	}

	wb := lm2.NewWriteBatch()
	wb.Set(committedKey, "0")
	wb.Delete(preparedKey)
	_, err := col.Update(wb)

	return l, err
}

// Open opens an existing commit log in an lm2 collection.
func Open(col *lm2.Collection) (*Log, error) {
	l := &Log{
		col: col,
	}

	cur, err := col.NewCursor()
	if err != nil {
		return nil, err
	}

	// Check committedKey
	_, err = cursorGet(cur, committedKey)
	if err != nil {
		return nil, err
	}

	return l, nil
}

// Prepare durably prepares data in the log.
func (l *Log) Prepare(data string) error {
	cur, err := l.col.NewCursor()
	if err != nil {
		return err
	}

	// Check if something is already prepared.
	if _, err := cursorGet(cur, preparedKey); err == nil {
		return errors.New("lm2col: already prepared data")
	}

	// Prepare
	committedStr, err := cursorGet(cur, committedKey)
	committed, err := strconv.ParseUint(committedStr, 10, 64)
	if err != nil {
		return err
	}

	wb := lm2.NewWriteBatch()
	nextRecordNum := strconv.FormatUint(committed+1, 10)
	wb.Set(nextRecordNum, data)
	wb.Set(preparedKey, nextRecordNum)
	_, err = l.col.Update(wb)
	return err
}

// Rollback clears any prepared data.
func (l *Log) Rollback() error {
	cur, err := l.col.NewCursor()
	if err != nil {
		return err
	}

	if _, err = cursorGet(cur, preparedKey); err != nil {
		if err == ErrNotFound {
			return nil
		}
		return err
	}

	wb := lm2.NewWriteBatch()
	wb.Delete(preparedKey)
	_, err = l.col.Update(wb)
	return err
}

// Commit marks the prepared data as committed.
func (l *Log) Commit() error {
	cur, err := l.col.NewCursor()
	if err != nil {
		return err
	}

	// Check if something is already prepared.
	prepared, err := cursorGet(cur, preparedKey)
	if err != nil {
		if err == ErrNotFound {
			return nil
		}
		return errors.New("lm2col: couldn't get prepared data")
	}

	// Commit
	wb := lm2.NewWriteBatch()
	wb.Set(committedKey, prepared)
	wb.Delete(preparedKey)
	_, err = l.col.Update(wb)

	return err
}

// Prepared returns the currently prepared record number.
func (l *Log) Prepared() (uint64, error) {
	cur, err := l.col.NewCursor()
	if err != nil {
		return 0, err
	}

	// Check if something is already prepared.
	prepared, err := cursorGet(cur, preparedKey)
	if err != nil {
		if err == ErrNotFound {
			return 0, ErrNotFound
		}
		return 0, errors.New("lm2col: couldn't get prepared data")
	}

	return strconv.ParseUint(prepared, 10, 64)
}

// Committed returns the latest committed record number.
func (l *Log) Committed() (uint64, error) {
	cur, err := l.col.NewCursor()
	if err != nil {
		return 0, err
	}

	committed, err := cursorGet(cur, committedKey)
	if err != nil {
		return 0, errors.New("lm2col: couldn't get committed data")
	}

	return strconv.ParseUint(committed, 10, 64)
}

// Get retrieves data in the commit log associated with the given record number.
func (l *Log) Get(record uint64) (string, error) {
	cur, err := l.col.NewCursor()
	if err != nil {
		return "", err
	}

	// Check if something is already prepared.
	data, err := cursorGet(cur, strconv.FormatUint(record, 10))
	if err != nil {
		return "", errors.New("lm2col: couldn't get record")
	}
	return data, nil
}

// SetCommitted updates the data at the given record number and updates
// any internal state accordingly.
func (l *Log) SetCommitted(record uint64, data string) error {
	cur, err := l.col.NewCursor()
	if err != nil {
		return err
	}

	wb := lm2.NewWriteBatch()
	recordStr := strconv.FormatUint(record, 10)
	committedStr, err := cursorGet(cur, committedKey)
	committed, err := strconv.ParseUint(committedStr, 10, 64)
	if err != nil {
		return err
	}
	if committed < record {
		wb.Set(committedStr, recordStr)
	}

	wb.Set(recordStr, data)
	_, err = l.col.Update(wb)
	return err
}

func cursorGet(cur *lm2.Cursor, key string) (string, error) {
	cur.Seek(key)
	for cur.Next() {
		if cur.Key() > key {
			break
		}
		if cur.Key() == key {
			return cur.Value(), nil
		}
	}
	return "", ErrNotFound
}
<|endoftext|>


<commit_before>// Loads up a UAS manifest from an XML file.
package uas

import (
  "encoding/xml"
  "io"
  "regexp"
)

var regMatcher *regexp.Regexp

func init() {
  regMatcher = regexp.MustCompile("^/(?P<reg>.*)/(?P<flags>[imsU]*)$")
}

func compileBrowserRegs(manifest *Manifest) {
  for i, reg := range manifest.Data.BrowsersReg {
    manifest.Data.BrowsersReg[i].Reg = regexp.MustCompile(
      regMatcher.ReplaceAllString(reg.RegString, "(?${flags}:${reg})"))
  }
}

func compileOsRegs(manifest *Manifest) {
  for i, reg := range manifest.Data.OperatingSystemsReg {
    manifest.Data.OperatingSystemsReg[i].Reg = regexp.MustCompile(
      regMatcher.ReplaceAllString(reg.RegString, "(?${flags}:${reg})"))
  }
}

func compileDeviceRegs(manifest *Manifest) {
  for i, reg := range manifest.Data.DevicesReg {
    manifest.Data.DevicesReg[i].Reg = regexp.MustCompile(
      regMatcher.ReplaceAllString(reg.RegString, "(?${flags}:${reg})"))
  }
}

func Load(reader io.Reader) (*Manifest, error) {
  var manifest Manifest
  if err := xml.NewDecoder(reader).Decode(&manifest); err != nil {
    return nil, err
  }
  compileBrowserRegs(&manifest)
  compileOsRegs(&manifest)
  compileDeviceRegs(&manifest)
  return &manifest, nil
}
<commit_msg>refactoring regex compilation methods in loader<commit_after>// Loads up a UAS manifest from an XML file.
package uas

import (
  "encoding/xml"
  "io"
  "regexp"
)

var regMatcher *regexp.Regexp

func init() {
  regMatcher = regexp.MustCompile("^/(?P<reg>.*)/(?P<flags>[imsU]*)$")
}

func compileReg(reg string) *regexp.Regexp {
  return regexp.MustCompile(regMatcher.ReplaceAllString(reg, "(?${flags}:${reg})"))
}

func compileBrowserRegs(data *Data) {
  regs := data.BrowsersReg
  for i, reg := range regs {
    regs[i].Reg = compileReg(reg.RegString)
  }
}

func compileOsRegs(data *Data) {
  regs := data.OperatingSystemsReg
  for i, reg := range regs {
    regs[i].Reg = compileReg(reg.RegString)
  }
}

func compileDeviceRegs(data *Data) {
  regs := data.DevicesReg
  for i, reg := range regs {
    regs[i].Reg = compileReg(reg.RegString)
  }
}

func Load(reader io.Reader) (*Manifest, error) {
  manifest := &Manifest{}
  if err := xml.NewDecoder(reader).Decode(manifest); err != nil {
    return nil, err
  }
  compileBrowserRegs(manifest.Data)
  compileOsRegs(manifest.Data)
  compileDeviceRegs(manifest.Data)
  return manifest, nil
}
<|endoftext|>


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

// +build darwin linux,!android

// Package audio provides a basic audio player.
package audio

import (
	"fmt"
	"io"
	"sync"
	"time"

	"golang.org/x/mobile/audio/al"
	"golang.org/x/mobile/audio/alc"
)

// Format represents an PCM data format.
type Format string

const (
	Mono8    = Format("mono8")
	Mono16   = Format("mono16")
	Stereo8  = Format("stereo8")
	Stereo16 = Format("stereo16")
)

var formatToCode = map[Format]int32{
	Mono8:    al.FormatMono8,
	Mono16:   al.FormatMono16,
	Stereo8:  al.FormatStereo8,
	Stereo16: al.FormatStereo16,
}

// State indicates the current playing state of the player.
type State string

const (
	Unknown = State("unknown")
	Initial = State("initial")
	Playing = State("playing")
	Paused  = State("paused")
	Stopped = State("stopped")
)

var codeToState = map[int32]State{
	0:          Unknown,
	al.Initial: Initial,
	al.Playing: Playing,
	al.Paused:  Paused,
	al.Stopped: Stopped,
}

var device struct {
	sync.Mutex
	d *alc.Device
}

type track struct {
	format           Format
	samplesPerSecond int64
	src              io.ReadSeeker
}

// Player is a basic audio player that plays PCM data.
// Operations on a nil *Player are no-op, a nil *Player can
// be used for testing purposes.
type Player struct {
	t      *track
	source al.Source

	mu        sync.Mutex
	prep      bool
	bufs      []al.Buffer // buffers are created and queued to source during prepare.
	sizeBytes int64       // size of the audio source
}

// NewPlayer returns a new Player.
// It initializes the underlying audio devices and the related resources.
func NewPlayer(src io.ReadSeeker, format Format, samplesPerSecond int64) (*Player, error) {
	device.Lock()
	defer device.Unlock()

	if device.d == nil {
		device.d = alc.Open("")
		c := device.d.CreateContext(nil)
		if !alc.MakeContextCurrent(c) {
			return nil, fmt.Errorf("audio: cannot initiate a new player")
		}
	}
	s := al.GenSources(1)
	if code := al.Error(); code != 0 {
		return nil, fmt.Errorf("audio: cannot generate an audio source [err=%x]", code)
	}
	return &Player{
		t:      &track{format: format, src: src, samplesPerSecond: samplesPerSecond},
		source: s[0],
	}, nil
}

func (p *Player) prepare(offset int64, force bool) error {
	p.mu.Lock()
	if !force && p.prep {
		p.mu.Unlock()
		return nil
	}
	p.mu.Unlock()

	if _, err := p.t.src.Seek(offset, 0); err != nil {
		return err
	}
	var bufs []al.Buffer
	// TODO(jbd): Limit the number of buffers in use, unqueue and reuse
	// the existing buffers as buffers are processed.
	buf := make([]byte, 128*1024)
	size := offset
	for {
		n, err := p.t.src.Read(buf)
		if n > 0 {
			size += int64(n)
			b := al.GenBuffers(1)
			b[0].BufferData(uint32(formatToCode[p.t.format]), buf[:n], int32(p.t.samplesPerSecond))
			bufs = append(bufs, b[0])
		}
		if err == io.EOF {
			break
		}
		if err != nil {
			return err
		}
	}

	p.mu.Lock()
	if len(p.bufs) > 0 {
		p.source.UnqueueBuffers(p.bufs)
		al.DeleteBuffers(p.bufs)
	}
	p.sizeBytes = size
	p.bufs = bufs
	p.prep = true
	if len(bufs) > 0 {
		p.source.QueueBuffers(bufs)
	}
	p.mu.Unlock()
	return nil
}

// Play buffers the source audio to the audio device and starts
// to play the source.
// If the player paused or stopped, it reuses the previously buffered
// resources to keep playing from the time it has paused or stopped.
func (p *Player) Play() error {
	if p == nil {
		return nil
	}
	// Prepares if the track hasn't been buffered before.
	if err := p.prepare(0, false); err != nil {
		return err
	}
	al.PlaySources(p.source)
	return lastErr()
}

// Pause pauses the player.
func (p *Player) Pause() error {
	if p == nil {
		return nil
	}
	al.PauseSources(p.source)
	return lastErr()
}

// Stop stops the player.
func (p *Player) Stop() error {
	if p == nil {
		return nil
	}
	al.StopSources(p.source)
	return lastErr()
}

// Seek moves the play head to the given offset relative to the start of the source.
func (p *Player) Seek(offset time.Duration) error {
	if p == nil {
		return nil
	}
	if err := p.Stop(); err != nil {
		return err
	}
	size := durToByteOffset(p.t, offset)
	if err := p.prepare(size, true); err != nil {
		return err
	}
	al.PlaySources(p.source)
	return lastErr()
}

// Current returns the current playback position of the audio that is being played.
func (p *Player) Current() time.Duration {
	if p == nil {
		return 0
	}
	// TODO(jbd): Current never returns the Total when the playing is finished.
	// OpenAL may be returning the last buffer's start point as an OffsetByte.
	return byteOffsetToDur(p.t, int64(p.source.OffsetByte()))
}

// Total returns the total duration of the audio source.
func (p *Player) Total() time.Duration {
	if p == nil {
		return 0
	}
	// Prepare is required to determine the length of the source.
	// We need to read the entire source to calculate the length.
	p.prepare(0, false)
	return byteOffsetToDur(p.t, p.sizeBytes)
}

// Volume returns the current player volume. The range of the volume is [0, 1].
func (p *Player) Volume() float64 {
	if p == nil {
		return 0
	}
	return float64(p.source.Gain())
}

// SetVolume sets the volume of the player. The range of the volume is [0, 1].
func (p *Player) SetVolume(vol float64) {
	if p == nil {
		return
	}
	p.source.SetGain(float32(vol))
}

// State returns the player's current state.
func (p *Player) State() State {
	if p == nil {
		return Unknown
	}
	return codeToState[p.source.State()]
}

// Destroy frees the underlying resources used by the player.
// It should be called as soon as the player is not in-use anymore.
func (p *Player) Destroy() {
	if p == nil {
		return
	}
	if p.source != 0 {
		al.DeleteSources(p.source)
	}
	p.mu.Lock()
	if len(p.bufs) > 0 {
		al.DeleteBuffers(p.bufs)
	}
	p.mu.Unlock()
}

func byteOffsetToDur(t *track, offset int64) time.Duration {
	samples := offset
	if t.format == Mono16 || t.format == Stereo16 {
		samples /= 2
	}
	if t.format == Stereo8 || t.format == Stereo16 {
		samples /= 2
	}
	return time.Duration(samples * int64(time.Second) / t.samplesPerSecond)
}

func durToByteOffset(t *track, dur time.Duration) int64 {
	size := t.samplesPerSecond * int64(dur) / int64(time.Second)
	if t.format == Mono16 || t.format == Stereo16 {
		// Each sample is represented by 16-bits. Move twice further.
		size *= 2
	}
	if t.format == Stereo8 || t.format == Stereo16 {
		size *= 2
	}
	return size
}

// lastErr returns the last error or nil if the last operation
// has been succesful.
func lastErr() error {
	if code := al.Error(); code != 0 {
		return fmt.Errorf("audio: openal failed with %x", code)
	}
	return nil
}

// TODO(jbd): Destroy context, close the device.
<commit_msg>audio: use int constants (C style enums) instead of string.<commit_after>// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build darwin linux,!android

// Package audio provides a basic audio player.
package audio

import (
	"fmt"
	"io"
	"sync"
	"time"

	"golang.org/x/mobile/audio/al"
	"golang.org/x/mobile/audio/alc"
)

// Format represents an PCM data format.
type Format int

const (
	Mono8 Format = iota
	Mono16
	Stereo8
	Stereo16
)

func (f Format) String() string { return formatStrings[f] }

// formatBytes is the product of bytes per sample and number of channels.
var formatBytes = [...]int64{
	Mono8:    1,
	Mono16:   2,
	Stereo8:  2,
	Stereo16: 4,
}

var formatCodes = [...]uint32{
	Mono8:    al.FormatMono8,
	Mono16:   al.FormatMono16,
	Stereo8:  al.FormatStereo8,
	Stereo16: al.FormatStereo16,
}

var formatStrings = [...]string{
	Mono8:    "mono8",
	Mono16:   "mono16",
	Stereo8:  "stereo8",
	Stereo16: "stereo16",
}

// State indicates the current playing state of the player.
type State int

const (
	Unknown State = iota
	Initial
	Playing
	Paused
	Stopped
)

func (s State) String() string { return stateStrings[s] }

var stateStrings = [...]string{
	Unknown: "unknown",
	Initial: "initial",
	Playing: "playing",
	Paused:  "paused",
	Stopped: "stopped",
}

var codeToState = map[int32]State{
	0:          Unknown,
	al.Initial: Initial,
	al.Playing: Playing,
	al.Paused:  Paused,
	al.Stopped: Stopped,
}

var device struct {
	sync.Mutex
	d *alc.Device
}

type track struct {
	format           Format
	samplesPerSecond int64
	src              io.ReadSeeker
}

// Player is a basic audio player that plays PCM data.
// Operations on a nil *Player are no-op, a nil *Player can
// be used for testing purposes.
type Player struct {
	t      *track
	source al.Source

	mu        sync.Mutex
	prep      bool
	bufs      []al.Buffer // buffers are created and queued to source during prepare.
	sizeBytes int64       // size of the audio source
}

// NewPlayer returns a new Player.
// It initializes the underlying audio devices and the related resources.
func NewPlayer(src io.ReadSeeker, format Format, samplesPerSecond int64) (*Player, error) {
	device.Lock()
	defer device.Unlock()

	if device.d == nil {
		device.d = alc.Open("")
		c := device.d.CreateContext(nil)
		if !alc.MakeContextCurrent(c) {
			return nil, fmt.Errorf("audio: cannot initiate a new player")
		}
	}
	s := al.GenSources(1)
	if code := al.Error(); code != 0 {
		return nil, fmt.Errorf("audio: cannot generate an audio source [err=%x]", code)
	}
	return &Player{
		t:      &track{format: format, src: src, samplesPerSecond: samplesPerSecond},
		source: s[0],
	}, nil
}

func (p *Player) prepare(offset int64, force bool) error {
	p.mu.Lock()
	if !force && p.prep {
		p.mu.Unlock()
		return nil
	}
	p.mu.Unlock()

	if _, err := p.t.src.Seek(offset, 0); err != nil {
		return err
	}
	var bufs []al.Buffer
	// TODO(jbd): Limit the number of buffers in use, unqueue and reuse
	// the existing buffers as buffers are processed.
	buf := make([]byte, 128*1024)
	size := offset
	for {
		n, err := p.t.src.Read(buf)
		if n > 0 {
			size += int64(n)
			b := al.GenBuffers(1)
			b[0].BufferData(formatCodes[p.t.format], buf[:n], int32(p.t.samplesPerSecond))
			bufs = append(bufs, b[0])
		}
		if err == io.EOF {
			break
		}
		if err != nil {
			return err
		}
	}

	p.mu.Lock()
	if len(p.bufs) > 0 {
		p.source.UnqueueBuffers(p.bufs)
		al.DeleteBuffers(p.bufs)
	}
	p.sizeBytes = size
	p.bufs = bufs
	p.prep = true
	if len(bufs) > 0 {
		p.source.QueueBuffers(bufs)
	}
	p.mu.Unlock()
	return nil
}

// Play buffers the source audio to the audio device and starts
// to play the source.
// If the player paused or stopped, it reuses the previously buffered
// resources to keep playing from the time it has paused or stopped.
func (p *Player) Play() error {
	if p == nil {
		return nil
	}
	// Prepares if the track hasn't been buffered before.
	if err := p.prepare(0, false); err != nil {
		return err
	}
	al.PlaySources(p.source)
	return lastErr()
}

// Pause pauses the player.
func (p *Player) Pause() error {
	if p == nil {
		return nil
	}
	al.PauseSources(p.source)
	return lastErr()
}

// Stop stops the player.
func (p *Player) Stop() error {
	if p == nil {
		return nil
	}
	al.StopSources(p.source)
	return lastErr()
}

// Seek moves the play head to the given offset relative to the start of the source.
func (p *Player) Seek(offset time.Duration) error {
	if p == nil {
		return nil
	}
	if err := p.Stop(); err != nil {
		return err
	}
	size := durToByteOffset(p.t, offset)
	if err := p.prepare(size, true); err != nil {
		return err
	}
	al.PlaySources(p.source)
	return lastErr()
}

// Current returns the current playback position of the audio that is being played.
func (p *Player) Current() time.Duration {
	if p == nil {
		return 0
	}
	// TODO(jbd): Current never returns the Total when the playing is finished.
	// OpenAL may be returning the last buffer's start point as an OffsetByte.
	return byteOffsetToDur(p.t, int64(p.source.OffsetByte()))
}

// Total returns the total duration of the audio source.
func (p *Player) Total() time.Duration {
	if p == nil {
		return 0
	}
	// Prepare is required to determine the length of the source.
	// We need to read the entire source to calculate the length.
	p.prepare(0, false)
	return byteOffsetToDur(p.t, p.sizeBytes)
}

// Volume returns the current player volume. The range of the volume is [0, 1].
func (p *Player) Volume() float64 {
	if p == nil {
		return 0
	}
	return float64(p.source.Gain())
}

// SetVolume sets the volume of the player. The range of the volume is [0, 1].
func (p *Player) SetVolume(vol float64) {
	if p == nil {
		return
	}
	p.source.SetGain(float32(vol))
}

// State returns the player's current state.
func (p *Player) State() State {
	if p == nil {
		return Unknown
	}
	return codeToState[p.source.State()]
}

// Destroy frees the underlying resources used by the player.
// It should be called as soon as the player is not in-use anymore.
func (p *Player) Destroy() {
	if p == nil {
		return
	}
	if p.source != 0 {
		al.DeleteSources(p.source)
	}
	p.mu.Lock()
	if len(p.bufs) > 0 {
		al.DeleteBuffers(p.bufs)
	}
	p.mu.Unlock()
}

func byteOffsetToDur(t *track, offset int64) time.Duration {
	return time.Duration(offset * formatBytes[t.format] * int64(time.Second) / t.samplesPerSecond)
}

func durToByteOffset(t *track, dur time.Duration) int64 {
	return int64(dur) * t.samplesPerSecond / (formatBytes[t.format] * int64(time.Second))
}

// lastErr returns the last error or nil if the last operation
// has been succesful.
func lastErr() error {
	if code := al.Error(); code != 0 {
		return fmt.Errorf("audio: openal failed with %x", code)
	}
	return nil
}

// TODO(jbd): Destroy context, close the device.
<|endoftext|>


<commit_before>package sched

import (
	"bytes"
	"fmt"
	"html/template"
	"io"
	"log"
	"net/url"
	"os"
	"strings"
	"time"

	"github.com/StackExchange/bosun/_third_party/github.com/StackExchange/scollector/opentsdb"
	"github.com/StackExchange/bosun/conf"
	"github.com/StackExchange/bosun/expr"
	"github.com/StackExchange/bosun/expr/parse"
)

type Context struct {
	*State
	Alert *conf.Alert

	schedule *Schedule
}

func (s *Schedule) Data(st *State, a *conf.Alert) *Context {
	return &Context{
		State:    st,
		Alert:    a,
		schedule: s,
	}
}

type unknownContext struct {
	Time  time.Time
	Name  string
	Group expr.AlertKeys

	schedule *Schedule
}

func (s *Schedule) unknownData(t time.Time, name string, group expr.AlertKeys) *unknownContext {
	return &unknownContext{
		Time:     t,
		Group:    group,
		Name:     name,
		schedule: s,
	}
}

// URL returns a prepopulated URL for external access, with path and query empty.
func (s *Schedule) URL() *url.URL {
	u := url.URL{
		Scheme: "http",
		Host:   s.Conf.HttpListen,
	}
	if strings.HasPrefix(s.Conf.HttpListen, ":") {
		h, err := os.Hostname()
		if err != nil {
			u.Host = "localhost" + u.Host
		} else {
			u.Host = h + u.Host
		}
	}
	return &u
}

// Ack returns the URL to acknowledge an alert.
func (c *Context) Ack() string {
	u := c.schedule.URL()
	u.Path = "/action"
	u.RawQuery = url.Values{
		"type": []string{"ack"},
		"key":  []string{c.Alert.Name + c.State.Group.String()},
	}.Encode()
	return u.String()
}

// HostView returns the URL to the host view page.
func (c *Context) HostView(host string) string {
	u := c.schedule.URL()
	u.Path = "/host"
	u.RawQuery = fmt.Sprintf("time=1d-ago&host=%s", host)
	return u.String()
}

func (c *Context) Expr(v string) string {
	q := url.QueryEscape("q=" + opentsdb.ReplaceTags(v, c.Group))
	u := url.URL{
		Scheme:   "http",
		Host:     c.schedule.Conf.HttpListen,
		Path:     "/expr",
		RawQuery: q,
	}
	if strings.HasPrefix(c.schedule.Conf.HttpListen, ":") {
		h, err := os.Hostname()
		if err != nil {
			return ""
		}
		u.Host = h + u.Host
	}
	return u.String()
}

func (s *Schedule) ExecuteBody(w io.Writer, a *conf.Alert, st *State) error {
	t := a.Template
	if t == nil || t.Body == nil {
		return nil
	}
	return t.Body.Execute(w, s.Data(st, a))
}

func (s *Schedule) ExecuteSubject(w io.Writer, a *conf.Alert, st *State) error {
	t := a.Template
	if t == nil || t.Subject == nil {
		return nil
	}
	return t.Subject.Execute(w, s.Data(st, a))
}

func (c *Context) eval(v string, filter bool, series bool, autods int) ([]*expr.Result, error) {
	e, err := expr.New(v)
	var results []*expr.Result
	if err != nil {
		return results, fmt.Errorf("%s: %v", v, err)
	}
	if series && e.Root.Return() != parse.TYPE_SERIES {
		return results, fmt.Errorf("egraph: requires an expression that returns a series")
	}
	res, _, err := e.Execute(c.schedule.cache, nil, c.schedule.CheckStart, autods, c.Alert.UnjoinedOK, c.schedule.Search, c.schedule.Lookups)
	if err != nil {
		return results, fmt.Errorf("%s: %v", v, err)
	}
	if filter {
		for _, r := range res.Results {
			if r.Group.Equal(c.State.Group) {
				results = append(results, r)
				return results, nil
			}
		}
		for _, r := range res.Results {
			if c.State.Group.Subset(r.Group) {
				results = append(results, r)
				return results, nil
			}
		}
	}
	return res.Results, nil
}

// Eval executes the given expression and returns a value with corresponding tags
// to the context's tags. If no such result is found, the first result with nil
// tags is returned. If no such result is found, "" is returned.
func (c *Context) Eval(v string) interface{} {
	res, err := c.eval(v, true, false, 0)
	if err != nil {
		log.Print(err)
		return ""
	}
	if len(res) != 1 {
		log.Printf("Expected 1 results, got %v", len(res))
		return ""
	}
	return res[0].Value
}

// EvalAll executes the expression and returns the result set. It is not filtered
// to the context's tags.
func (c *Context) EvalAll(v string) interface{} {
	res, err := c.eval(v, false, false, 0)
	if err != nil {
		log.Print(err)
		return ""
	}
	return res
}

func (c *Context) graph(v string, res []*expr.Result) interface{} {
	var buf bytes.Buffer
	if err := c.schedule.ExprGraph(nil, &buf, res, v, time.Now().UTC()); err != nil {
		return err.Error()
	}
	return template.HTML(buf.String())
}

func (c *Context) Graph(v string) interface{} {
	res, err := c.eval(v, false, true, 1000)
	if err != nil {
		log.Print(err)
		return ""
	}
	return c.graph(v, res)
}

func (c *Context) GraphAll(v string) interface{} {
	res, err := c.eval(v, true, true, 1000)
	if err != nil {
		log.Print(err)
		return ""
	}
	return c.graph(v, res)
}
<commit_msg>Changes from code review<commit_after>package sched

import (
	"bytes"
	"fmt"
	"html/template"
	"io"
	"log"
	"net/url"
	"os"
	"strings"
	"time"

	"github.com/StackExchange/bosun/_third_party/github.com/StackExchange/scollector/opentsdb"
	"github.com/StackExchange/bosun/conf"
	"github.com/StackExchange/bosun/expr"
	"github.com/StackExchange/bosun/expr/parse"
)

type Context struct {
	*State
	Alert *conf.Alert

	schedule *Schedule
}

func (s *Schedule) Data(st *State, a *conf.Alert) *Context {
	return &Context{
		State:    st,
		Alert:    a,
		schedule: s,
	}
}

type unknownContext struct {
	Time  time.Time
	Name  string
	Group expr.AlertKeys

	schedule *Schedule
}

func (s *Schedule) unknownData(t time.Time, name string, group expr.AlertKeys) *unknownContext {
	return &unknownContext{
		Time:     t,
		Group:    group,
		Name:     name,
		schedule: s,
	}
}

// URL returns a prepopulated URL for external access, with path and query empty.
func (s *Schedule) URL() *url.URL {
	u := url.URL{
		Scheme: "http",
		Host:   s.Conf.HttpListen,
	}
	if strings.HasPrefix(s.Conf.HttpListen, ":") {
		h, err := os.Hostname()
		if err != nil {
			u.Host = "localhost" + u.Host
		} else {
			u.Host = h + u.Host
		}
	}
	return &u
}

// Ack returns the URL to acknowledge an alert.
func (c *Context) Ack() string {
	u := c.schedule.URL()
	u.Path = "/action"
	u.RawQuery = url.Values{
		"type": []string{"ack"},
		"key":  []string{c.Alert.Name + c.State.Group.String()},
	}.Encode()
	return u.String()
}

// HostView returns the URL to the host view page.
func (c *Context) HostView(host string) string {
	u := c.schedule.URL()
	u.Path = "/host"
	u.RawQuery = fmt.Sprintf("time=1d-ago&host=%s", host)
	return u.String()
}

func (c *Context) Expr(v string) string {
	q := url.QueryEscape("q=" + opentsdb.ReplaceTags(v, c.Group))
	u := url.URL{
		Scheme:   "http",
		Host:     c.schedule.Conf.HttpListen,
		Path:     "/expr",
		RawQuery: q,
	}
	if strings.HasPrefix(c.schedule.Conf.HttpListen, ":") {
		h, err := os.Hostname()
		if err != nil {
			return ""
		}
		u.Host = h + u.Host
	}
	return u.String()
}

func (s *Schedule) ExecuteBody(w io.Writer, a *conf.Alert, st *State) error {
	t := a.Template
	if t == nil || t.Body == nil {
		return nil
	}
	return t.Body.Execute(w, s.Data(st, a))
}

func (s *Schedule) ExecuteSubject(w io.Writer, a *conf.Alert, st *State) error {
	t := a.Template
	if t == nil || t.Subject == nil {
		return nil
	}
	return t.Subject.Execute(w, s.Data(st, a))
}

func (c *Context) eval(v string, filter bool, series bool, autods int) ([]*expr.Result, error) {
	e, err := expr.New(v)
	var results []*expr.Result
	if err != nil {
		return results, fmt.Errorf("%s: %v", v, err)
	}
	if series && e.Root.Return() != parse.TYPE_SERIES {
		return results, fmt.Errorf("egraph: requires an expression that returns a series")
	}
	res, _, err := e.Execute(c.schedule.cache, nil, c.schedule.CheckStart, autods, c.Alert.UnjoinedOK, c.schedule.Search, c.schedule.Lookups)
	if err != nil {
		return results, fmt.Errorf("%s: %v", v, err)
	}
	if !filter {
		return res.Results, nil
	}
	for _, r := range res.Results {
		if r.Group.Equal(c.State.Group) {
			results = append(results, r)
			return results, nil
		}
	}
	for _, r := range res.Results {
		if c.State.Group.Subset(r.Group) {
			results = append(results, r)
			return results, nil
		}
	}
	return nil, nil
}

// Eval executes the given expression and returns a value with corresponding tags
// to the context's tags. If no such result is found, the first result with nil
// tags is returned. If no such result is found, "" is returned.
func (c *Context) Eval(v string) interface{} {
	res, err := c.eval(v, true, false, 0)
	if err != nil {
		log.Print(err)
		return 0
	}
	if len(res) != 1 {
		log.Printf("Expected 1 results, got %v", len(res))
		return 0
	}
	return res[0].Value
}

// EvalAll executes the expression and returns the result set. It is not filtered
// to the context's tags.
func (c *Context) EvalAll(v string) interface{} {
	res, err := c.eval(v, false, false, 0)
	if err != nil {
		log.Print(err)
		return nil
	}
	return res
}

func (c *Context) graph(v string, res []*expr.Result) interface{} {
	var buf bytes.Buffer
	if err := c.schedule.ExprGraph(nil, &buf, res, v, time.Now().UTC()); err != nil {
		return err.Error()
	}
	return template.HTML(buf.String())
}

func (c *Context) Graph(v string) interface{} {
	res, err := c.eval(v, false, true, 1000)
	if err != nil {
		log.Print(err)
		return ""
	}
	return c.graph(v, res)
}

func (c *Context) GraphAll(v string) interface{} {
	res, err := c.eval(v, true, true, 1000)
	if err != nil {
		log.Print(err)
		return ""
	}
	return c.graph(v, res)
}
<|endoftext|>


<commit_before>package builder

import (
	"fmt"
	"io/ioutil"
	"net"
	"net/url"
	"os"
	"path/filepath"
	"regexp"
	"strings"
	"time"

	"github.com/fsouza/go-dockerclient"
	"github.com/openshift/origin/pkg/build/api"
	"github.com/openshift/source-to-image/pkg/sti/git"
	"github.com/openshift/source-to-image/pkg/sti/tar"
)

// urlCheckTimeout is the timeout used to check the source URL
// If fetching the URL exceeeds the timeout, then the build will
// not proceed further and stop
const urlCheckTimeout = 16 * time.Second

// imageRegex is used to substitute image names in buildconfigs with immutable image ids at build time.
var imageRegex = regexp.MustCompile(`^FROM\s+\w+.+`)

// DockerBuilder builds Docker images given a git repository URL
type DockerBuilder struct {
	dockerClient DockerClient
	authPresent  bool
	auth         docker.AuthConfiguration
	git          git.Git
	tar          tar.Tar
	build        *api.Build
	urlTimeout   time.Duration
}

// NewDockerBuilder creates a new instance of DockerBuilder
func NewDockerBuilder(dockerClient DockerClient, authCfg docker.AuthConfiguration, authPresent bool, build *api.Build) *DockerBuilder {
	return &DockerBuilder{
		dockerClient: dockerClient,
		authPresent:  authPresent,
		auth:         authCfg,
		build:        build,
		git:          git.NewGit(),
		tar:          tar.NewTar(),
		urlTimeout:   urlCheckTimeout,
	}
}

// Build executes a Docker build
func (d *DockerBuilder) Build() error {
	buildDir, err := ioutil.TempDir("", "docker-build")
	if err != nil {
		return err
	}
	if err = d.fetchSource(buildDir); err != nil {
		return err
	}
	if err = d.addBuildParameters(buildDir); err != nil {
		return err
	}
	if err = d.dockerBuild(buildDir); err != nil {
		return err
	}
	tag := d.build.Parameters.Output.DockerImageReference
	defer removeImage(d.dockerClient, tag)
	if len(d.build.Parameters.Output.DockerImageReference) != 0 {
		return pushImage(d.dockerClient, tag, d.auth)
	}
	return nil
}

// checkSourceURI performs a check on the URI associated with the build
// to make sure that it is live before proceeding with the build.
func (d *DockerBuilder) checkSourceURI() error {
	rawurl := d.build.Parameters.Source.Git.URI
	if !d.git.ValidCloneSpec(rawurl) {
		return fmt.Errorf("Invalid git source url: %s", rawurl)
	}
	if strings.HasPrefix(rawurl, "git://") || strings.HasPrefix(rawurl, "git@") {
		return nil
	}
	if !strings.HasPrefix(rawurl, "http://") && !strings.HasPrefix(rawurl, "https://") {
		rawurl = fmt.Sprintf("https://%s", rawurl)
	}
	srcURL, err := url.Parse(rawurl)
	if err != nil {
		return err
	}
	host := srcURL.Host
	if strings.Index(host, ":") == -1 {
		switch srcURL.Scheme {
		case "http":
			host += ":80"
		case "https":
			host += ":443"
		}
	}
	dialer := net.Dialer{Timeout: d.urlTimeout}
	conn, err := dialer.Dial("tcp", host)
	if err != nil {
		return err
	}
	return conn.Close()

}

// fetchSource retrieves the git source from the repository. If a commit ID
// is included in the build revision, that commit ID is checked out. Otherwise
// if a ref is included in the source definition, that ref is checked out.
func (d *DockerBuilder) fetchSource(dir string) error {
	if err := d.checkSourceURI(); err != nil {
		return err
	}
	if err := d.git.Clone(d.build.Parameters.Source.Git.URI, dir); err != nil {
		return err
	}
	if d.build.Parameters.Source.Git.Ref == "" &&
		(d.build.Parameters.Revision == nil ||
			d.build.Parameters.Revision.Git == nil ||
			d.build.Parameters.Revision.Git.Commit == "") {
		return nil
	}
	if d.build.Parameters.Revision != nil &&
		d.build.Parameters.Revision.Git != nil &&
		d.build.Parameters.Revision.Git.Commit != "" {
		return d.git.Checkout(dir, d.build.Parameters.Revision.Git.Commit)
	}
	return d.git.Checkout(dir, d.build.Parameters.Source.Git.Ref)
}

// addBuildParameters checks if a BaseImage is set to replace the default base image.
// If that's the case then change the Dockerfile to make the build with the given image.
// Also append the environment variables in the Dockerfile.
func (d *DockerBuilder) addBuildParameters(dir string) error {
	dockerfilePath := filepath.Join(dir, "Dockerfile")
	if d.build.Parameters.Strategy.DockerStrategy != nil && len(d.build.Parameters.Strategy.DockerStrategy.ContextDir) > 0 {
		dockerfilePath = filepath.Join(dir, d.build.Parameters.Strategy.DockerStrategy.ContextDir, "Dockerfile")
	}

	fileStat, err := os.Lstat(dockerfilePath)
	filePerm := fileStat.Mode()

	fileData, err := ioutil.ReadFile(dockerfilePath)
	if err != nil {
		return err
	}

	var newFileData string
	if d.build.Parameters.Strategy.DockerStrategy.BaseImage != "" {
		newFileData = imageRegex.ReplaceAllLiteralString(string(fileData), fmt.Sprintf("FROM %s", d.build.Parameters.Strategy.DockerStrategy.BaseImage))
	} else {
		newFileData = newFileData + string(fileData)
	}

	envVars := getBuildEnvVars(d.build)
	for k, v := range envVars {
		newFileData = newFileData + fmt.Sprintf("ENV %s %s\n", k, v)
	}

	if ioutil.WriteFile(dockerfilePath, []byte(newFileData), filePerm); err != nil {
		return err
	}

	return nil
}

// dockerBuild performs a docker build on the source that has been retrieved
func (d *DockerBuilder) dockerBuild(dir string) error {
	var noCache bool
	if d.build.Parameters.Strategy.DockerStrategy != nil {
		if d.build.Parameters.Strategy.DockerStrategy.ContextDir != "" {
			dir = filepath.Join(dir, d.build.Parameters.Strategy.DockerStrategy.ContextDir)
		}
		noCache = d.build.Parameters.Strategy.DockerStrategy.NoCache
	}
	return buildImage(d.dockerClient, dir, noCache, d.build.Parameters.Output.DockerImageReference, d.tar)
}
<commit_msg>check for error on missing docker file<commit_after>package builder

import (
	"fmt"
	"io/ioutil"
	"net"
	"net/url"
	"os"
	"path/filepath"
	"regexp"
	"strings"
	"time"

	"github.com/fsouza/go-dockerclient"
	"github.com/openshift/origin/pkg/build/api"
	"github.com/openshift/source-to-image/pkg/sti/git"
	"github.com/openshift/source-to-image/pkg/sti/tar"
)

// urlCheckTimeout is the timeout used to check the source URL
// If fetching the URL exceeeds the timeout, then the build will
// not proceed further and stop
const urlCheckTimeout = 16 * time.Second

// imageRegex is used to substitute image names in buildconfigs with immutable image ids at build time.
var imageRegex = regexp.MustCompile(`^FROM\s+\w+.+`)

// DockerBuilder builds Docker images given a git repository URL
type DockerBuilder struct {
	dockerClient DockerClient
	authPresent  bool
	auth         docker.AuthConfiguration
	git          git.Git
	tar          tar.Tar
	build        *api.Build
	urlTimeout   time.Duration
}

// NewDockerBuilder creates a new instance of DockerBuilder
func NewDockerBuilder(dockerClient DockerClient, authCfg docker.AuthConfiguration, authPresent bool, build *api.Build) *DockerBuilder {
	return &DockerBuilder{
		dockerClient: dockerClient,
		authPresent:  authPresent,
		auth:         authCfg,
		build:        build,
		git:          git.NewGit(),
		tar:          tar.NewTar(),
		urlTimeout:   urlCheckTimeout,
	}
}

// Build executes a Docker build
func (d *DockerBuilder) Build() error {
	buildDir, err := ioutil.TempDir("", "docker-build")
	if err != nil {
		return err
	}
	if err = d.fetchSource(buildDir); err != nil {
		return err
	}
	if err = d.addBuildParameters(buildDir); err != nil {
		return err
	}
	if err = d.dockerBuild(buildDir); err != nil {
		return err
	}
	tag := d.build.Parameters.Output.DockerImageReference
	defer removeImage(d.dockerClient, tag)
	if len(d.build.Parameters.Output.DockerImageReference) != 0 {
		return pushImage(d.dockerClient, tag, d.auth)
	}
	return nil
}

// checkSourceURI performs a check on the URI associated with the build
// to make sure that it is live before proceeding with the build.
func (d *DockerBuilder) checkSourceURI() error {
	rawurl := d.build.Parameters.Source.Git.URI
	if !d.git.ValidCloneSpec(rawurl) {
		return fmt.Errorf("Invalid git source url: %s", rawurl)
	}
	if strings.HasPrefix(rawurl, "git://") || strings.HasPrefix(rawurl, "git@") {
		return nil
	}
	if !strings.HasPrefix(rawurl, "http://") && !strings.HasPrefix(rawurl, "https://") {
		rawurl = fmt.Sprintf("https://%s", rawurl)
	}
	srcURL, err := url.Parse(rawurl)
	if err != nil {
		return err
	}
	host := srcURL.Host
	if strings.Index(host, ":") == -1 {
		switch srcURL.Scheme {
		case "http":
			host += ":80"
		case "https":
			host += ":443"
		}
	}
	dialer := net.Dialer{Timeout: d.urlTimeout}
	conn, err := dialer.Dial("tcp", host)
	if err != nil {
		return err
	}
	return conn.Close()

}

// fetchSource retrieves the git source from the repository. If a commit ID
// is included in the build revision, that commit ID is checked out. Otherwise
// if a ref is included in the source definition, that ref is checked out.
func (d *DockerBuilder) fetchSource(dir string) error {
	if err := d.checkSourceURI(); err != nil {
		return err
	}
	if err := d.git.Clone(d.build.Parameters.Source.Git.URI, dir); err != nil {
		return err
	}
	if d.build.Parameters.Source.Git.Ref == "" &&
		(d.build.Parameters.Revision == nil ||
			d.build.Parameters.Revision.Git == nil ||
			d.build.Parameters.Revision.Git.Commit == "") {
		return nil
	}
	if d.build.Parameters.Revision != nil &&
		d.build.Parameters.Revision.Git != nil &&
		d.build.Parameters.Revision.Git.Commit != "" {
		return d.git.Checkout(dir, d.build.Parameters.Revision.Git.Commit)
	}
	return d.git.Checkout(dir, d.build.Parameters.Source.Git.Ref)
}

// addBuildParameters checks if a BaseImage is set to replace the default base image.
// If that's the case then change the Dockerfile to make the build with the given image.
// Also append the environment variables in the Dockerfile.
func (d *DockerBuilder) addBuildParameters(dir string) error {
	dockerfilePath := filepath.Join(dir, "Dockerfile")
	if d.build.Parameters.Strategy.DockerStrategy != nil && len(d.build.Parameters.Strategy.DockerStrategy.ContextDir) > 0 {
		dockerfilePath = filepath.Join(dir, d.build.Parameters.Strategy.DockerStrategy.ContextDir, "Dockerfile")
	}

	fileStat, err := os.Lstat(dockerfilePath)
	if err != nil {
		return err
	}

	filePerm := fileStat.Mode()

	fileData, err := ioutil.ReadFile(dockerfilePath)
	if err != nil {
		return err
	}

	var newFileData string
	if d.build.Parameters.Strategy.DockerStrategy.BaseImage != "" {
		newFileData = imageRegex.ReplaceAllLiteralString(string(fileData), fmt.Sprintf("FROM %s", d.build.Parameters.Strategy.DockerStrategy.BaseImage))
	} else {
		newFileData = newFileData + string(fileData)
	}

	envVars := getBuildEnvVars(d.build)
	for k, v := range envVars {
		newFileData = newFileData + fmt.Sprintf("ENV %s %s\n", k, v)
	}

	if ioutil.WriteFile(dockerfilePath, []byte(newFileData), filePerm); err != nil {
		return err
	}

	return nil
}

// dockerBuild performs a docker build on the source that has been retrieved
func (d *DockerBuilder) dockerBuild(dir string) error {
	var noCache bool
	if d.build.Parameters.Strategy.DockerStrategy != nil {
		if d.build.Parameters.Strategy.DockerStrategy.ContextDir != "" {
			dir = filepath.Join(dir, d.build.Parameters.Strategy.DockerStrategy.ContextDir)
		}
		noCache = d.build.Parameters.Strategy.DockerStrategy.NoCache
	}
	return buildImage(d.dockerClient, dir, noCache, d.build.Parameters.Output.DockerImageReference, d.tar)
}
<|endoftext|>


<commit_before>// Package file provides ...
package file

import (
	"os"
	"path/filepath"
	"text/template"
	"time"

	"github.com/eiblog/eiblog/pkg/cache"
	"github.com/eiblog/eiblog/pkg/config"
	"github.com/eiblog/eiblog/tools"

	"github.com/sirupsen/logrus"
)

var xmlTmpl *template.Template

func init() {
	root := filepath.Join(config.WorkDir, "conf", "tpl", "*.xml")

	var err error
	xmlTmpl, err = template.New("").Funcs(template.FuncMap{
		"dateformat": tools.DateFormat,
	}).ParseGlob(root)
	if err != nil {
		panic(err)
	}
	generateOpensearch()
	generateRobots()
	generateCrossdomain()
	go timerFeed()
	go timerSitemap()
}

// timerFeed 定时刷新feed
func timerFeed() {
	tpl := xmlTmpl.Lookup("feedTpl.xml")
	if tpl == nil {
		logrus.Info("file: not found: feedTpl.xml")
		return
	}

	now := time.Now()
	_, _, articles := cache.Ei.PageArticleFE(1, 20)
	params := map[string]interface{}{
		"Titile":    cache.Ei.Blogger.BTitle,
		"SubTitle":  cache.Ei.Blogger.SubTitle,
		"Host":      config.Conf.BlogApp.Host,
		"FeedrURL":  config.Conf.BlogApp.FeedRPC.FeedrURL,
		"BuildDate": now.Format(time.RFC1123Z),
		"Articles":  articles,
	}
	f, err := os.OpenFile("assets/feed.xml", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
	if err != nil {
		logrus.Error("file: timerFeed.OpenFile: ", err)
		return
	}
	defer f.Close()
	err = tpl.Execute(f, params)
	if err != nil {
		logrus.Error("file: timerFeed.Execute: ", err)
		return
	}
	time.AfterFunc(time.Hour*4, timerFeed)
}

// timerSitemap 定时刷新sitemap
func timerSitemap() {
	tpl := xmlTmpl.Lookup("sitemapTpl.xml")
	if tpl == nil {
		logrus.Info("file: not found: sitemapTpl.xml")
		return
	}

	params := map[string]interface{}{
		"Articles": cache.Ei.Articles,
		"Host":     config.Conf.BlogApp.Host,
	}
	f, err := os.OpenFile("assets/sitemap.xml", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
	if err != nil {
		logrus.Error("file: timerSitemap.OpenFile: ", err)
		return
	}
	defer f.Close()
	err = tpl.Execute(f, params)
	if err != nil {
		logrus.Error("file: timerSitemap.Execute: ", err)
		return
	}
	time.AfterFunc(time.Hour*24, timerSitemap)
}

// generateOpensearch 生成opensearch.xml
func generateOpensearch() {
	tpl := xmlTmpl.Lookup("opensearchTpl.xml")
	if tpl == nil {
		logrus.Info("file: not found: opensearchTpl.xml")
		return
	}
	params := map[string]string{
		"BTitle":   cache.Ei.Blogger.BTitle,
		"SubTitle": cache.Ei.Blogger.SubTitle,
		"Host":     config.Conf.BlogApp.Host,
	}
	f, err := os.OpenFile("assets/opensearch.xml", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
	if err != nil {
		logrus.Error("file: generateOpensearch.OpenFile: ", err)
		return
	}
	defer f.Close()
	err = tpl.Execute(f, params)
	if err != nil {
		logrus.Error("file: generateOpensearch.Execute: ", err)
		return
	}
}

// generateRobots 生成robots.txt
func generateRobots() {
	tpl := xmlTmpl.Lookup("robotsTpl.xml")
	if tpl == nil {
		logrus.Info("file: not found: robotsTpl.xml")
		return
	}
	params := map[string]string{
		"Host": config.Conf.BlogApp.Host,
	}
	f, err := os.OpenFile("assets/robots.txt", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
	if err != nil {
		logrus.Error("file: generateRobots.OpenFile: ", err)
		return
	}
	defer f.Close()
	err = tpl.Execute(f, params)
	if err != nil {
		logrus.Error("file: generateRobots.Execute: ", err)
		return
	}
}

// generateCrossdomain 生成crossdomain.xml
func generateCrossdomain() {
	tpl := xmlTmpl.Lookup("crossdomainTpl.xml")
	if tpl == nil {
		logrus.Info("file: not found: crossdomainTpl.xml")
		return
	}
	params := map[string]string{
		"Host": config.Conf.BlogApp.Host,
	}
	f, err := os.OpenFile("assets/crossdomain.xml", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
	if err != nil {
		logrus.Error("file: generateCrossdomain.OpenFile: ", err)
		return
	}
	defer f.Close()
	err = tpl.Execute(f, params)
	if err != nil {
		logrus.Error("file: generateCrossdomain.Execute: ", err)
		return
	}
}
<commit_msg>fix: filed name<commit_after>// Package file provides ...
package file

import (
	"os"
	"path/filepath"
	"text/template"
	"time"

	"github.com/eiblog/eiblog/pkg/cache"
	"github.com/eiblog/eiblog/pkg/config"
	"github.com/eiblog/eiblog/tools"

	"github.com/sirupsen/logrus"
)

var xmlTmpl *template.Template

func init() {
	root := filepath.Join(config.WorkDir, "conf", "tpl", "*.xml")

	var err error
	xmlTmpl, err = template.New("").Funcs(template.FuncMap{
		"dateformat": tools.DateFormat,
	}).ParseGlob(root)
	if err != nil {
		panic(err)
	}
	generateOpensearch()
	generateRobots()
	generateCrossdomain()
	go timerFeed()
	go timerSitemap()
}

// timerFeed 定时刷新feed
func timerFeed() {
	tpl := xmlTmpl.Lookup("feedTpl.xml")
	if tpl == nil {
		logrus.Info("file: not found: feedTpl.xml")
		return
	}

	now := time.Now()
	_, _, articles := cache.Ei.PageArticleFE(1, 20)
	params := map[string]interface{}{
		"Title":     cache.Ei.Blogger.BTitle,
		"SubTitle":  cache.Ei.Blogger.SubTitle,
		"Host":      config.Conf.BlogApp.Host,
		"FeedrURL":  config.Conf.BlogApp.FeedRPC.FeedrURL,
		"BuildDate": now.Format(time.RFC1123Z),
		"Articles":  articles,
	}
	f, err := os.OpenFile("assets/feed.xml", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
	if err != nil {
		logrus.Error("file: timerFeed.OpenFile: ", err)
		return
	}
	defer f.Close()
	err = tpl.Execute(f, params)
	if err != nil {
		logrus.Error("file: timerFeed.Execute: ", err)
		return
	}
	time.AfterFunc(time.Hour*4, timerFeed)
}

// timerSitemap 定时刷新sitemap
func timerSitemap() {
	tpl := xmlTmpl.Lookup("sitemapTpl.xml")
	if tpl == nil {
		logrus.Info("file: not found: sitemapTpl.xml")
		return
	}

	params := map[string]interface{}{
		"Articles": cache.Ei.Articles,
		"Host":     config.Conf.BlogApp.Host,
	}
	f, err := os.OpenFile("assets/sitemap.xml", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
	if err != nil {
		logrus.Error("file: timerSitemap.OpenFile: ", err)
		return
	}
	defer f.Close()
	err = tpl.Execute(f, params)
	if err != nil {
		logrus.Error("file: timerSitemap.Execute: ", err)
		return
	}
	time.AfterFunc(time.Hour*24, timerSitemap)
}

// generateOpensearch 生成opensearch.xml
func generateOpensearch() {
	tpl := xmlTmpl.Lookup("opensearchTpl.xml")
	if tpl == nil {
		logrus.Info("file: not found: opensearchTpl.xml")
		return
	}
	params := map[string]string{
		"BTitle":   cache.Ei.Blogger.BTitle,
		"SubTitle": cache.Ei.Blogger.SubTitle,
		"Host":     config.Conf.BlogApp.Host,
	}
	f, err := os.OpenFile("assets/opensearch.xml", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
	if err != nil {
		logrus.Error("file: generateOpensearch.OpenFile: ", err)
		return
	}
	defer f.Close()
	err = tpl.Execute(f, params)
	if err != nil {
		logrus.Error("file: generateOpensearch.Execute: ", err)
		return
	}
}

// generateRobots 生成robots.txt
func generateRobots() {
	tpl := xmlTmpl.Lookup("robotsTpl.xml")
	if tpl == nil {
		logrus.Info("file: not found: robotsTpl.xml")
		return
	}
	params := map[string]string{
		"Host": config.Conf.BlogApp.Host,
	}
	f, err := os.OpenFile("assets/robots.txt", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
	if err != nil {
		logrus.Error("file: generateRobots.OpenFile: ", err)
		return
	}
	defer f.Close()
	err = tpl.Execute(f, params)
	if err != nil {
		logrus.Error("file: generateRobots.Execute: ", err)
		return
	}
}

// generateCrossdomain 生成crossdomain.xml
func generateCrossdomain() {
	tpl := xmlTmpl.Lookup("crossdomainTpl.xml")
	if tpl == nil {
		logrus.Info("file: not found: crossdomainTpl.xml")
		return
	}
	params := map[string]string{
		"Host": config.Conf.BlogApp.Host,
	}
	f, err := os.OpenFile("assets/crossdomain.xml", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
	if err != nil {
		logrus.Error("file: generateCrossdomain.OpenFile: ", err)
		return
	}
	defer f.Close()
	err = tpl.Execute(f, params)
	if err != nil {
		logrus.Error("file: generateCrossdomain.Execute: ", err)
		return
	}
}
<|endoftext|>