<commit_before>package cli_test

import (
	"bytes"
	"fmt"
	"github.com/appcelerator/amp/api/server"
	"gopkg.in/yaml.v2"
	"io/ioutil"
	"math/rand"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"regexp"
	"strings"
	"testing"
	"text/template"
	"time"
)

type TestSpec struct {
	Name     string
	Commands []CommandSpec
}

type CommandSpec struct {
	Cmd               string   `yaml:"cmd"`
	Args              []string `yaml:"args"`
	Options           []string `yaml:"options"`
	Expectation       string   `yaml:"expectation"`
	ExpectErrorStatus bool     `yaml:"expectErrorStatus"`
	Retry             int      `yaml:"retry"`
	Timeout           int64    `yaml:"timeout"`
	Delay             int64    `yaml:"delay"`
}

const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"

var (
	testDir   = "./test_samples"
	lookupDir = "./lookup"
	regexMap  map[string]string
)

func TestMain(m *testing.M) {
	server.StartTestServer()
	os.Exit(m.Run())
}

func TestCmds(t *testing.T) {
	err := loadRegexLookup()
	if err != nil {
		t.Errorf("Unable to load lookup specs, reason: %v", err)
		return
	}

	tests, err := loadTestSpecs()
	if err != nil {
		t.Errorf("unable to load test specs, reason: %v", err)
		return
	}

	for _, test := range tests {
		t.Log("-----------------------------------------------------------------------------------------")
		t.Logf("Running spec: %s", test.Name)
		if err := runTestSpec(t, test); err != nil {
			t.Error(err)
			return
		}
	}
}

func loadTestSpecs() ([]*TestSpec, error) {
	files, err := ioutil.ReadDir(testDir)
	if err != nil {
		return nil, err
	}

	tests := []*TestSpec{}
	for _, file := range files {
		test, err := loadTestSpec(path.Join(testDir, file.Name()))
		if err != nil {
			return nil, err
		}
		if test != nil {
			tests = append(tests, test)
		}
	}
	return tests, nil
}

func loadTestSpec(fileName string) (*TestSpec, error) {
	if filepath.Ext(fileName) != ".yml" {
		return nil, nil
	}
	content, err := ioutil.ReadFile(fileName)
	if err != nil {
		return nil, fmt.Errorf("unable to load test spec: %s. Error: %v", fileName, err)
	}
	testSpec := &TestSpec{
		Name: fileName,
	}

	var commandMap []CommandSpec
	if err := yaml.Unmarshal(content, &commandMap); err != nil {
		return nil, fmt.Errorf("unable to parse test spec: %s. Error: %v", fileName, err)
	}

	// Keep values only
	for _, command := range commandMap {
		testSpec.Commands = append(testSpec.Commands, command)
	}

	return testSpec, nil
}

func runTestSpec(t *testing.T, test *TestSpec) (err error) {
	var i int
	var startTime, endTime int64
	var tmplString []string
	var cache = map[string]string{}

	for _, cmdSpec := range test.Commands {
		startTime = time.Now().UnixNano() / 1000000
		for i = -1; i < cmdSpec.Retry; i++ {
			cmdString := generateCmdString(&cmdSpec)
			tmplOutput, tmplErr := performTemplating(strings.Join(cmdString, " "), cache)
			if tmplErr != nil {
				return fmt.Errorf("Executing templating failed: %s", tmplErr)
			}
			tmplString := strings.Fields(tmplOutput)
			t.Logf("Running: %s", strings.Join(tmplString, " "))
			actualOutput, cmdErr := exec.Command(tmplString[0], tmplString[1:]...).CombinedOutput()
			expectedOutput := regexp.MustCompile(cmdSpec.Expectation)

			if !expectedOutput.MatchString(string(actualOutput)) {
				return fmt.Errorf("miss matched expected output: %s", actualOutput)
			}
			if cmdErr != nil && !cmdSpec.ExpectErrorStatus {
				return fmt.Errorf("Command was expected to exit with zero status but got: %v", cmdErr)
			}
			if cmdErr == nil && cmdSpec.ExpectErrorStatus {
				return fmt.Errorf("Command was expected to exit with error status but exited with zero")
			}

			endTime = time.Now().UnixNano() / 1000000
			if cmdSpec.Timeout != 0 && endTime-startTime >= cmdSpec.Timeout {
				return fmt.Errorf("Command execution has exceeded timeout : %s", tmplString)
			}
			if err == nil {
				break
			}
			time.Sleep(time.Duration(cmdSpec.Delay) * time.Millisecond)
		}

		if i > 0 && i == cmdSpec.Retry {
			t.Log("This command :", tmplString, "has re-run", i, "times.")

		}
	}
	return
}

func generateCmdString(cmdSpec *CommandSpec) (cmdString []string) {
	cmdSplit := strings.Fields(cmdSpec.Cmd)
	optionsSplit := []string{}
	for _, val := range cmdSpec.Options {
		optionsSplit = append(optionsSplit, strings.Fields(val)...)
	}
	cmdString = append(cmdSplit, cmdSpec.Args...)
	cmdString = append(cmdString, optionsSplit...)
	if regexMap[cmdSpec.Expectation] != "" {
		cmdSpec.Expectation = regexMap[cmdSpec.Expectation]
	}
	return
}

func loadRegexLookup() error {
	files, err := ioutil.ReadDir(lookupDir)
	if err != nil {
		return err
	}
	for _, file := range files {
		err := parseLookup(path.Join(lookupDir, file.Name()))
		if err != nil {
			return err
		}
	}
	return nil
}

func parseLookup(file string) error {
	if filepath.Ext(file) != ".yml" {
		return nil
	}
	pairs, err := ioutil.ReadFile(file)
	if err != nil {
		return fmt.Errorf("Unable to load regex lookup: %s. Error: %v", file, err)
	}
	if err := yaml.Unmarshal(pairs, &regexMap); err != nil {
		return fmt.Errorf("Unable to parse regex lookup: %s. Error: %v", file, err)
	}
	return nil
}

func performTemplating(s string, cache map[string]string) (output string, err error) {
	fmt.Println(s)
	var t *template.Template
	t, err = template.New("Command").Parse(s)
	if err != nil {
		return
	}
	f := func(in string) string {
		if val, ok := cache[in]; ok {
			return val
		}
		out := in + "-" + randString(10)
		cache[in] = out
		return out
	}
	var doc bytes.Buffer
	var fm = template.FuncMap{
		"uniq": func(in string) string { return f(in) },
	}
	err = t.Execute(&doc, fm)
	if err != nil {
		return
	}
	output = doc.String()
	fmt.Println(output)
	return
}

func randString(n int) string {
	b := make([]byte, n)
	for i := range b {
		b[i] = letterBytes[rand.Intn(len(letterBytes))]
	}
	return string(b)
}
<commit_msg>Minor fix to retry + Cleanup (#427)<commit_after>package cli_test

import (
	"fmt"
	"os"
	"os/exec"

	"bytes"
	"io/ioutil"
	"math/rand"
	"path"
	"path/filepath"
	"regexp"
	"strings"
	"testing"
	"text/template"
	"time"

	"github.com/appcelerator/amp/api/server"
	"gopkg.in/yaml.v2"
)

type TestSpec struct {
	Name     string
	Commands []CommandSpec
}

type CommandSpec struct {
	Cmd               string   `yaml:"cmd"`
	Args              []string `yaml:"args"`
	Options           []string `yaml:"options"`
	Expectation       string   `yaml:"expectation"`
	Retry             int      `yaml:"retry"`
	Timeout           int64    `yaml:"timeout"`
	Delay             int64    `yaml:"delay"`
}

const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"

var (
	testDir   = "./test_samples"
	lookupDir = "./lookup"
	regexMap  map[string]string
)

func TestMain(m *testing.M) {
	server.StartTestServer()
	os.Exit(m.Run())
}

func TestCmds(t *testing.T) {
	err := loadRegexLookup()
	if err != nil {
		t.Errorf("Unable to load lookup specs, reason: %v", err)
		return
	}
	tests, err := loadTestSpecs()
	if err != nil {
		t.Errorf("unable to load test specs, reason: %v", err)
		return
	}
	for _, test := range tests {
		t.Log("-----------------------------------------------------------------------------------------")
		t.Logf("Running spec: %s", test.Name)
		if err := runTestSpec(t, test); err != nil {
			t.Error(err)
			return
		}
	}
}

func loadTestSpecs() ([]*TestSpec, error) {
	files, err := ioutil.ReadDir(testDir)
	if err != nil {
		return nil, err
	}
	tests := []*TestSpec{}
	for _, file := range files {
		test, err := loadTestSpec(path.Join(testDir, file.Name()))
		if err != nil {
			return nil, err
		}
		if test != nil {
			tests = append(tests, test)
		}
	}
	return tests, nil
}

func loadTestSpec(fileName string) (*TestSpec, error) {
	if filepath.Ext(fileName) != ".yml" {
		return nil, nil
	}
	content, err := ioutil.ReadFile(fileName)
	if err != nil {
		return nil, fmt.Errorf("unable to load test spec: %s. Error: %v", fileName, err)
	}
	testSpec := &TestSpec{
		Name: fileName,
	}

	var commandMap []CommandSpec
	if err := yaml.Unmarshal(content, &commandMap); err != nil {
		return nil, fmt.Errorf("unable to parse test spec: %s. Error: %v", fileName, err)
	}

	for _, command := range commandMap {
		testSpec.Commands = append(testSpec.Commands, command)
	}
	return testSpec, nil
}

func runTestSpec(t *testing.T, test *TestSpec) (err error) {
	var i int
	var cache = map[string]string{}

	for _, cmdSpec := range test.Commands {
		var tmplString []string
		startTime := time.Now().UnixNano() / 1000000

		for i = -1; i < cmdSpec.Retry; i++ {
			cmdString := generateCmdString(&cmdSpec)
			tmplOutput, tmplErr := performTemplating(strings.Join(cmdString, " "), cache)
			if tmplErr != nil {
				err = fmt.Errorf("Executing templating failed: %s", tmplErr)
				t.Log(err)
			}
			tmplString := strings.Fields(tmplOutput)

			t.Logf("Running: %s", strings.Join(tmplString, " "))
			cmdOutput, cmdErr := exec.Command(tmplString[0], tmplString[1:]...).CombinedOutput()
			expectedOutput := regexp.MustCompile(cmdSpec.Expectation)
			if !expectedOutput.MatchString(string(cmdOutput)) {
				err = fmt.Errorf("miss matched expected output: %s : Error: %v", cmdOutput, cmdErr)
				t.Log(err)
			}

			endTime := time.Now().UnixNano() / 1000000
			if cmdSpec.Timeout != 0 && endTime-startTime >= cmdSpec.Timeout {
				return fmt.Errorf("Command execution has exceeded timeout : %s", tmplString)
			}
			if err == nil {
				break
			}
			time.Sleep(time.Duration(cmdSpec.Delay) * time.Millisecond)
		}
		if i > 0 && i == cmdSpec.Retry {
			t.Log("This command :", tmplString, "has re-run", i, "times.")
		}
	}
	return
}

func generateCmdString(cmdSpec *CommandSpec) (cmdString []string) {
	cmdSplit := strings.Fields(cmdSpec.Cmd)
	optionsSplit := []string{}
	for _, val := range cmdSpec.Options {
		optionsSplit = append(optionsSplit, strings.Fields(val)...)
	}
	cmdString = append(cmdSplit, cmdSpec.Args...)
	cmdString = append(cmdString, optionsSplit...)
	if regexMap[cmdSpec.Expectation] != "" {
		cmdSpec.Expectation = regexMap[cmdSpec.Expectation]
	}
	return
}

func loadRegexLookup() error {
	files, err := ioutil.ReadDir(lookupDir)
	if err != nil {
		return err
	}
	for _, file := range files {
		err := parseLookup(path.Join(lookupDir, file.Name()))
		if err != nil {
			return err
		}
	}
	return nil
}

func parseLookup(file string) error {
	if filepath.Ext(file) != ".yml" {
		return nil
	}
	pairs, err := ioutil.ReadFile(file)
	if err != nil {
		return fmt.Errorf("Unable to load regex lookup: %s. Error: %v", file, err)
	}
	if err := yaml.Unmarshal(pairs, &regexMap); err != nil {
		return fmt.Errorf("Unable to parse regex lookup: %s. Error: %v", file, err)
	}
	return nil
}

func performTemplating(s string, cache map[string]string) (output string, err error) {
	fmt.Println(s)
	var t *template.Template
	t, err = template.New("Command").Parse(s)
	if err != nil {
		return
	}
	f := func(in string) string {
		if val, ok := cache[in]; ok {
			return val
		}
		out := in + "-" + randString(10)
		cache[in] = out
		return out
	}
	var doc bytes.Buffer
	var fm = template.FuncMap{
		"uniq": func(in string) string { return f(in) },
	}
	err = t.Execute(&doc, fm)
	if err != nil {
		return
	}
	output = doc.String()
	fmt.Println(output)
	return
}

func randString(n int) string {
	b := make([]byte, n)
	for i := range b {
		b[i] = letterBytes[rand.Intn(len(letterBytes))]
	}
	return string(b)
}
<|endoftext|>


<commit_before>/*
Copyright 2011 Google Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"errors"
	"flag"
	"fmt"
	"strings"
	"time"

	"camlistore.org/pkg/client"
	"camlistore.org/pkg/cmdmain"
	"camlistore.org/pkg/schema"
)

type permanodeCmd struct {
	name    string
	tag     string
	key     string // else random
	sigTime string
}

func init() {
	cmdmain.RegisterCommand("permanode", func(flags *flag.FlagSet) cmdmain.CommandRunner {
		cmd := new(permanodeCmd)
		flags.StringVar(&cmd.name, "name", "", "Optional name attribute to set on new permanode")
		flags.StringVar(&cmd.tag, "tag", "", "Optional tag(s) to set on new permanode; comma separated.")
		flags.StringVar(&cmd.key, "key", "", "Optional key to create deterministic ('planned') permanodes. Must also use --sigtime.")
		flags.StringVar(&cmd.sigTime, "sigtime", "", "Optional time to put in the OpenPGP signature packet instead of the current time. Required when producing a deterministic permanode (with --key). In format YYYY-MM-DD HH:MM:SS")
		return cmd
	})
}

func (c *permanodeCmd) Describe() string {
	return "Create and upload a permanode."
}

func (c *permanodeCmd) Usage() {
	cmdmain.Errorf("Usage: camput [globalopts] permanode [permanodeopts]\n")
}

func (c *permanodeCmd) Examples() []string {
	return []string{
		"                               (create a new permanode)",
		`-name="Some Name" -tag=foo,bar (with attributes added)`,
	}
}

func (c *permanodeCmd) RunCommand(args []string) error {
	if len(args) > 0 {
		return errors.New("Permanode command doesn't take any additional arguments")
	}

	var (
		permaNode *client.PutResult
		err       error
		up        = getUploader()
	)
	if (c.key != "") != (c.sigTime != "") {
		return errors.New("Both --key and --sigtime must be used to produce deterministic permanodes.")
	}
	if c.key == "" {
		// Normal case, with a random permanode.
		permaNode, err = up.UploadNewPermanode()
	} else {
		const format = "2006-01-02 15:04:05"
		sigTime, err := time.Parse(format, c.sigTime)
		if err != nil {
			return fmt.Errorf("Error parsing time %q; expecting time of form %q", c.sigTime, format)
		}
		permaNode, err = up.UploadPlannedPermanode(c.key, sigTime)
	}
	if handleResult("permanode", permaNode, err) != nil {
		return err
	}

	if c.name != "" {
		put, err := up.UploadAndSignBlob(schema.NewSetAttributeClaim(permaNode.BlobRef, "title", c.name))
		handleResult("claim-permanode-title", put, err)
	}
	if c.tag != "" {
		tags := strings.Split(c.tag, ",")
		m := schema.NewSetAttributeClaim(permaNode.BlobRef, "tag", tags[0])
		for _, tag := range tags {
			m = schema.NewAddAttributeClaim(permaNode.BlobRef, "tag", tag)
			put, err := up.UploadAndSignBlob(m)
			handleResult("claim-permanode-tag", put, err)
		}
	}
	return nil
}
<commit_msg>camput: rename -name flag to -title for consistency with other commands<commit_after>/*
Copyright 2011 Google Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"errors"
	"flag"
	"fmt"
	"strings"
	"time"

	"camlistore.org/pkg/client"
	"camlistore.org/pkg/cmdmain"
	"camlistore.org/pkg/schema"
)

type permanodeCmd struct {
	title   string
	tag     string
	key     string // else random
	sigTime string
}

func init() {
	cmdmain.RegisterCommand("permanode", func(flags *flag.FlagSet) cmdmain.CommandRunner {
		cmd := new(permanodeCmd)
		flags.StringVar(&cmd.title, "title", "", "Optional 'title' attribute to set on new permanode")
		flags.StringVar(&cmd.tag, "tag", "", "Optional tag(s) to set on new permanode; comma separated.")
		flags.StringVar(&cmd.key, "key", "", "Optional key to create deterministic ('planned') permanodes. Must also use --sigtime.")
		flags.StringVar(&cmd.sigTime, "sigtime", "", "Optional time to put in the OpenPGP signature packet instead of the current time. Required when producing a deterministic permanode (with --key). In format YYYY-MM-DD HH:MM:SS")
		return cmd
	})
}

func (c *permanodeCmd) Describe() string {
	return "Create and upload a permanode."
}

func (c *permanodeCmd) Usage() {
	cmdmain.Errorf("Usage: camput [globalopts] permanode [permanodeopts]\n")
}

func (c *permanodeCmd) Examples() []string {
	return []string{
		"                               (create a new permanode)",
		`-name="Some Name" -tag=foo,bar (with attributes added)`,
	}
}

func (c *permanodeCmd) RunCommand(args []string) error {
	if len(args) > 0 {
		return errors.New("Permanode command doesn't take any additional arguments")
	}

	var (
		permaNode *client.PutResult
		err       error
		up        = getUploader()
	)
	if (c.key != "") != (c.sigTime != "") {
		return errors.New("Both --key and --sigtime must be used to produce deterministic permanodes.")
	}
	if c.key == "" {
		// Normal case, with a random permanode.
		permaNode, err = up.UploadNewPermanode()
	} else {
		const format = "2006-01-02 15:04:05"
		sigTime, err := time.Parse(format, c.sigTime)
		if err != nil {
			return fmt.Errorf("Error parsing time %q; expecting time of form %q", c.sigTime, format)
		}
		permaNode, err = up.UploadPlannedPermanode(c.key, sigTime)
	}
	if handleResult("permanode", permaNode, err) != nil {
		return err
	}

	if c.title != "" {
		put, err := up.UploadAndSignBlob(schema.NewSetAttributeClaim(permaNode.BlobRef, "title", c.title))
		handleResult("claim-permanode-title", put, err)
	}
	if c.tag != "" {
		tags := strings.Split(c.tag, ",")
		m := schema.NewSetAttributeClaim(permaNode.BlobRef, "tag", tags[0])
		for _, tag := range tags {
			m = schema.NewAddAttributeClaim(permaNode.BlobRef, "tag", tag)
			put, err := up.UploadAndSignBlob(m)
			handleResult("claim-permanode-tag", put, err)
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"time"

	"golang.org/x/crypto/ssh"

	"code.cloudfoundry.org/lager"
	"github.com/concourse/atc"
	"github.com/concourse/baggageclaim/baggageclaimcmd"
	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/ifrit/grouper"
	"github.com/tedsuo/ifrit/restart"
	"github.com/tedsuo/ifrit/sigmon"
)

type WorkerCommand struct {
	Name string   `long:"name" description:"The name to set for the worker during registration. If not specified, the hostname will be used."`
	Tags []string `long:"tag" description:"A tag to set during registration. Can be specified multiple times."`

	TeamName string `long:"team" description:"The name of the team that this worker will be assigned to."`

	HTTPProxy  URLFlag  `long:"http-proxy"  env:"http_proxy"                  description:"HTTP proxy endpoint to use for containers."`
	HTTPSProxy URLFlag  `long:"https-proxy" env:"https_proxy"                 description:"HTTPS proxy endpoint to use for containers."`
	NoProxy    []string `long:"no-proxy"    env:"no_proxy"    env-delim:","   description:"Blacklist of addresses to skip the proxy when reaching."`

	CertificatesPath string `long:"certificates-path" default:"/etc/ssl/certs" description:"Path to directory containing certificates that will be shared in containers at /etc/ssl/certs."`

	WorkDir DirFlag `long:"work-dir" required:"true" description:"Directory in which to place container data."`

	BindIP   IPFlag `long:"bind-ip"   default:"127.0.0.1" description:"IP address on which to listen for the Garden server."`
	BindPort uint16 `long:"bind-port" default:"7777"      description:"Port on which to listen for the Garden server."`

	PeerIP IPFlag `long:"peer-ip" description:"IP used to reach this worker from the ATC nodes. If omitted, the worker will be forwarded through the SSH connection to the TSA."`

	Garden GardenBackend `group:"Garden Configuration" namespace:"garden"`

	Baggageclaim baggageclaimcmd.BaggageclaimCommand `group:"Baggageclaim Configuration" namespace:"baggageclaim"`

	TSA BeaconConfig `group:"TSA Configuration" namespace:"tsa"`

	Metrics struct {
		YellerAPIKey      string `long:"yeller-api-key"     description:"Yeller API key. If specified, all errors logged will be emitted."`
		YellerEnvironment string `long:"yeller-environment" description:"Environment to tag on all Yeller events emitted."`
	} `group:"Metrics & Diagnostics"`
}

func (cmd *WorkerCommand) Execute(args []string) error {
	logger := lager.NewLogger("worker")
	logger.RegisterSink(lager.NewWriterSink(os.Stdout, lager.INFO))

	worker, gardenRunner, err := cmd.gardenRunner(logger.Session("garden"), args)
	if err != nil {
		return err
	}

	baggageclaimRunner, err := cmd.baggageclaimRunner(logger.Session("baggageclaim"))
	if err != nil {
		return err
	}

	members := grouper.Members{
		{
			Name:   "garden",
			Runner: gardenRunner,
		},
		{
			Name:   "baggageclaim",
			Runner: baggageclaimRunner,
		},
	}

	if cmd.TSA.WorkerPrivateKey != "" {
		members = append(members, grouper.Member{
			Name:   "beacon",
			Runner: cmd.beaconRunner(logger.Session("beacon"), worker),
		})
	}

	runner := sigmon.New(grouper.NewParallel(os.Interrupt, members))

	return <-ifrit.Invoke(runner).Wait()
}

func (cmd *WorkerCommand) workerName() (string, error) {
	if cmd.Name != "" {
		return cmd.Name, nil
	}

	return os.Hostname()
}

func (cmd *WorkerCommand) beaconRunner(logger lager.Logger, worker atc.Worker) ifrit.Runner {
	beacon := Beacon{
		Logger: logger,
		Config: cmd.TSA,
	}

	var beaconRunner ifrit.RunFunc
	if cmd.PeerIP != nil {
		worker.GardenAddr = fmt.Sprintf("%s:%d", cmd.PeerIP.IP(), cmd.BindPort)
		worker.BaggageclaimURL = fmt.Sprintf("http://%s:%d", cmd.PeerIP.IP(), cmd.Baggageclaim.BindPort)
		beaconRunner = beacon.Register
	} else {
		worker.GardenAddr = fmt.Sprintf("%s:%d", cmd.BindIP.IP(), cmd.BindPort)
		worker.BaggageclaimURL = fmt.Sprintf("http://%s:%d", cmd.Baggageclaim.BindIP.IP(), cmd.Baggageclaim.BindPort)
		beaconRunner = beacon.Forward
	}

	beacon.Worker = worker

	return restart.Restarter{
		Runner: beaconRunner,
		Load: func(prevRunner ifrit.Runner, prevErr error) ifrit.Runner {
			if prevErr == nil {
				return nil
			}

			if _, ok := prevErr.(*ssh.ExitError); !ok {
				logger.Error("restarting", prevErr)
				time.Sleep(5 * time.Second)
				return beaconRunner
			}

			return nil
		},
	}
}
<commit_msg>disable cert bind mount stuff by default<commit_after>package main

import (
	"fmt"
	"os"
	"time"

	"golang.org/x/crypto/ssh"

	"code.cloudfoundry.org/lager"
	"github.com/concourse/atc"
	"github.com/concourse/baggageclaim/baggageclaimcmd"
	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/ifrit/grouper"
	"github.com/tedsuo/ifrit/restart"
	"github.com/tedsuo/ifrit/sigmon"
)

type WorkerCommand struct {
	Name string   `long:"name" description:"The name to set for the worker during registration. If not specified, the hostname will be used."`
	Tags []string `long:"tag" description:"A tag to set during registration. Can be specified multiple times."`

	TeamName string `long:"team" description:"The name of the team that this worker will be assigned to."`

	HTTPProxy  URLFlag  `long:"http-proxy"  env:"http_proxy"                  description:"HTTP proxy endpoint to use for containers."`
	HTTPSProxy URLFlag  `long:"https-proxy" env:"https_proxy"                 description:"HTTPS proxy endpoint to use for containers."`
	NoProxy    []string `long:"no-proxy"    env:"no_proxy"    env-delim:","   description:"Blacklist of addresses to skip the proxy when reaching."`

	CertificatesPath string `long:"certificates-path" default:"" description:"Path to directory containing certificates that will be shared in containers at /etc/ssl/certs."`

	WorkDir DirFlag `long:"work-dir" required:"true" description:"Directory in which to place container data."`

	BindIP   IPFlag `long:"bind-ip"   default:"127.0.0.1" description:"IP address on which to listen for the Garden server."`
	BindPort uint16 `long:"bind-port" default:"7777"      description:"Port on which to listen for the Garden server."`

	PeerIP IPFlag `long:"peer-ip" description:"IP used to reach this worker from the ATC nodes. If omitted, the worker will be forwarded through the SSH connection to the TSA."`

	Garden GardenBackend `group:"Garden Configuration" namespace:"garden"`

	Baggageclaim baggageclaimcmd.BaggageclaimCommand `group:"Baggageclaim Configuration" namespace:"baggageclaim"`

	TSA BeaconConfig `group:"TSA Configuration" namespace:"tsa"`

	Metrics struct {
		YellerAPIKey      string `long:"yeller-api-key"     description:"Yeller API key. If specified, all errors logged will be emitted."`
		YellerEnvironment string `long:"yeller-environment" description:"Environment to tag on all Yeller events emitted."`
	} `group:"Metrics & Diagnostics"`
}

func (cmd *WorkerCommand) Execute(args []string) error {
	logger := lager.NewLogger("worker")
	logger.RegisterSink(lager.NewWriterSink(os.Stdout, lager.INFO))

	worker, gardenRunner, err := cmd.gardenRunner(logger.Session("garden"), args)
	if err != nil {
		return err
	}

	baggageclaimRunner, err := cmd.baggageclaimRunner(logger.Session("baggageclaim"))
	if err != nil {
		return err
	}

	members := grouper.Members{
		{
			Name:   "garden",
			Runner: gardenRunner,
		},
		{
			Name:   "baggageclaim",
			Runner: baggageclaimRunner,
		},
	}

	if cmd.TSA.WorkerPrivateKey != "" {
		members = append(members, grouper.Member{
			Name:   "beacon",
			Runner: cmd.beaconRunner(logger.Session("beacon"), worker),
		})
	}

	runner := sigmon.New(grouper.NewParallel(os.Interrupt, members))

	return <-ifrit.Invoke(runner).Wait()
}

func (cmd *WorkerCommand) workerName() (string, error) {
	if cmd.Name != "" {
		return cmd.Name, nil
	}

	return os.Hostname()
}

func (cmd *WorkerCommand) beaconRunner(logger lager.Logger, worker atc.Worker) ifrit.Runner {
	beacon := Beacon{
		Logger: logger,
		Config: cmd.TSA,
	}

	var beaconRunner ifrit.RunFunc
	if cmd.PeerIP != nil {
		worker.GardenAddr = fmt.Sprintf("%s:%d", cmd.PeerIP.IP(), cmd.BindPort)
		worker.BaggageclaimURL = fmt.Sprintf("http://%s:%d", cmd.PeerIP.IP(), cmd.Baggageclaim.BindPort)
		beaconRunner = beacon.Register
	} else {
		worker.GardenAddr = fmt.Sprintf("%s:%d", cmd.BindIP.IP(), cmd.BindPort)
		worker.BaggageclaimURL = fmt.Sprintf("http://%s:%d", cmd.Baggageclaim.BindIP.IP(), cmd.Baggageclaim.BindPort)
		beaconRunner = beacon.Forward
	}

	beacon.Worker = worker

	return restart.Restarter{
		Runner: beaconRunner,
		Load: func(prevRunner ifrit.Runner, prevErr error) ifrit.Runner {
			if prevErr == nil {
				return nil
			}

			if _, ok := prevErr.(*ssh.ExitError); !ok {
				logger.Error("restarting", prevErr)
				time.Sleep(5 * time.Second)
				return beaconRunner
			}

			return nil
		},
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/xml"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"sort"
	"strings"
	"sync"
	"text/template"

	"github.com/haya14busa/errorformat"
	"github.com/haya14busa/errorformat/fmts"
	"github.com/haya14busa/go-checkstyle/checkstyle"
)

const usageMessage = "" +
	`Usage: errorformat [flags] [errorformat ...]

errorformat reads compiler/linter/static analyzer result from STDIN, formats
them by given 'errorformat' (90% compatible with Vim's errorformat. :h
errorformat), and outputs formated result to STDOUT.

Example:
	$ echo '/path/to/file:14:28: error message\nfile2:3:4: msg' | errorformat "%f:%l:%c: %m"
	/path/to/file|14 col 28| error message
	file2|3 col 4| msg

	$ golint ./... | errorformat -name=golint

The -f flag specifies an alternate format for the entry, using the
syntax of package template.  The default output is equivalent to -f
'{{.String}}'. The struct being passed to the template is:

	type Entry struct {
		// name of a file
		Filename string
		// line number
		Lnum int
		// column number (first column is 1)
		Col int
		// true: "col" is visual column
		// false: "col" is byte index
		Vcol bool
		// error number
		Nr int
		// search pattern used to locate the error
		Pattern string
		// description of the error
		Text string
		// type of the error, 'E', '1', etc.
		Type rune
		// true: recognized error message
		Valid bool

		// Original error lines (often one line. more than one line for multi-line
		// errorformat. :h errorformat-multi-line)
		Lines []string
	}
`

func usage() {
	fmt.Fprintln(os.Stderr, usageMessage)
	fmt.Fprintln(os.Stderr, "Flags:")
	flag.PrintDefaults()
	os.Exit(2)
}

func main() {
	var (
		entryFmt  = flag.String("f", "{{.String}}", "format template for -w=template")
		writerFmt = flag.String("w", "template", "writer format (template|checkstyle)")
		name      = flag.String("name", "", "defined errorformat name")
		list      = flag.Bool("list", false, "list defined errorformats")
	)
	flag.Usage = usage
	flag.Parse()
	errorformats := flag.Args()
	if err := run(os.Stdin, os.Stdout, errorformats, *writerFmt, *entryFmt, *name, *list); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}

func run(r io.Reader, w io.Writer, efms []string, writerFmt, entryFmt, name string, list bool) error {
	if list {
		fs := fmts.DefinedFmts()
		out := make([]string, 0, len(fs))
		for _, f := range fs {
			out = append(out, fmt.Sprintf("%s\t\t%s - %s", f.Name, f.Description, f.URL))
		}
		sort.Strings(out)
		fmt.Fprintln(w, strings.Join(out, "\n"))
		return nil
	}

	if name != "" {
		f, ok := fmts.DefinedFmts()[name]
		if !ok {
			return fmt.Errorf("%q is not defined", name)
		}
		efms = f.Errorformat
	}

	var writer Writer

	switch writerFmt {
	case "template", "":
		fm := template.FuncMap{
			"join": strings.Join,
		}
		tmpl, err := template.New("main").Funcs(fm).Parse(entryFmt)
		if err != nil {
			return err
		}
		writer = &TemplateWriter{Template: tmpl, Writer: newTrackingWriter(w)}
	case "checkstyle":
		writer = &CheckStyleWriter{w: w}
	default:
		return fmt.Errorf("unknown writer: -w=%v", writerFmt)
	}
	defer func() {
		if err := writer.Flash(); err != nil {
			log.Println(err)
		}
	}()

	efm, err := errorformat.NewErrorformat(efms)
	if err != nil {
		return err
	}
	s := efm.NewScanner(r)
	for s.Scan() {
		if err := writer.Write(s.Entry()); err != nil {
			return err
		}
	}
	return nil
}

type Writer interface {
	Write(*errorformat.Entry) error
	Flash() error
}

type TemplateWriter struct {
	Template *template.Template
	Writer   *TrackingWriter
}

func (t *TemplateWriter) Write(e *errorformat.Entry) error {
	if err := t.Template.Execute(t.Writer, e); err != nil {
		return err
	}
	if t.Writer.NeedNL() {
		t.Writer.WriteNL()
	}
	return nil
}

func (*TemplateWriter) Flash() error {
	return nil
}

// TrackingWriter tracks the last byte written on every write so
// we can avoid printing a newline if one was already written or
// if there is no output at all.
type TrackingWriter struct {
	w    io.Writer
	last byte
}

func newTrackingWriter(w io.Writer) *TrackingWriter {
	return &TrackingWriter{
		w:    w,
		last: '\n',
	}
}

func (t *TrackingWriter) Write(p []byte) (n int, err error) {
	n, err = t.w.Write(p)
	if n > 0 {
		t.last = p[n-1]
	}
	return
}

var nl = []byte{'\n'}

// WriteNL writes NL.
func (t *TrackingWriter) WriteNL() (int, error) {
	return t.w.Write(nl)
}

// NeedNL returns true if the last byte written is not NL.
func (t *TrackingWriter) NeedNL() bool {
	return t.last != '\n'
}

type CheckStyleWriter struct {
	mu    sync.Mutex
	files map[string]*checkstyle.File
	w     io.Writer
}

func (c *CheckStyleWriter) Write(e *errorformat.Entry) error {
	c.mu.Lock()
	defer c.mu.Unlock()
	if c.files == nil {
		c.files = make(map[string]*checkstyle.File)
	}
	if _, ok := c.files[e.Filename]; !ok {
		c.files[e.Filename] = &checkstyle.File{Name: e.Filename}
	}
	checkerr := &checkstyle.Error{
		Column:   e.Col,
		Line:     e.Lnum,
		Message:  e.Text,
		Severity: e.Types(),
	}
	c.files[e.Filename].Errors = append(c.files[e.Filename].Errors, checkerr)
	return nil
}

func (c *CheckStyleWriter) Flash() error {
	c.mu.Lock()
	defer c.mu.Unlock()
	r := &checkstyle.Result{Version: "1.0"}
	for _, f := range c.files {
		r.Files = append(r.Files, f)
	}
	fmt.Fprint(c.w, xml.Header)
	e := xml.NewEncoder(c.w)
	e.Indent("", "  ")
	defer c.w.Write(nl)
	return e.Encode(r)
}
<commit_msg>check err<commit_after>package main

import (
	"encoding/xml"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"sort"
	"strings"
	"sync"
	"text/template"

	"github.com/haya14busa/errorformat"
	"github.com/haya14busa/errorformat/fmts"
	"github.com/haya14busa/go-checkstyle/checkstyle"
)

const usageMessage = "" +
	`Usage: errorformat [flags] [errorformat ...]

errorformat reads compiler/linter/static analyzer result from STDIN, formats
them by given 'errorformat' (90% compatible with Vim's errorformat. :h
errorformat), and outputs formated result to STDOUT.

Example:
	$ echo '/path/to/file:14:28: error message\nfile2:3:4: msg' | errorformat "%f:%l:%c: %m"
	/path/to/file|14 col 28| error message
	file2|3 col 4| msg

	$ golint ./... | errorformat -name=golint

The -f flag specifies an alternate format for the entry, using the
syntax of package template.  The default output is equivalent to -f
'{{.String}}'. The struct being passed to the template is:

	type Entry struct {
		// name of a file
		Filename string
		// line number
		Lnum int
		// column number (first column is 1)
		Col int
		// true: "col" is visual column
		// false: "col" is byte index
		Vcol bool
		// error number
		Nr int
		// search pattern used to locate the error
		Pattern string
		// description of the error
		Text string
		// type of the error, 'E', '1', etc.
		Type rune
		// true: recognized error message
		Valid bool

		// Original error lines (often one line. more than one line for multi-line
		// errorformat. :h errorformat-multi-line)
		Lines []string
	}
`

func usage() {
	fmt.Fprintln(os.Stderr, usageMessage)
	fmt.Fprintln(os.Stderr, "Flags:")
	flag.PrintDefaults()
	os.Exit(2)
}

func main() {
	var (
		entryFmt  = flag.String("f", "{{.String}}", "format template for -w=template")
		writerFmt = flag.String("w", "template", "writer format (template|checkstyle)")
		name      = flag.String("name", "", "defined errorformat name")
		list      = flag.Bool("list", false, "list defined errorformats")
	)
	flag.Usage = usage
	flag.Parse()
	errorformats := flag.Args()
	if err := run(os.Stdin, os.Stdout, errorformats, *writerFmt, *entryFmt, *name, *list); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}

func run(r io.Reader, w io.Writer, efms []string, writerFmt, entryFmt, name string, list bool) error {
	if list {
		fs := fmts.DefinedFmts()
		out := make([]string, 0, len(fs))
		for _, f := range fs {
			out = append(out, fmt.Sprintf("%s\t\t%s - %s", f.Name, f.Description, f.URL))
		}
		sort.Strings(out)
		fmt.Fprintln(w, strings.Join(out, "\n"))
		return nil
	}

	if name != "" {
		f, ok := fmts.DefinedFmts()[name]
		if !ok {
			return fmt.Errorf("%q is not defined", name)
		}
		efms = f.Errorformat
	}

	var writer Writer

	switch writerFmt {
	case "template", "":
		fm := template.FuncMap{
			"join": strings.Join,
		}
		tmpl, err := template.New("main").Funcs(fm).Parse(entryFmt)
		if err != nil {
			return err
		}
		writer = &TemplateWriter{Template: tmpl, Writer: newTrackingWriter(w)}
	case "checkstyle":
		writer = &CheckStyleWriter{w: w}
	default:
		return fmt.Errorf("unknown writer: -w=%v", writerFmt)
	}
	defer func() {
		if err := writer.Flash(); err != nil {
			log.Println(err)
		}
	}()

	efm, err := errorformat.NewErrorformat(efms)
	if err != nil {
		return err
	}
	s := efm.NewScanner(r)
	for s.Scan() {
		if err := writer.Write(s.Entry()); err != nil {
			return err
		}
	}
	return nil
}

type Writer interface {
	Write(*errorformat.Entry) error
	Flash() error
}

type TemplateWriter struct {
	Template *template.Template
	Writer   *TrackingWriter
}

func (t *TemplateWriter) Write(e *errorformat.Entry) error {
	if err := t.Template.Execute(t.Writer, e); err != nil {
		return err
	}
	if t.Writer.NeedNL() {
		if _, err := t.Writer.WriteNL(); err != nil {
			return err
		}
	}
	return nil
}

func (*TemplateWriter) Flash() error {
	return nil
}

// TrackingWriter tracks the last byte written on every write so
// we can avoid printing a newline if one was already written or
// if there is no output at all.
type TrackingWriter struct {
	w    io.Writer
	last byte
}

func newTrackingWriter(w io.Writer) *TrackingWriter {
	return &TrackingWriter{
		w:    w,
		last: '\n',
	}
}

func (t *TrackingWriter) Write(p []byte) (n int, err error) {
	n, err = t.w.Write(p)
	if n > 0 {
		t.last = p[n-1]
	}
	return
}

var nl = []byte{'\n'}

// WriteNL writes NL.
func (t *TrackingWriter) WriteNL() (int, error) {
	return t.w.Write(nl)
}

// NeedNL returns true if the last byte written is not NL.
func (t *TrackingWriter) NeedNL() bool {
	return t.last != '\n'
}

type CheckStyleWriter struct {
	mu    sync.Mutex
	files map[string]*checkstyle.File
	w     io.Writer
}

func (c *CheckStyleWriter) Write(e *errorformat.Entry) error {
	c.mu.Lock()
	defer c.mu.Unlock()
	if c.files == nil {
		c.files = make(map[string]*checkstyle.File)
	}
	if _, ok := c.files[e.Filename]; !ok {
		c.files[e.Filename] = &checkstyle.File{Name: e.Filename}
	}
	checkerr := &checkstyle.Error{
		Column:   e.Col,
		Line:     e.Lnum,
		Message:  e.Text,
		Severity: e.Types(),
	}
	c.files[e.Filename].Errors = append(c.files[e.Filename].Errors, checkerr)
	return nil
}

func (c *CheckStyleWriter) Flash() error {
	c.mu.Lock()
	defer c.mu.Unlock()
	r := &checkstyle.Result{Version: "1.0"}
	for _, f := range c.files {
		r.Files = append(r.Files, f)
	}
	fmt.Fprint(c.w, xml.Header)
	e := xml.NewEncoder(c.w)
	e.Indent("", "  ")
	defer c.w.Write(nl)
	return e.Encode(r)
}
<|endoftext|>


<commit_before>// Copyright 2022 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.

//go:build go1.18
// +build go1.18

// Command govulncheck reports known vulnerabilities filed in a vulnerability database
// (see https://golang.org/design/draft-vulndb) that affect a given package or binary.
//
// It uses static analysis or the binary's symbol table to narrow down reports to only
// those that potentially affect the application.
//
// WARNING WARNING WARNING
//
// govulncheck is still experimental and neither its output or the vulnerability
// database should be relied on to be stable or comprehensive.
package main

import (
	"context"
	"encoding/json"
	"flag"
	"fmt"
	"go/build"
	"log"
	"os"
	"sort"
	"strings"

	"golang.org/x/exp/vulncheck"
	"golang.org/x/mod/semver"
	"golang.org/x/tools/go/buildutil"
	"golang.org/x/tools/go/packages"
	"golang.org/x/vuln/client"
	"golang.org/x/vuln/osv"
)

var (
	jsonFlag    = flag.Bool("json", false, "")
	verboseFlag = flag.Bool("v", false, "")
	testsFlag   = flag.Bool("tests", false, "")
)

const usage = `govulncheck: identify known vulnerabilities by call graph traversal.

Usage:

	govulncheck [-json] [-all] [-tests] [-tags] {package pattern...}

	govulncheck {binary path}

Flags:

	-json  	   Print vulnerability findings in JSON format.

	-tags	   Comma-separated list of build tags.

	-tests     Boolean flag indicating if test files should be analyzed too.

govulncheck can be used with either one or more package patterns (i.e. golang.org/x/crypto/...
or ./...) or with a single path to a Go binary. In the latter case module and symbol
information will be extracted from the binary in order to detect vulnerable symbols.

The environment variable GOVULNDB can be set to a comma-separate list of vulnerability
database URLs, with http://, https://, or file:// protocols. Entries from multiple
databases are merged.
`

func init() {
	flag.Var((*buildutil.TagsFlag)(&build.Default.BuildTags), "tags", buildutil.TagsFlagDoc)
}

func main() {
	flag.Usage = func() { fmt.Fprint(os.Stderr, usage) }
	flag.Parse()

	if len(flag.Args()) == 0 {
		die("%s", usage)
	}

	dbs := []string{"https://storage.googleapis.com/go-vulndb"}
	if GOVULNDB := os.Getenv("GOVULNDB"); GOVULNDB != "" {
		dbs = strings.Split(GOVULNDB, ",")
	}
	dbClient, err := client.NewClient(dbs, client.Options{HTTPCache: defaultCache()})
	if err != nil {
		die("govulncheck: %s", err)
	}
	vcfg := &vulncheck.Config{Client: dbClient}
	ctx := context.Background()

	patterns := flag.Args()
	var r *vulncheck.Result
	var pkgs []*packages.Package
	if len(patterns) == 1 && isFile(patterns[0]) {
		f, err := os.Open(patterns[0])
		if err != nil {
			die("govulncheck: %v", err)
		}
		defer f.Close()
		r, err = vulncheck.Binary(ctx, f, vcfg)
		if err != nil {
			die("govulncheck: %v", err)
		}
	} else {
		cfg := &packages.Config{
			Mode:       packages.NeedName | packages.NeedFiles | packages.NeedCompiledGoFiles | packages.NeedImports | packages.NeedTypes | packages.NeedTypesSizes | packages.NeedSyntax | packages.NeedTypesInfo | packages.NeedDeps | packages.NeedModule,
			Tests:      *testsFlag,
			BuildFlags: []string{fmt.Sprintf("-tags=%s", strings.Join(build.Default.BuildTags, ","))},
		}
		pkgs, err = loadPackages(cfg, patterns)
		if err != nil {
			die("govulncheck: %v", err)
		}
		r, err = vulncheck.Source(ctx, vulncheck.Convert(pkgs), vcfg)
		if err != nil {
			die("govulncheck: %v", err)
		}
	}
	if *jsonFlag {
		writeJSON(r)
	} else {
		writeText(r, pkgs)
	}
	exitCode := 0
	// Following go vet, fail with 3 if there are findings (in this case, vulns).
	if len(r.Vulns) > 0 {
		exitCode = 3
	}
	os.Exit(exitCode)
}

func writeJSON(r *vulncheck.Result) {
	b, err := json.MarshalIndent(r, "", "\t")
	if err != nil {
		die("govulncheck: %s", err)
	}
	os.Stdout.Write(b)
	fmt.Println()
}

func writeText(r *vulncheck.Result, pkgs []*packages.Package) {
	if len(r.Vulns) == 0 {
		return
	}
	// Build a map from module paths to versions.
	moduleVersions := map[string]string{}
	packages.Visit(pkgs, nil, func(p *packages.Package) {
		if m := packageModule(p); m != nil {
			moduleVersions[m.Path] = m.Version
		}
	})
	callStacks := vulncheck.CallStacks(r)

	const labelWidth = 16
	line := func(label, text string) {
		fmt.Printf("%-*s%s\n", labelWidth, label, text)
	}

	// Create set of top-level packages, used to find
	// representative symbols
	topPackages := map[string]bool{}
	for _, p := range pkgs {
		topPackages[p.PkgPath] = true
	}
	vulnGroups := groupByIDAndPackage(r.Vulns)
	for _, vg := range vulnGroups {
		// All the vulns in vg have the same PkgPath, ModPath and OSV.
		// All have a non-zero CallSink.
		v0 := vg[0]

		current := moduleVersions[v0.ModPath]
		fixed := "v" + latestFixed(v0.OSV.Affected)
		ref := fmt.Sprintf("https://pkg.go.dev/vuln/%s", v0.OSV.ID)

		fns := representativeFuncs(vg, topPackages, callStacks)
		// Use first as representative.
		rep := funcName(fns[0])
		var syms string
		if len(fns) == 1 {
			syms = rep
		} else {
			syms = fmt.Sprintf("%s and %d others", rep, len(fns)-1)
		}
		line("package:", v0.PkgPath)
		line("your version:", current)
		line("fixed version:", fixed)
		line("symbols:", syms)
		line("reference:", ref)

		desc := strings.Split(wrap(v0.OSV.Details, 80-labelWidth), "\n")
		for i, l := range desc {
			if i == 0 {
				line("description:", l)
			} else {
				line("", l)
			}
		}
		fmt.Println()
	}
}

func groupByIDAndPackage(vs []*vulncheck.Vuln) [][]*vulncheck.Vuln {
	groups := map[[2]string][]*vulncheck.Vuln{}
	for _, v := range vs {
		if v.CallSink == 0 {
			// Skip this vuln because although it appears in the
			// import graph, there are no calls to it.
			continue
		}
		key := [2]string{v.OSV.ID, v.PkgPath}
		groups[key] = append(groups[key], v)
	}

	var res [][]*vulncheck.Vuln
	for _, g := range groups {
		res = append(res, g)
	}
	sort.Slice(res, func(i, j int) bool {
		return res[i][0].PkgPath < res[j][0].PkgPath
	})
	return res
}

func packageModule(p *packages.Package) *packages.Module {
	m := p.Module
	if m == nil {
		return nil
	}
	if r := m.Replace; r != nil {
		return r
	}
	return m
}

func isFile(path string) bool {
	s, err := os.Stat(path)
	if err != nil {
		return false
	}
	return !s.IsDir()
}

func loadPackages(cfg *packages.Config, patterns []string) ([]*packages.Package, error) {
	if *verboseFlag {
		log.Println("loading packages...")
	}
	pkgs, err := packages.Load(cfg, patterns...)
	if err != nil {
		return nil, err
	}
	if packages.PrintErrors(pkgs) > 0 {
		return nil, fmt.Errorf("packages contain errors")
	}
	if *verboseFlag {
		log.Printf("\t%d loaded packages\n", len(pkgs))
	}
	return pkgs, nil
}

// latestFixed returns the latest fixed version in the list of affected ranges,
// or the empty string if there are no fixed versions.
func latestFixed(as []osv.Affected) string {
	v := ""
	for _, a := range as {
		for _, r := range a.Ranges {
			if r.Type == osv.TypeSemver {
				for _, e := range r.Events {
					if e.Fixed != "" && (v == "" || semver.Compare(e.Fixed, v) > 0) {
						v = e.Fixed
					}
				}
			}
		}
	}
	return v
}

// representativeFuncs collects representative functions for the group
// of vulns from the the call stacks.
func representativeFuncs(vg []*vulncheck.Vuln, topPkgs map[string]bool, callStacks map[*vulncheck.Vuln][]vulncheck.CallStack) []*vulncheck.FuncNode {
	// Collect unique top of call stacks.
	fns := map[*vulncheck.FuncNode]bool{}
	for _, v := range vg {
		for _, cs := range callStacks[v] {
			// Find the lowest function in the stack that is in
			// one of the top packages.
			for i := len(cs) - 1; i > 0; i-- {
				pkg := pkgPath(cs[i].Function)
				if topPkgs[pkg] {
					fns[cs[i].Function] = true
					break
				}
			}
		}
	}
	var res []*vulncheck.FuncNode
	for fn := range fns {
		res = append(res, fn)
	}
	return res
}

func pkgPath(fn *vulncheck.FuncNode) string {
	if fn.PkgPath != "" {
		return fn.PkgPath
	}
	s := strings.TrimPrefix(fn.RecvType, "*")
	if i := strings.LastIndexByte(s, '.'); i > 0 {
		s = s[:i]
	}
	return s
}

func funcName(fn *vulncheck.FuncNode) string {
	return strings.TrimPrefix(fn.String(), "*")
}

func die(format string, args ...interface{}) {
	fmt.Fprintf(os.Stderr, format+"\n", args...)
	os.Exit(1)
}
<commit_msg>cmd/govulncheck: fail in GOPATH mode<commit_after>// Copyright 2022 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.

//go:build go1.18
// +build go1.18

// Command govulncheck reports known vulnerabilities filed in a vulnerability database
// (see https://golang.org/design/draft-vulndb) that affect a given package or binary.
//
// It uses static analysis or the binary's symbol table to narrow down reports to only
// those that potentially affect the application.
//
// WARNING WARNING WARNING
//
// govulncheck is still experimental and neither its output or the vulnerability
// database should be relied on to be stable or comprehensive.
package main

import (
	"context"
	"encoding/json"
	"flag"
	"fmt"
	"go/build"
	"log"
	"os"
	"sort"
	"strings"

	"golang.org/x/exp/vulncheck"
	"golang.org/x/mod/semver"
	"golang.org/x/tools/go/buildutil"
	"golang.org/x/tools/go/packages"
	"golang.org/x/vuln/client"
	"golang.org/x/vuln/osv"
)

var (
	jsonFlag    = flag.Bool("json", false, "")
	verboseFlag = flag.Bool("v", false, "")
	testsFlag   = flag.Bool("tests", false, "")
)

const usage = `govulncheck: identify known vulnerabilities by call graph traversal.

Usage:

	govulncheck [-json] [-all] [-tests] [-tags] {package pattern...}

	govulncheck {binary path}

Flags:

	-json  	   Print vulnerability findings in JSON format.

	-tags	   Comma-separated list of build tags.

	-tests     Boolean flag indicating if test files should be analyzed too.

govulncheck can be used with either one or more package patterns (i.e. golang.org/x/crypto/...
or ./...) or with a single path to a Go binary. In the latter case module and symbol
information will be extracted from the binary in order to detect vulnerable symbols.

The environment variable GOVULNDB can be set to a comma-separate list of vulnerability
database URLs, with http://, https://, or file:// protocols. Entries from multiple
databases are merged.
`

func init() {
	flag.Var((*buildutil.TagsFlag)(&build.Default.BuildTags), "tags", buildutil.TagsFlagDoc)
}

func main() {
	flag.Usage = func() { fmt.Fprint(os.Stderr, usage) }
	flag.Parse()

	if len(flag.Args()) == 0 {
		die("%s", usage)
	}

	dbs := []string{"https://storage.googleapis.com/go-vulndb"}
	if GOVULNDB := os.Getenv("GOVULNDB"); GOVULNDB != "" {
		dbs = strings.Split(GOVULNDB, ",")
	}
	dbClient, err := client.NewClient(dbs, client.Options{HTTPCache: defaultCache()})
	if err != nil {
		die("govulncheck: %s", err)
	}
	vcfg := &vulncheck.Config{Client: dbClient}
	ctx := context.Background()

	patterns := flag.Args()
	var (
		r              *vulncheck.Result
		pkgs           []*packages.Package
		moduleVersions map[string]string
	)
	if len(patterns) == 1 && isFile(patterns[0]) {
		f, err := os.Open(patterns[0])
		if err != nil {
			die("govulncheck: %v", err)
		}
		defer f.Close()
		r, err = vulncheck.Binary(ctx, f, vcfg)
		if err != nil {
			die("govulncheck: %v", err)
		}
	} else {
		cfg := &packages.Config{
			Mode:       packages.NeedName | packages.NeedFiles | packages.NeedCompiledGoFiles | packages.NeedImports | packages.NeedTypes | packages.NeedTypesSizes | packages.NeedSyntax | packages.NeedTypesInfo | packages.NeedDeps | packages.NeedModule,
			Tests:      *testsFlag,
			BuildFlags: []string{fmt.Sprintf("-tags=%s", strings.Join(build.Default.BuildTags, ","))},
		}
		pkgs, err = loadPackages(cfg, patterns)
		if err != nil {
			die("govulncheck: %v", err)
		}
		// Build a map from module paths to versions.
		moduleVersions = map[string]string{}
		packages.Visit(pkgs, nil, func(p *packages.Package) {
			if m := packageModule(p); m != nil {
				moduleVersions[m.Path] = m.Version
			}
		})

		if len(moduleVersions) == 0 {
			die("govulncheck: no modules found; are you in GOPATH mode? Module mode required.")
		}
		r, err = vulncheck.Source(ctx, vulncheck.Convert(pkgs), vcfg)
		if err != nil {
			die("govulncheck: %v", err)
		}
	}
	if *jsonFlag {
		writeJSON(r)
	} else {
		writeText(r, pkgs, moduleVersions)
	}
	exitCode := 0
	// Following go vet, fail with 3 if there are findings (in this case, vulns).
	if len(r.Vulns) > 0 {
		exitCode = 3
	}
	os.Exit(exitCode)
}

func writeJSON(r *vulncheck.Result) {
	b, err := json.MarshalIndent(r, "", "\t")
	if err != nil {
		die("govulncheck: %s", err)
	}
	os.Stdout.Write(b)
	fmt.Println()
}

func writeText(r *vulncheck.Result, pkgs []*packages.Package, moduleVersions map[string]string) {
	if len(r.Vulns) == 0 {
		return
	}
	callStacks := vulncheck.CallStacks(r)

	const labelWidth = 16
	line := func(label, text string) {
		fmt.Printf("%-*s%s\n", labelWidth, label, text)
	}

	// Create set of top-level packages, used to find
	// representative symbols
	topPackages := map[string]bool{}
	for _, p := range pkgs {
		topPackages[p.PkgPath] = true
	}
	vulnGroups := groupByIDAndPackage(r.Vulns)
	for _, vg := range vulnGroups {
		// All the vulns in vg have the same PkgPath, ModPath and OSV.
		// All have a non-zero CallSink.
		v0 := vg[0]

		current := moduleVersions[v0.ModPath]
		fixed := "v" + latestFixed(v0.OSV.Affected)
		ref := fmt.Sprintf("https://pkg.go.dev/vuln/%s", v0.OSV.ID)

		fns := representativeFuncs(vg, topPackages, callStacks)
		// Use first as representative.
		rep := funcName(fns[0])
		var syms string
		if len(fns) == 1 {
			syms = rep
		} else {
			syms = fmt.Sprintf("%s and %d others", rep, len(fns)-1)
		}
		line("package:", v0.PkgPath)
		line("your version:", current)
		line("fixed version:", fixed)
		line("symbols:", syms)
		line("reference:", ref)

		desc := strings.Split(wrap(v0.OSV.Details, 80-labelWidth), "\n")
		for i, l := range desc {
			if i == 0 {
				line("description:", l)
			} else {
				line("", l)
			}
		}
		fmt.Println()
	}
}

func groupByIDAndPackage(vs []*vulncheck.Vuln) [][]*vulncheck.Vuln {
	groups := map[[2]string][]*vulncheck.Vuln{}
	for _, v := range vs {
		if v.CallSink == 0 {
			// Skip this vuln because although it appears in the
			// import graph, there are no calls to it.
			continue
		}
		key := [2]string{v.OSV.ID, v.PkgPath}
		groups[key] = append(groups[key], v)
	}

	var res [][]*vulncheck.Vuln
	for _, g := range groups {
		res = append(res, g)
	}
	sort.Slice(res, func(i, j int) bool {
		return res[i][0].PkgPath < res[j][0].PkgPath
	})
	return res
}

func packageModule(p *packages.Package) *packages.Module {
	m := p.Module
	if m == nil {
		return nil
	}
	if r := m.Replace; r != nil {
		return r
	}
	return m
}

func isFile(path string) bool {
	s, err := os.Stat(path)
	if err != nil {
		return false
	}
	return !s.IsDir()
}

func loadPackages(cfg *packages.Config, patterns []string) ([]*packages.Package, error) {
	if *verboseFlag {
		log.Println("loading packages...")
	}
	pkgs, err := packages.Load(cfg, patterns...)
	if err != nil {
		return nil, err
	}
	if packages.PrintErrors(pkgs) > 0 {
		return nil, fmt.Errorf("packages contain errors")
	}
	if *verboseFlag {
		log.Printf("\t%d loaded packages\n", len(pkgs))
	}
	return pkgs, nil
}

// latestFixed returns the latest fixed version in the list of affected ranges,
// or the empty string if there are no fixed versions.
func latestFixed(as []osv.Affected) string {
	v := ""
	for _, a := range as {
		for _, r := range a.Ranges {
			if r.Type == osv.TypeSemver {
				for _, e := range r.Events {
					if e.Fixed != "" && (v == "" || semver.Compare(e.Fixed, v) > 0) {
						v = e.Fixed
					}
				}
			}
		}
	}
	return v
}

// representativeFuncs collects representative functions for the group
// of vulns from the the call stacks.
func representativeFuncs(vg []*vulncheck.Vuln, topPkgs map[string]bool, callStacks map[*vulncheck.Vuln][]vulncheck.CallStack) []*vulncheck.FuncNode {
	// Collect unique top of call stacks.
	fns := map[*vulncheck.FuncNode]bool{}
	for _, v := range vg {
		for _, cs := range callStacks[v] {
			// Find the lowest function in the stack that is in
			// one of the top packages.
			for i := len(cs) - 1; i >= 0; i-- {
				pkg := pkgPath(cs[i].Function)
				if topPkgs[pkg] {
					fns[cs[i].Function] = true
					break
				}
			}
		}
	}
	var res []*vulncheck.FuncNode
	for fn := range fns {
		res = append(res, fn)
	}
	return res
}

func pkgPath(fn *vulncheck.FuncNode) string {
	if fn.PkgPath != "" {
		return fn.PkgPath
	}
	s := strings.TrimPrefix(fn.RecvType, "*")
	if i := strings.LastIndexByte(s, '.'); i > 0 {
		s = s[:i]
	}
	return s
}

func funcName(fn *vulncheck.FuncNode) string {
	return strings.TrimPrefix(fn.String(), "*")
}

func die(format string, args ...interface{}) {
	fmt.Fprintf(os.Stderr, format+"\n", args...)
	os.Exit(1)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"os"
	"os/user"
	"path/filepath"
	"strings"
	"sync"

	"github.com/immortal/immortal"
)

var version string

func exit1(err error) {
	fmt.Println(err)
	os.Exit(1)
}

// immortal-ctl options service
// immortal-ctl status (print status of all services)
func main() {
	var (
		options                 = []string{"kill", "one", "restart", "start", "status", "stop", "exit"}
		ppid, pup, pdown, pname int
		sdir                    string
		serviceName             string
		wg                      sync.WaitGroup
		v                       = flag.Bool("v", false, fmt.Sprintf("Print version: %s", version))
		a                       = flag.Bool("a", false, "ALRM")
		c                       = flag.Bool("c", false, "CONT")
		h                       = flag.Bool("h", false, "HUP")
		i                       = flag.Bool("i", false, "INT")
		in                      = flag.Bool("in", false, "TTIN")
		k                       = flag.Bool("k", false, "KILL")
		ou                      = flag.Bool("ou", false, "TTOU")
		q                       = flag.Bool("q", false, "QUIT")
		s                       = flag.Bool("s", false, "STOP")
		t                       = flag.Bool("t", false, "TERM")
		usr1                    = flag.Bool("1", false, "USR1")
		usr2                    = flag.Bool("2", false, "USR2")
		w                       = flag.Bool("w", false, "WINCH")
	)

	// if IMMORTAL_SDIR env is set, use it as default sdir
	if sdir = os.Getenv("IMMORTAL_SDIR"); sdir == "" {
		sdir = "/var/run/immortal"
	}

	// if no options defaults to status
	if len(os.Args) == 1 {
		os.Args = append(os.Args, "status")
	}

	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "usage: %s [option] [-12achikinouqstvw] service\n\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n\n%s %s\n",
			os.Args[0],
			"  Options:",
			"    exit      Stop service and supervisor",
			"    kill      Terminate service",
			"    once      Do not restart if service stops",
			"    restart   Restart the service",
			"    start     Start the service",
			"    status    Print status",
			"    stop      Stop the service",
			"  Signals:",
			"    -1        USR1",
			"    -2        USR2",
			"    -a        ALRM",
			"    -c        CONT",
			"    -h        HUP",
			"    -i        INT",
			"    -k        KILL",
			"    -in       TTIN",
			"    -ou       TTOU",
			"    -q        QUIT",
			"    -s        STOP",
			"    -t        TERM",
			"    -w        WINCH",
			"  version", version)
	}

	flag.Parse()

	if *v {
		fmt.Printf("%s\n", version)
		os.Exit(0)
	}

	println(a, c, h, i, in, ou, q, s, t, usr1, usr2, w, k)

	// check options
	exit := true
	if flag.Arg(0) != "" {
		for _, v := range options {
			if flag.Arg(0) == v {
				exit = false
				break
			}
		}
	}
	if exit {
		exit1(fmt.Errorf("Invalid option, use (\"%s -help\") for help.\n", os.Args[0]))
	}

	// set service name
	if flag.NArg() > 1 {
		serviceName = flag.Arg(1)
	}

	// get status for all services
	services, _ := immortal.FindServices(sdir)

	// get user $HOME/.immortal services
	if usr, err := user.Current(); err == nil {
		if userServices, err := immortal.FindServices(
			filepath.Join(usr.HomeDir, ".immortal"),
		); err == nil {
			services = append(services, userServices...)
		}
	}

	wg.Add(len(services))
	for _, service := range services {
		if serviceName != "" {
			if !strings.HasPrefix(service.Name, serviceName) {
				wg.Done()
				continue
			}
		}
		go func(s *immortal.ServiceStatus) {
			defer wg.Done()
			status, err := immortal.GetStatus(s.Socket)
			if err != nil {
				immortal.PurgeServices(s.Socket)
			} else {
				s.Status = status
				if l := len(fmt.Sprintf("%d", status.Pid)); l > ppid {
					ppid = l
				}
				if l := len(status.Up); l > pup {
					pup = l
				}
				if l := len(status.Down); l > pdown {
					pdown = l
				}
				if l := len(s.Name); l > pname {
					pname = l
				}
			}
		}(service)
	}
	wg.Wait()

	// format the output
	if ppid < 3 {
		ppid = 3
	}
	if pup < 2 {
		pup = 2
	}
	if pdown < 4 {
		pdown = 4
	}
	format := fmt.Sprintf("%%+%dv   %%+%ds   %%+%ds   %%-%ds   %%s\n",
		ppid,
		pup,
		pdown,
		pname,
	)

	fmt.Printf(format, "PID", "Up", "Down", "Name", "CMD")
	for _, s := range services {
		if s.Status.Pid > 0 {
			if s.Status.Down != "" {
				fmt.Printf(format, s.Status.Pid, s.Status.Up, s.Status.Down, immortal.Red(fmt.Sprintf("%-*s", pname, s.Name)), s.Status.Cmd)
			} else {
				fmt.Printf(format, s.Status.Pid, s.Status.Up, s.Status.Down, immortal.Green(fmt.Sprintf("%-*s", pname, s.Name)), s.Status.Cmd)
			}
		}
	}
}
<commit_msg>check options/arguments to be only option or signal<commit_after>package main

import (
	"flag"
	"fmt"
	"os"
	"os/user"
	"path/filepath"
	"strings"
	"sync"

	"github.com/immortal/immortal"
)

var version string

func exit1(err error) {
	fmt.Println(err)
	os.Exit(1)
}

// immortal-ctl options service
// immortal-ctl status (print status of all services)
func main() {
	var (
		options                 = []string{"kill", "once", "restart", "start", "status", "stop", "exit"}
		ppid, pup, pdown, pname int
		sdir                    string
		serviceName             string
		wg                      sync.WaitGroup
		v                       = flag.Bool("v", false, fmt.Sprintf("Print version: %s", version))
		a                       = flag.Bool("a", false, "ALRM")
		c                       = flag.Bool("c", false, "CONT")
		h                       = flag.Bool("h", false, "HUP")
		i                       = flag.Bool("i", false, "INT")
		in                      = flag.Bool("in", false, "TTIN")
		k                       = flag.Bool("k", false, "KILL")
		ou                      = flag.Bool("ou", false, "TTOU")
		q                       = flag.Bool("q", false, "QUIT")
		s                       = flag.Bool("s", false, "STOP")
		t                       = flag.Bool("t", false, "TERM")
		usr1                    = flag.Bool("1", false, "USR1")
		usr2                    = flag.Bool("2", false, "USR2")
		w                       = flag.Bool("w", false, "WINCH")
	)

	// if IMMORTAL_SDIR env is set, use it as default sdir
	if sdir = os.Getenv("IMMORTAL_SDIR"); sdir == "" {
		sdir = "/var/run/immortal"
	}

	// if no options defaults to status
	if len(os.Args) == 1 {
		os.Args = append(os.Args, "status")
	}

	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "usage: %s [option] [-12achikinouqstvw] service\n\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n\n%s %s\n",
			os.Args[0],
			"  Options:",
			"    exit      Stop service and supervisor",
			"    kill      Terminate service",
			"    once      Do not restart if service stops",
			"    restart   Restart the service",
			"    start     Start the service",
			"    status    Print status",
			"    stop      Stop the service",
			"  Signals:",
			"    -1        USR1",
			"    -2        USR2",
			"    -a        ALRM",
			"    -c        CONT",
			"    -h        HUP",
			"    -i        INT",
			"    -k        KILL",
			"    -in       TTIN",
			"    -ou       TTOU",
			"    -q        QUIT",
			"    -s        STOP",
			"    -t        TERM",
			"    -w        WINCH",
			"  version", version)
	}

	flag.Parse()

	if *v {
		fmt.Printf("%s\n", version)
		os.Exit(0)
	}

	if flag.NFlag() > 1000 {
		println(a, c, h, i, in, ou, q, s, t, usr1, usr2, w, k)
	}

	// check options and flags
	exit := true
	if flag.NFlag() == 0 && flag.Arg(0) != "" {
		for _, v := range options {
			if flag.Arg(0) == v {
				exit = false
				if flag.NArg() == 2 {
					serviceName = flag.Arg(1)
				} else {
					exit = true
				}
				break
			}
		}
	} else if flag.NFlag() == 1 && flag.NArg() == 1 {
		serviceName = flag.Arg(0)
		exit = false
	}
	if exit {
		exit1(fmt.Errorf("Invalid arguments, use (\"%s -help\") for help.\n", os.Args[0]))
	}

	fmt.Printf("serviceName = %+v\n", serviceName)

	// get status for all services
	services, _ := immortal.FindServices(sdir)

	// get user $HOME/.immortal services
	if usr, err := user.Current(); err == nil {
		if userServices, err := immortal.FindServices(
			filepath.Join(usr.HomeDir, ".immortal"),
		); err == nil {
			services = append(services, userServices...)
		}
	}

	// apply options/signals to specified services
	wg.Add(len(services))
	for _, service := range services {
		if serviceName != "" {
			if !strings.HasPrefix(service.Name, serviceName) {
				wg.Done()
				continue
			}
		}
		switch flag.Arg(0) {
		case "status":
			go func(s *immortal.ServiceStatus) {
				defer wg.Done()
				status, err := immortal.GetStatus(s.Socket)
				if err != nil {
					immortal.PurgeServices(s.Socket)
				} else {
					s.Status = status
					if l := len(fmt.Sprintf("%d", status.Pid)); l > ppid {
						ppid = l
					}
					if l := len(status.Up); l > pup {
						pup = l
					}
					if l := len(status.Down); l > pdown {
						pdown = l
					}
					if l := len(s.Name); l > pname {
						pname = l
					}
				}
			}(service)
		case "exit":
			fmt.Printf("flag.Arg(0) = %+v\n", flag.Arg(0))
			wg.Done()
		default:
			wg.Done()
		}

	}
	wg.Wait()

	// format the output
	if ppid < 3 {
		ppid = 3
	}
	if pup < 2 {
		pup = 2
	}
	if pdown < 4 {
		pdown = 4
	}
	format := fmt.Sprintf("%%+%dv   %%+%ds   %%+%ds   %%-%ds   %%s\n",
		ppid,
		pup,
		pdown,
		pname,
	)

	fmt.Printf(format, "PID", "Up", "Down", "Name", "CMD")
	for _, s := range services {
		if s.Status.Pid > 0 {
			if s.Status.Down != "" {
				fmt.Printf(format, s.Status.Pid, s.Status.Up, s.Status.Down, immortal.Red(fmt.Sprintf("%-*s", pname, s.Name)), s.Status.Cmd)
			} else {
				fmt.Printf(format, s.Status.Pid, s.Status.Up, s.Status.Down, immortal.Green(fmt.Sprintf("%-*s", pname, s.Name)), s.Status.Cmd)
			}
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"launchpad.net/juju-core/state"
	"strconv"
	"strings"
)

// constraintsValue implements gnuflag.Value for a state.Constraints.
type constraintsValue struct {
	c *state.Constraints
}

func (v *constraintsValue) String() string {
	return v.c.String()
}

func (v *constraintsValue) Set(raw string) error {
	args := strings.Split(raw, " ")
	for _, arg := range args {
		eq := strings.Index(arg, "=")
		if eq <= 0 {
			return fmt.Errorf("malformed constraint %q", arg)
		}
		name, str := arg[:eq], arg[eq+1:]
		var err error
		switch name {
		case "cpu-cores":
			err = v.setCpuCores(str)
		case "cpu-power":
			err = v.setCpuPower(str)
		case "mem":
			err = v.setMem(str)
		default:
			return fmt.Errorf("unknown constraint %q", name)
		}
		if err != nil {
			return fmt.Errorf("bad %q constraint: %v", name, err)
		}
	}
	return nil
}

func (v *constraintsValue) setCpuCores(str string) (err error) {
	if v.c.CpuCores != nil {
		return fmt.Errorf("already set")
	}
	v.c.CpuCores, err = parseUint64(str)
	return
}

func (v *constraintsValue) setCpuPower(str string) (err error) {
	if v.c.CpuPower != nil {
		return fmt.Errorf("already set")
	}
	v.c.CpuPower, err = parseUint64(str)
	return
}

func parseUint64(str string) (*uint64, error) {
	var value uint64
	if str != "" {
		if val, err := strconv.Atoi(str); err != nil || val < 0 {
			return nil, fmt.Errorf("must be a non-negative integer")
		} else {
			value = uint64(val)
		}
	}
	return &value, nil
}

func (v *constraintsValue) setMem(str string) error {
	if v.c.Mem != nil {
		return fmt.Errorf("already set")
	}
	var value uint64
	if str != "" {
		mult := 1.0
		if m, ok := mbSuffixes[str[len(str)-1:]]; ok {
			str = str[:len(str)-1]
			mult = m
		}
		val, err := strconv.ParseFloat(str, 64)
		if err != nil || val < 0 {
			return fmt.Errorf("must be a non-negative float with optional M/G/T/P suffix")
		}
		val *= mult
		value = uint64(val)
	}
	v.c.Mem = &value
	return nil
}

var mbSuffixes = map[string]float64{
	"M": 1,
	"G": 1024,
	"T": 1024 * 1024,
	"P": 1024 * 1024 * 1024,
}
<commit_msg>round fractional MB up, not down<commit_after>package main

import (
	"fmt"
	"launchpad.net/juju-core/state"
	"math"
	"strconv"
	"strings"
)

// constraintsValue implements gnuflag.Value for a state.Constraints.
type constraintsValue struct {
	c *state.Constraints
}

func (v *constraintsValue) String() string {
	return v.c.String()
}

func (v *constraintsValue) Set(raw string) error {
	args := strings.Split(raw, " ")
	for _, arg := range args {
		eq := strings.Index(arg, "=")
		if eq <= 0 {
			return fmt.Errorf("malformed constraint %q", arg)
		}
		name, str := arg[:eq], arg[eq+1:]
		var err error
		switch name {
		case "cpu-cores":
			err = v.setCpuCores(str)
		case "cpu-power":
			err = v.setCpuPower(str)
		case "mem":
			err = v.setMem(str)
		default:
			return fmt.Errorf("unknown constraint %q", name)
		}
		if err != nil {
			return fmt.Errorf("bad %q constraint: %v", name, err)
		}
	}
	return nil
}

func (v *constraintsValue) setCpuCores(str string) (err error) {
	if v.c.CpuCores != nil {
		return fmt.Errorf("already set")
	}
	v.c.CpuCores, err = parseUint64(str)
	return
}

func (v *constraintsValue) setCpuPower(str string) (err error) {
	if v.c.CpuPower != nil {
		return fmt.Errorf("already set")
	}
	v.c.CpuPower, err = parseUint64(str)
	return
}

func parseUint64(str string) (*uint64, error) {
	var value uint64
	if str != "" {
		if val, err := strconv.Atoi(str); err != nil || val < 0 {
			return nil, fmt.Errorf("must be a non-negative integer")
		} else {
			value = uint64(val)
		}
	}
	return &value, nil
}

func (v *constraintsValue) setMem(str string) error {
	if v.c.Mem != nil {
		return fmt.Errorf("already set")
	}
	var value uint64
	if str != "" {
		mult := 1.0
		if m, ok := mbSuffixes[str[len(str)-1:]]; ok {
			str = str[:len(str)-1]
			mult = m
		}
		val, err := strconv.ParseFloat(str, 64)
		if err != nil || val < 0 {
			return fmt.Errorf("must be a non-negative float with optional M/G/T/P suffix")
		}
		val *= mult
		value = uint64(math.Ceil(val))
	}
	v.c.Mem = &value
	return nil
}

var mbSuffixes = map[string]float64{
	"M": 1,
	"G": 1024,
	"T": 1024 * 1024,
	"P": 1024 * 1024 * 1024,
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"image"
	"image/color"
	"image/draw"
	"image/png"
	"math"
	"net/http"
	"strconv"
	"time"

	"github.com/codahale/hdrhistogram"

	"golang.org/x/image/font"
	"golang.org/x/image/font/inconsolata"
	"golang.org/x/image/math/fixed"
)

// TODO(kr): display more than one bucket (in time-series?)
// TODO(kr): collect more fine-grain stats
// TODO(kr): coalesce /debug/vars requests (cache them?)

var (
	dims       = image.Rect(0, 0, 800, 100)
	lineColor  = color.RGBA{R: 0xff, A: 0xff}
	labelColor = color.Black
	drawer     = font.Drawer{
		Src:  image.NewUniform(labelColor),
		Face: inconsolata.Regular8x16,
	}
)

func heatmap(w http.ResponseWriter, req *http.Request) {
	query := req.URL.Query()
	name := query.Get("name")
	id, err := strconv.Atoi(query.Get("id"))
	if err != nil {
		pngError(w, err)
		return
	}

	dv := getDebugVars(id)
	if dv == nil {
		pngError(w, errors.New("not found"))
		return
	}

	latency, ok := dv.Latency[name]
	if !ok {
		pngError(w, errors.New("not found"))
		return
	}

	b0 := latency.Buckets[0]
	img := newImage(dims)
	d := drawer
	d.Dst = img
	drawf(d, 4, 20, "%v", time.Duration(b0.Histogram.HighestTrackableValue))
	drawf(d, 4, 38, "%s", name)
	drawf(d, 4, 54, "over: %d", b0.Over)
	graph(img, hdrhistogram.Import(&b0.Histogram), lineColor, labelColor)
	png.Encode(w, img)
}

func graph(img *image.RGBA, hist *hdrhistogram.Histogram, lineColor, labelColor color.Color) {
	graph := img.SubImage(img.Bounds().Inset(1)).(*image.RGBA)
	gdims := graph.Bounds().Inset(1)
	d := drawer
	d.Dst = graph

	labelDigits := 0
	labelPixels := 50
	p := 0.5
	for x := 0; x < gdims.Max.X; x++ {
		q := 1 - p
		v := hist.ValueAtQuantile(100 * q)
		y := int(scale(v, hist.HighestTrackableValue(), int64(gdims.Max.Y)))
		graph.Set(x, gdims.Max.Y-y, lineColor)
		if labelPixels >= 50 && digits(p) > labelDigits {
			labelPixels = 0
			labelDigits = digits(p)
			for i := 0; i < 5; i++ {
				graph.Set(x, gdims.Max.Y-i, labelColor)
			}
			prec := labelDigits - 3
			if prec < 0 {
				prec = 0
			}
			drawf(d, x+4, gdims.Max.Y-2, "p%.*f", prec, 100*q)
		}
		labelPixels++
		p *= 0.98
	}

	// special case for p50
	drawf(d, 4, gdims.Max.Y-2, "p50")
}

func digits(p float64) int {
	return -int(math.Floor(math.Log10(p)))
}

func drawf(d font.Drawer, x, y int, format string, args ...interface{}) {
	d.Dot = fixed.P(x, y)
	d.DrawString(fmt.Sprintf(format, args...))
}

func scale(v, from, to int64) int64 {
	if v > from {
		return to
	} else if v < 0 {
		return 0
	}
	return v * to / from
}

func pngError(w http.ResponseWriter, err error) {
	img := newImage(dims)
	d := drawer
	d.Dst = img
	drawf(d, 10, 25, "%s", err.Error())
	w.WriteHeader(500)
	png.Encode(w, img)
}

func newImage(dims image.Rectangle) *image.RGBA {
	img := image.NewRGBA(dims)
	draw.Draw(img, dims, image.Black, image.ZP, draw.Over)
	draw.Draw(img, dims.Inset(1), image.White, image.ZP, draw.Over)
	return img
}
<commit_msg>cmd/perfdash: remove stale comment<commit_after>package main

import (
	"errors"
	"fmt"
	"image"
	"image/color"
	"image/draw"
	"image/png"
	"math"
	"net/http"
	"strconv"
	"time"

	"github.com/codahale/hdrhistogram"

	"golang.org/x/image/font"
	"golang.org/x/image/font/inconsolata"
	"golang.org/x/image/math/fixed"
)

// TODO(kr): display more than one bucket (in time-series?)
// TODO(kr): collect more fine-grain stats

var (
	dims       = image.Rect(0, 0, 800, 100)
	lineColor  = color.RGBA{R: 0xff, A: 0xff}
	labelColor = color.Black
	drawer     = font.Drawer{
		Src:  image.NewUniform(labelColor),
		Face: inconsolata.Regular8x16,
	}
)

func heatmap(w http.ResponseWriter, req *http.Request) {
	query := req.URL.Query()
	name := query.Get("name")
	id, err := strconv.Atoi(query.Get("id"))
	if err != nil {
		pngError(w, err)
		return
	}

	dv := getDebugVars(id)
	if dv == nil {
		pngError(w, errors.New("not found"))
		return
	}

	latency, ok := dv.Latency[name]
	if !ok {
		pngError(w, errors.New("not found"))
		return
	}

	b0 := latency.Buckets[0]
	img := newImage(dims)
	d := drawer
	d.Dst = img
	drawf(d, 4, 20, "%v", time.Duration(b0.Histogram.HighestTrackableValue))
	drawf(d, 4, 38, "%s", name)
	drawf(d, 4, 54, "over: %d", b0.Over)
	graph(img, hdrhistogram.Import(&b0.Histogram), lineColor, labelColor)
	png.Encode(w, img)
}

func graph(img *image.RGBA, hist *hdrhistogram.Histogram, lineColor, labelColor color.Color) {
	graph := img.SubImage(img.Bounds().Inset(1)).(*image.RGBA)
	gdims := graph.Bounds().Inset(1)
	d := drawer
	d.Dst = graph

	labelDigits := 0
	labelPixels := 50
	p := 0.5
	for x := 0; x < gdims.Max.X; x++ {
		q := 1 - p
		v := hist.ValueAtQuantile(100 * q)
		y := int(scale(v, hist.HighestTrackableValue(), int64(gdims.Max.Y)))
		graph.Set(x, gdims.Max.Y-y, lineColor)
		if labelPixels >= 50 && digits(p) > labelDigits {
			labelPixels = 0
			labelDigits = digits(p)
			for i := 0; i < 5; i++ {
				graph.Set(x, gdims.Max.Y-i, labelColor)
			}
			prec := labelDigits - 3
			if prec < 0 {
				prec = 0
			}
			drawf(d, x+4, gdims.Max.Y-2, "p%.*f", prec, 100*q)
		}
		labelPixels++
		p *= 0.98
	}

	// special case for p50
	drawf(d, 4, gdims.Max.Y-2, "p50")
}

func digits(p float64) int {
	return -int(math.Floor(math.Log10(p)))
}

func drawf(d font.Drawer, x, y int, format string, args ...interface{}) {
	d.Dot = fixed.P(x, y)
	d.DrawString(fmt.Sprintf(format, args...))
}

func scale(v, from, to int64) int64 {
	if v > from {
		return to
	} else if v < 0 {
		return 0
	}
	return v * to / from
}

func pngError(w http.ResponseWriter, err error) {
	img := newImage(dims)
	d := drawer
	d.Dst = img
	drawf(d, 10, 25, "%s", err.Error())
	w.WriteHeader(500)
	png.Encode(w, img)
}

func newImage(dims image.Rectangle) *image.RGBA {
	img := image.NewRGBA(dims)
	draw.Draw(img, dims, image.Black, image.ZP, draw.Over)
	draw.Draw(img, dims.Inset(1), image.White, image.ZP, draw.Over)
	return img
}
<|endoftext|>


<commit_before>package bmp

import (
	"errors"
	"gopkg.in/yaml.v2"
	"path/filepath"
	"io/ioutil"
	"fmt"
	"os"
	"strconv"
	"strings"

	clients "github.com/cloudfoundry-community/bosh-softlayer-tools/clients"
	cmds "github.com/cloudfoundry-community/bosh-softlayer-tools/cmds"
	common "github.com/cloudfoundry-community/bosh-softlayer-tools/common"
	tablewriter "github.com/olekukonko/tablewriter"
)

type bmsCommand struct {
	args    []string
	options cmds.Options

	ui      common.UI
	printer common.Printer

	bmpClient clients.BmpClient
}

func NewBmsCommand(options cmds.Options, bmpClient clients.BmpClient) bmsCommand {
	consoleUi := common.NewConsoleUi()

	return bmsCommand{
		options:   options,
		ui:        consoleUi,
		printer:   common.NewDefaultPrinter(consoleUi, options.Verbose),
		bmpClient: bmpClient,
	}
}

func (cmd bmsCommand) Name() string {
	return "bms"
}

func (cmd bmsCommand) Description() string {
	return "List all bare metals"
}

func (cmd bmsCommand) Usage() string {
	return "bmp bms --deployment[-d] <deployment file>"
}

func (cmd bmsCommand) Options() cmds.Options {
	return cmd.options
}

func (cmd bmsCommand) Validate() (bool, error) {
	cmd.printer.Printf("Validating %s command: args: %#v, options: %#v", cmd.Name(), cmd.args, cmd.options)
	if cmd.options.Deployment == "" {
		return false, errors.New("please specify the deployment file with -d")
	}

	_, err := os.Stat(cmd.options.Deployment)
	if os.IsNotExist(err) {
		return false, errors.New(fmt.Sprintf("deployment file '%s' doesn't exist", cmd.options.Deployment))
	}

	return true, nil
}

func (cmd bmsCommand) Execute(args []string) (int, error) {
	cmd.printer.Printf("Executing %s command: args: %#v, options: %#v", cmd.Name(), cmd.args, cmd.options)

	filename, _ := filepath.Abs(cmd.options.Deployment)
	yamlFile, err := ioutil.ReadFile(filename)
	if err != nil{
		errorMessage := fmt.Sprintf("bmp: could not read File '%s', error message '%s'", filename, err.Error())
		return 1, errors.New(errorMessage)
	}

	var deploymentInfo clients.Deployment
	err = yaml.Unmarshal(yamlFile, &deploymentInfo)
	if err != nil {
		errorMessage := fmt.Sprintf("bmp: failed to decode Yaml File '%s', error message '%s'", filename, err.Error())
		return 1, errors.New(errorMessage)
	}

	deploymentName := deploymentInfo.Name
	bmsResponse, err := cmd.bmpClient.Bms(deploymentName)
	if err != nil {
		return bmsResponse.Status, err
	}

	if bmsResponse.Status != 200 {
		return bmsResponse.Status, nil
	}

	table := tablewriter.NewWriter(os.Stdout)
	table.SetHeader([]string{"Id", "Hostname", "IPs", "Hardware_status", "Memory","Cpu", "Provision_date"})

	content := make([][]string,len(bmsResponse.Data),7)
	for i, serverInfo := range bmsResponse.Data {
		IPs := strings.Join([]string{serverInfo.Private_ip_address, serverInfo.Public_ip_address}, "/")
		content[i] = []string{
			strconv.Itoa(serverInfo.Id),
			serverInfo.Hostname,
			IPs,
			serverInfo.Hardware_status,
			strconv.Itoa(serverInfo.Memory),
			strconv.Itoa(serverInfo.Cpu),
			serverInfo.Provision_date}
	}

	for _, value := range content {
		table.Append(value)
	}
	table.Render()

	return 0, nil
}
<commit_msg>updated bms command output<commit_after>package bmp

import (
	"errors"
	"gopkg.in/yaml.v2"
	"path/filepath"
	"io/ioutil"
	"fmt"
	"os"
	"strconv"
	"strings"

	clients "github.com/cloudfoundry-community/bosh-softlayer-tools/clients"
	cmds "github.com/cloudfoundry-community/bosh-softlayer-tools/cmds"
	common "github.com/cloudfoundry-community/bosh-softlayer-tools/common"
	tablewriter "github.com/olekukonko/tablewriter"
)

type bmsCommand struct {
	args    []string
	options cmds.Options

	ui      common.UI
	printer common.Printer

	bmpClient clients.BmpClient
}

func NewBmsCommand(options cmds.Options, bmpClient clients.BmpClient) bmsCommand {
	consoleUi := common.NewConsoleUi()

	return bmsCommand{
		options:   options,
		ui:        consoleUi,
		printer:   common.NewDefaultPrinter(consoleUi, options.Verbose),
		bmpClient: bmpClient,
	}
}

func (cmd bmsCommand) Name() string {
	return "bms"
}

func (cmd bmsCommand) Description() string {
	return "List all bare metals"
}

func (cmd bmsCommand) Usage() string {
	return "bmp bms --deployment[-d] <deployment file>"
}

func (cmd bmsCommand) Options() cmds.Options {
	return cmd.options
}

func (cmd bmsCommand) Validate() (bool, error) {
	cmd.printer.Printf("Validating %s command: args: %#v, options: %#v", cmd.Name(), cmd.args, cmd.options)
	if cmd.options.Deployment == "" {
		return false, errors.New("please specify the deployment file with -d")
	}

	_, err := os.Stat(cmd.options.Deployment)
	if os.IsNotExist(err) {
		return false, errors.New(fmt.Sprintf("deployment file '%s' doesn't exist", cmd.options.Deployment))
	}

	return true, nil
}

func (cmd bmsCommand) Execute(args []string) (int, error) {
	cmd.printer.Printf("Executing %s command: args: %#v, options: %#v", cmd.Name(), cmd.args, cmd.options)

	filename, _ := filepath.Abs(cmd.options.Deployment)
	yamlFile, err := ioutil.ReadFile(filename)
	if err != nil{
		errorMessage := fmt.Sprintf("bmp: could not read File '%s', error message '%s'", filename, err.Error())
		return 1, errors.New(errorMessage)
	}

	var deploymentInfo clients.Deployment
	err = yaml.Unmarshal(yamlFile, &deploymentInfo)
	if err != nil {
		errorMessage := fmt.Sprintf("bmp: failed to decode Yaml File '%s', error message '%s'", filename, err.Error())
		return 1, errors.New(errorMessage)
	}

	deploymentName := deploymentInfo.Name
	bmsResponse, err := cmd.bmpClient.Bms(deploymentName)
	if err != nil {
		return bmsResponse.Status, err
	}

	if bmsResponse.Status != 200 {
		return bmsResponse.Status, nil
	}

	table := tablewriter.NewWriter(os.Stdout)
	table.SetHeader([]string{"Id", "Hostname", "IPs", "Hardware_status", "Memory","Cpu", "Provision_date"})

	content := make([][]string,len(bmsResponse.Data))
	for i, serverInfo := range bmsResponse.Data {
		IPs := strings.Join([]string{serverInfo.Private_ip_address, serverInfo.Public_ip_address}, "/")
		content[i] = []string{
			strconv.Itoa(serverInfo.Id),
			serverInfo.Hostname,
			IPs,
			serverInfo.Hardware_status,
			strconv.Itoa(serverInfo.Memory),
			strconv.Itoa(serverInfo.Cpu),
			serverInfo.Provision_date}
	}

	for _, value := range content {
		table.Append(value)
	}
	table.Render()

	return 0, nil
}
<|endoftext|>


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

// Script takes the arg list, does minimal rewriting, builds it and runs it
package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"syscall"

	"golang.org/x/tools/imports"
)

type mount struct {
	source string
	target string
	fstype string
	flags  uintptr
	opts   string
}

var (
	startPart = "package main\n"
	initPart  = "func init() {\n	addBuiltIn(\"%s\", %s)\n}\nfunc %s(c*Command) error {\nvar err error\n"
	//	endPart = "\n}\n)\n}\n"
	endPart   = "\nreturn err\n}\n"
	namespace = []mount{
		{source: "tmpfs", target: "/src/cmds/sh", fstype: "tmpfs", flags: syscall.MS_MGC_VAL, opts: ""},
		{source: "tmpfs", target: "/ubin", fstype: "tmpfs", flags: syscall.MS_MGC_VAL, opts: ""},
	}
)

func main() {
	opts := imports.Options{
		Fragment:  true,
		AllErrors: true,
		Comments:  true,
		TabIndent: true,
		TabWidth:  8,
	}
	flag.Parse()
	a := flag.Args()
	if len(a) < 2 || len(a) % 2 != 0 {
		log.Fatalf("Usage: builtin <command> <code> [<command> <code>]*")
	}
	filemap := make(map[string][]byte)
	for ;len(a) > 0; a = a[2:] {
		goCode := startPart
		// Simple programs are just bits of code for main ...
		if a[1][0] == '{' {
			goCode = goCode + fmt.Sprintf(initPart, a[0], a[0], a[0])
			goCode = goCode + a[1][1:len(a[1])-1]
		} else {
			for _, v := range a[1:] {
				if v == "{" {
					goCode = goCode + fmt.Sprintf(initPart, a[0])
					continue
				}
				// FIXME: should only look for last arg.
				if v == "}" {
					break
				}
				goCode = goCode + v + "\n"
			}
		}
		goCode = goCode + endPart
		log.Printf("\n---------------------\n%v\n------------------------\n", goCode)
		fullCode, err := imports.Process("commandline", []byte(goCode), &opts)
		if err != nil {
			log.Fatalf("bad parse: '%v': %v", goCode, err)
		}
		log.Printf("\n----FULLCODE---------\n%v\n------FULLCODE----------\n", string(fullCode))
		bName := path.Join("/src/cmds/sh", a[0]+".go")
		//fmt.Printf("filemap %v\n", filemap)
		filemap[bName] = fullCode
		//log.Printf("%v: %v", bName, fullCode)
	}

	// processed code, read in shell files.
	globs, err := filepath.Glob("/src/cmds/sh/*.go")
	if err != nil {
		log.Fatal(err)
	}
	for _, i := range globs {
		if b, err := ioutil.ReadFile(i); err != nil {
			log.Fatal(err)
		} else {
			if _, ok := filemap[i]; ok {
				log.Fatalf("%v exists", i)
			}
			filemap[i] = b
		}
	}

	if b, err := ioutil.ReadFile("/proc/mounts"); err == nil && false {
		log.Printf("m %v\n", string(b))
	}
	// we'd like to do this here, but it seems it doesn't end
	// up applying to all procs in this group, leading to confusion.
	// sometimes they get the private mount, sometimes not. So we had
	// to hack it in the shell.
	// FIXME
	if false {
		if err := syscall.Unshare(syscall.CLONE_NEWNS); err != nil {
			log.Fatal(err)
		}
	}
	if b, err := ioutil.ReadFile("/proc/mounts"); err == nil {
		fmt.Printf("m %v\n", b)
	}

	// We are rewriting the shell. We need to create a new binary, i.e.
	// rewrite the one in /ubin. Sadly, there is no way to say "mount THIS bin
	// before THAT bin". There will be ca. 3.18 and we might as well wait for
	// that to become common. For now, we essentially erase /ubin but mounting
	// a tmpfs over it.
	// This would be infinitely easier with a true union file system. Oh well.
	for _, m := range namespace {
		if err := syscall.Mount(m.source, m.target, m.fstype, m.flags, m.opts); err != nil {
			log.Printf("Mount :%s: on :%s: type :%s: flags %x: opts %v: %v\n", m.source, m.target, m.fstype, m.flags, m.opts, err)
		}
	}
	//log.Printf("filemap: %v", filemap)
	// write the new /src/cmds/sh
	for i, v := range filemap {
		if err = ioutil.WriteFile(i, v, 0600); err != nil {
			log.Fatal(err)
		}
	}

	// the big fun: just run it. The Right Things Happen.
	cmd := exec.Command("/buildbin/sh")
	cmd.Stdin = os.Stdin
	cmd.Stderr = os.Stderr
	cmd.Stdout = os.Stdout
	// TODO: figure out why we get EPERM when we use this.
	//cmd.SysProcAttr = &syscall.SysProcAttr{Setctty: true, Setsid: true,}
	log.Printf("Run %v", cmd)
	err = cmd.Run()
	if err != nil {
		log.Printf("%v\n", err)
	}
	// Unshare doesn't work in a sane way due to a Go issue?
	for _, m := range namespace {
		if err := syscall.Unmount(m.target, syscall.MNT_FORCE); err != nil {
			log.Printf("Umount :%s: %v\n", m.target, err)
		}
	}
	log.Printf("init: /ubin/sh returned!\n")
}
<commit_msg>builtin: fix the builtin command.<commit_after>// Copyright 2012 the u-root Authors. All rights reserved
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Script takes the arg list, does minimal rewriting, builds it and runs it
package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"syscall"

	"golang.org/x/tools/imports"
)

const (
	rushPath = "/src/github.com/u-root/u-root/cmds/rush"
)

type mount struct {
	source string
	target string
	fstype string
	flags  uintptr
	opts   string
}

var (
	startPart = "package main\n"
	initPart  = "func init() {\n	addBuiltIn(\"%s\", %s)\n}\nfunc %s(c*Command) error {\nvar err error\n"
	//	endPart = "\n}\n)\n}\n"
	endPart   = "\nreturn err\n}\n"
	namespace = []mount{
		{source: "tmpfs", target: rushPath, fstype: "tmpfs", flags: syscall.MS_MGC_VAL, opts: ""},
		{source: "tmpfs", target: "/ubin", fstype: "tmpfs", flags: syscall.MS_MGC_VAL, opts: ""},
	}
	debug = flag.Bool("d", false, "Print debug info")
)

func main() {
	opts := imports.Options{
		Fragment:  true,
		AllErrors: true,
		Comments:  true,
		TabIndent: true,
		TabWidth:  8,
	}
	flag.Parse()
	a := flag.Args()
	if len(a) < 2 || len(a) % 2 != 0 {
		log.Fatalf("Usage: builtin <command> <code> [<command> <code>]*")
	}
	filemap := make(map[string][]byte)
	for ;len(a) > 0; a = a[2:] {
		goCode := startPart
		// Simple programs are just bits of code for main ...
		if a[1][0] == '{' {
			goCode = goCode + fmt.Sprintf(initPart, a[0], a[0], a[0])
			goCode = goCode + a[1][1:len(a[1])-1]
		} else {
			for _, v := range a[1:] {
				if v == "{" {
					goCode = goCode + fmt.Sprintf(initPart, a[0])
					continue
				}
				// FIXME: should only look for last arg.
				if v == "}" {
					break
				}
				goCode = goCode + v + "\n"
			}
		}
		goCode = goCode + endPart
		if *debug {
			log.Printf("\n---------------------\n%v\n------------------------\n", goCode)
		}
		fullCode, err := imports.Process("commandline", []byte(goCode), &opts)
		if err != nil {
			log.Fatalf("bad parse: '%v': %v", goCode, err)
		}
		if *debug {
			log.Printf("\n----FULLCODE---------\n%v\n------FULLCODE----------\n", string(fullCode))
		}
		bName := path.Join(rushPath, a[0]+".go")
		filemap[bName] = fullCode
	}

	// processed code, read in shell files.
	globs, err := filepath.Glob(rushPath + "/*.go")
	if err != nil {
		log.Fatal(err)
	}
	for _, i := range globs {
		if b, err := ioutil.ReadFile(i); err != nil {
			log.Fatal(err)
		} else {
			if _, ok := filemap[i]; ok {
				log.Fatalf("%v exists", i)
			}
			filemap[i] = b
		}
	}

	if b, err := ioutil.ReadFile("/proc/mounts"); err == nil && false {
		log.Printf("m %v\n", string(b))
	}
	// we'd like to do this here, but it seems it doesn't end
	// up applying to all procs in this group, leading to confusion.
	// sometimes they get the private mount, sometimes not.
	// It's a fundamental limit in the go runtime.
	// So we hack it in the shell.
	// There is no FIXME
	if false {
		if err := syscall.Unshare(syscall.CLONE_NEWNS); err != nil {
			log.Fatal(err)
		}
	}
	if *debug {
		if b, err := ioutil.ReadFile("/proc/mounts"); err == nil {
			log.Printf("Reading /proc/mount:m %v\n", b)
		}
	}

	// We are rewriting the shell. We need to create a new binary, i.e.
	// rewrite the one in /ubin. Sadly, there is no way to say "mount THIS bin
	// before THAT bin". There will be ca. 3.18 and we might as well wait for
	// that to become common. For now, we essentially erase /ubin but mounting
	// a tmpfs over it.
	// This would be infinitely easier with a true union file system. Oh well.
	for _, m := range namespace {
		if err := syscall.Mount(m.source, m.target, m.fstype, m.flags, m.opts); err != nil {
			log.Printf("Mount :%s: on :%s: type :%s: flags %x: opts %v: %v\n", m.source, m.target, m.fstype, m.flags, m.opts, err)
		}
	}
	// write the new rushPath
	for i, v := range filemap {
		if err = ioutil.WriteFile(i, v, 0600); err != nil {
			log.Fatal(err)
		}
	}

	// the big fun: just run it. The Right Things Happen.
	cmd := exec.Command("/buildbin/rush")
	cmd.Stdin = os.Stdin
	cmd.Stderr = os.Stderr
	cmd.Stdout = os.Stdout
	// TODO: figure out why we get EPERM when we use this.
	//cmd.SysProcAttr = &syscall.SysProcAttr{Setctty: true, Setsid: true,}
	if *debug {
		log.Printf("Run %v", cmd)
	}
	if err := cmd.Run(); err != nil {
		log.Printf("%v\n", err)
	}
	// Unshare doesn't work in a sane way due to a Go issue?
	for _, m := range namespace {
		if err := syscall.Unmount(m.target, syscall.MNT_FORCE); err != nil {
			log.Printf("Umount :%s: %v\n", m.target, err)
		}
	}
	log.Printf("builtin: /ubin/rush returned!\n")
}
<|endoftext|>