<commit_before>package dependencies

import (
	"errors"
	"fmt"
	"os"
	"os/exec"
	"strings"

	log "github.com/Sirupsen/logrus"
	"github.com/bitrise-io/bitrise-cli/bitrise"
)

// CheckProgramInstalledPath ...
func CheckProgramInstalledPath(clcommand string) (string, error) {
	cmd := exec.Command("which", clcommand)
	cmd.Stderr = os.Stderr
	outBytes, err := cmd.Output()
	outStr := string(outBytes)
	return strings.TrimSpace(outStr), err
}

// CheckIsRubyGemsInstalled ...
func CheckIsRubyGemsInstalled() error {
	officialSiteURL := "https://rubygems.org"

	progInstallPth, err := CheckProgramInstalledPath("gem")
	if err != nil {
		fmt.Println()
		log.Warn("It seems that RubyGems is not installed on your system.")
		log.Infoln("RubyGems is required in order to be able to auto-install all the bitrise dependencies.")
		// log.Infoln("You should be able to install brew by copying this command and running it in your Terminal:")
		// log.Infoln(brewRubyInstallCmdString)
		log.Infoln("You can find more information about RubyGems on it's official site at:", officialSiteURL)
		log.Warn("Once the installation of RubyGems is finished you should call the bitrise setup again.")
		return err
	}
	verStr, err := bitrise.RunCommandAndReturnStdout("gem", "--version")
	if err != nil {
		log.Infoln("")
		return errors.New("Failed to get version")
	}
	log.Debugln(" * [OK] RubyGems :", progInstallPth)
	log.Debugln("        version :", verStr)
	return nil
}

// CheckIsHomebrewInstalled ...
func CheckIsHomebrewInstalled() error {
	brewRubyInstallCmdString := `$ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"`
	officialSiteURL := "http://brew.sh/"

	progInstallPth, err := CheckProgramInstalledPath("brew")
	if err != nil {
		fmt.Println()
		log.Warn("It seems that Homebrew is not installed on your system.")
		log.Infoln("Homebrew (short: brew) is required in order to be able to auto-install all the bitrise dependencies.")
		log.Infoln("You should be able to install brew by copying this command and running it in your Terminal:")
		log.Infoln(brewRubyInstallCmdString)
		log.Infoln("You can find more information about Homebrew on it's official site at:", officialSiteURL)
		log.Warn("Once the installation of brew is finished you should call the bitrise setup again.")
		return err
	}
	verStr, err := bitrise.RunCommandAndReturnStdout("brew", "--version")
	if err != nil {
		log.Infoln("")
		return errors.New("Failed to get version")
	}
	log.Debugln(" * [OK] Homebrew :", progInstallPth)
	log.Debugln("        version :", verStr)
	return nil
}

// CheckIsXcodeCLTInstalled ...
func CheckIsXcodeCLTInstalled() error {
	progInstallPth, err := CheckProgramInstalledPath("xcodebuild")
	if err != nil {
		fmt.Println()
		log.Warn("It seems that the Xcode Command Line Tools are not installed on your system.")
		log.Infoln("You can install it by running the following command in your Terminal:")
		log.Infoln("xcode-select --install")
		log.Warn("Once the installation is finished you should call the bitrise setup again.")
		return err
	}
	verStr, err := bitrise.RunCommandAndReturnStdout("xcodebuild", "-version")
	if err != nil {
		log.Infoln("")
		return errors.New("Failed to get version")
	}
	xcodeSelectPth, err := bitrise.RunCommandAndReturnStdout("xcode-select", "-p")
	if err != nil {
		log.Infoln("")
		return errors.New("Failed to get Xcode path")
	}
	log.Infoln(" * [OK] xcodebuild path :", progInstallPth)
	log.Infoln("        active Xcode (Command Line Tools) path :", xcodeSelectPth)
	log.Infoln("        version :", strings.Join(strings.Split(verStr, "\n"), " | "))
	return nil
}

func checkIsBitriseToolInstalled(toolname, minVersion string, isInstall bool) error {
	doInstall := func() error {
		installCmdLines := []string{
			"curl -L https://github.com/bitrise-io/" + toolname + "/releases/download/" + minVersion + "/" + toolname + "-$(uname -s)-$(uname -m) > /usr/local/bin/" + toolname,
			"chmod +x /usr/local/bin/" + toolname,
		}
		officialGithub := "https://github.com/bitrise-io/" + toolname
		fmt.Println()
		log.Warnln("No supported " + toolname + " version found.")
		log.Infoln("You can find more information about "+toolname+" on it's official GitHub page:", officialGithub)
		fmt.Println()

		// Install
		log.Infoln("Installing...")
		fmt.Println(strings.Join(installCmdLines, "\n"))
		if err := bitrise.RunBashCommandLines(installCmdLines); err != nil {
			return err
		}

		// check again
		return checkIsBitriseToolInstalled(toolname, minVersion, false)
	}

	// check whether installed
	progInstallPth, err := CheckProgramInstalledPath(toolname)
	if err != nil {
		if !isInstall {
			return err
		}

		return doInstall()
	}
	verStr, err := bitrise.RunCommandAndReturnStdout(toolname, "-version")
	if err != nil {
		log.Infoln("")
		return errors.New("Failed to get version")
	}

	// version check
	isVersionOk, err := bitrise.IsVersionGreaterOrEqual(verStr, minVersion)
	if err != nil {
		log.Error("Failed to validate installed version")
		return err
	}
	if !isVersionOk {
		log.Warn("Installed "+toolname+" found, but not a supported version: ", verStr)
		if !isInstall {
			return errors.New("Failed to install required version.")
		}
		log.Warn("Updating...")
		return doInstall()
	}

	log.Infoln(" * [OK] "+toolname+" :", progInstallPth)
	log.Infoln("        version :", verStr)
	return nil
}

// CheckIsEnvmanInstalled ...
func CheckIsEnvmanInstalled(minEnvmanVersion string) error {
	toolname := "envman"
	minVersion := minEnvmanVersion
	if err := checkIsBitriseToolInstalled(toolname, minVersion, true); err != nil {
		return err
	}
	return nil
}

// CheckIsStepmanInstalled ...
func CheckIsStepmanInstalled(minStepmanVersion string) error {
	toolname := "stepman"
	minVersion := minStepmanVersion
	if err := checkIsBitriseToolInstalled(toolname, minVersion, true); err != nil {
		return err
	}
	return nil
}

// InstallWithBrewIfNeeded ...
func InstallWithBrewIfNeeded(tool string) error {
	if err := CheckIsHomebrewInstalled(); err != nil {
		return err
	}
	if _, err := CheckProgramInstalledPath(tool); err != nil {
		args := []string{"install", tool}
		if err := bitrise.RunCommand("brew", args...); err != nil {
			return err
		}
	}
	return nil
}

// InstallWithRubyGemsIfNeeded ...
func InstallWithRubyGemsIfNeeded(gemName string) error {
	if err := CheckIsRubyGemsInstalled(); err != nil {
		return err
	}
	if _, err := CheckProgramInstalledPath(gemName); err != nil {
		args := []string{"install", gemName}
		if err := bitrise.RunCommand("gem", args...); err != nil {
			return err
		}
	}
	return nil
}
<commit_msg>dependencies: no full Xcode required, only Command line tools<commit_after>package dependencies

import (
	"errors"
	"fmt"
	"os"
	"os/exec"
	"strings"

	log "github.com/Sirupsen/logrus"
	"github.com/bitrise-io/bitrise-cli/bitrise"
)

// CheckProgramInstalledPath ...
func CheckProgramInstalledPath(clcommand string) (string, error) {
	cmd := exec.Command("which", clcommand)
	cmd.Stderr = os.Stderr
	outBytes, err := cmd.Output()
	outStr := string(outBytes)
	return strings.TrimSpace(outStr), err
}

// CheckIsRubyGemsInstalled ...
func CheckIsRubyGemsInstalled() error {
	officialSiteURL := "https://rubygems.org"

	progInstallPth, err := CheckProgramInstalledPath("gem")
	if err != nil {
		fmt.Println()
		log.Warn("It seems that RubyGems is not installed on your system.")
		log.Infoln("RubyGems is required in order to be able to auto-install all the bitrise dependencies.")
		// log.Infoln("You should be able to install brew by copying this command and running it in your Terminal:")
		// log.Infoln(brewRubyInstallCmdString)
		log.Infoln("You can find more information about RubyGems on it's official site at:", officialSiteURL)
		log.Warn("Once the installation of RubyGems is finished you should call the bitrise setup again.")
		return err
	}
	verStr, err := bitrise.RunCommandAndReturnStdout("gem", "--version")
	if err != nil {
		log.Infoln("")
		return errors.New("Failed to get version")
	}
	log.Debugln(" * [OK] RubyGems :", progInstallPth)
	log.Debugln("        version :", verStr)
	return nil
}

// CheckIsHomebrewInstalled ...
func CheckIsHomebrewInstalled() error {
	brewRubyInstallCmdString := `$ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"`
	officialSiteURL := "http://brew.sh/"

	progInstallPth, err := CheckProgramInstalledPath("brew")
	if err != nil {
		fmt.Println()
		log.Warn("It seems that Homebrew is not installed on your system.")
		log.Infoln("Homebrew (short: brew) is required in order to be able to auto-install all the bitrise dependencies.")
		log.Infoln("You should be able to install brew by copying this command and running it in your Terminal:")
		log.Infoln(brewRubyInstallCmdString)
		log.Infoln("You can find more information about Homebrew on it's official site at:", officialSiteURL)
		log.Warn("Once the installation of brew is finished you should call the bitrise setup again.")
		return err
	}
	verStr, err := bitrise.RunCommandAndReturnStdout("brew", "--version")
	if err != nil {
		log.Infoln("")
		return errors.New("Failed to get version")
	}
	log.Debugln(" * [OK] Homebrew :", progInstallPth)
	log.Debugln("        version :", verStr)
	return nil
}

// CheckIsXcodeCLTInstalled ...
func CheckIsXcodeCLTInstalled() error {
	progInstallPth, err := CheckProgramInstalledPath("xcodebuild")
	if err != nil {
		fmt.Println()
		log.Warn("It seems that the Xcode Command Line Tools are not installed on your system.")
		log.Infoln("You can install it by running the following command in your Terminal:")
		log.Infoln("xcode-select --install")
		log.Warn("Once the installation is finished you should call the bitrise setup again.")
		return err
	}
	xcodeSelectPth, err := bitrise.RunCommandAndReturnStdout("xcode-select", "-p")
	if err != nil {
		log.Infoln("")
		return errors.New("Failed to get Xcode path")
	}

	verStr, err := bitrise.RunCommandAndReturnStdout("xcodebuild", "-version")
	if err != nil {
		log.Infoln("")
		log.Warn("No Xcode found, only the Xcode Command Line Tools are available!")
		log.Warn("Full Xcode is required to build, test and archive iOS apps!")
		verStr = "No full Xcode available, only Command Line Tools."
	}

	log.Infoln(" * [OK] xcodebuild path :", progInstallPth)
	log.Infoln("        active Xcode (Command Line Tools) path :", xcodeSelectPth)
	log.Infoln("        version :", strings.Join(strings.Split(verStr, "\n"), " | "))
	return nil
}

func checkIsBitriseToolInstalled(toolname, minVersion string, isInstall bool) error {
	doInstall := func() error {
		installCmdLines := []string{
			"curl -L https://github.com/bitrise-io/" + toolname + "/releases/download/" + minVersion + "/" + toolname + "-$(uname -s)-$(uname -m) > /usr/local/bin/" + toolname,
			"chmod +x /usr/local/bin/" + toolname,
		}
		officialGithub := "https://github.com/bitrise-io/" + toolname
		fmt.Println()
		log.Warnln("No supported " + toolname + " version found.")
		log.Infoln("You can find more information about "+toolname+" on it's official GitHub page:", officialGithub)
		fmt.Println()

		// Install
		log.Infoln("Installing...")
		fmt.Println(strings.Join(installCmdLines, "\n"))
		if err := bitrise.RunBashCommandLines(installCmdLines); err != nil {
			return err
		}

		// check again
		return checkIsBitriseToolInstalled(toolname, minVersion, false)
	}

	// check whether installed
	progInstallPth, err := CheckProgramInstalledPath(toolname)
	if err != nil {
		if !isInstall {
			return err
		}

		return doInstall()
	}
	verStr, err := bitrise.RunCommandAndReturnStdout(toolname, "-version")
	if err != nil {
		log.Infoln("")
		return errors.New("Failed to get version")
	}

	// version check
	isVersionOk, err := bitrise.IsVersionGreaterOrEqual(verStr, minVersion)
	if err != nil {
		log.Error("Failed to validate installed version")
		return err
	}
	if !isVersionOk {
		log.Warn("Installed "+toolname+" found, but not a supported version: ", verStr)
		if !isInstall {
			return errors.New("Failed to install required version.")
		}
		log.Warn("Updating...")
		return doInstall()
	}

	log.Infoln(" * [OK] "+toolname+" :", progInstallPth)
	log.Infoln("        version :", verStr)
	return nil
}

// CheckIsEnvmanInstalled ...
func CheckIsEnvmanInstalled(minEnvmanVersion string) error {
	toolname := "envman"
	minVersion := minEnvmanVersion
	if err := checkIsBitriseToolInstalled(toolname, minVersion, true); err != nil {
		return err
	}
	return nil
}

// CheckIsStepmanInstalled ...
func CheckIsStepmanInstalled(minStepmanVersion string) error {
	toolname := "stepman"
	minVersion := minStepmanVersion
	if err := checkIsBitriseToolInstalled(toolname, minVersion, true); err != nil {
		return err
	}
	return nil
}

// InstallWithBrewIfNeeded ...
func InstallWithBrewIfNeeded(tool string) error {
	if err := CheckIsHomebrewInstalled(); err != nil {
		return err
	}
	if _, err := CheckProgramInstalledPath(tool); err != nil {
		args := []string{"install", tool}
		if err := bitrise.RunCommand("brew", args...); err != nil {
			return err
		}
	}
	return nil
}

// InstallWithRubyGemsIfNeeded ...
func InstallWithRubyGemsIfNeeded(gemName string) error {
	if err := CheckIsRubyGemsInstalled(); err != nil {
		return err
	}
	if _, err := CheckProgramInstalledPath(gemName); err != nil {
		args := []string{"install", gemName}
		if err := bitrise.RunCommand("gem", args...); err != nil {
			return err
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/ethereum/eth-go"
	"github.com/ethereum/eth-go/ethchain"
	"github.com/ethereum/eth-go/ethutil"
	"github.com/ethereum/eth-go/ethwire"
	"github.com/ethereum/go-ethereum/ui"
	"github.com/niemeyer/qml"
	"github.com/obscuren/secp256k1-go"
	"log"
	"os"
	"os/signal"
	"runtime"
)

const Debug = true

// Register interrupt handlers so we can stop the ethereum
func RegisterInterupts(s *eth.Ethereum) {
	// Buffered chan of one is enough
	c := make(chan os.Signal, 1)
	// Notify about interrupts for now
	signal.Notify(c, os.Interrupt)
	go func() {
		for sig := range c {
			fmt.Printf("Shutting down (%v) ... \n", sig)

			s.Stop()
		}
	}()
}

func CreateKeyPair(force bool) {
	data, _ := ethutil.Config.Db.Get([]byte("KeyRing"))
	if len(data) == 0 || force {
		pub, prv := secp256k1.GenerateKeyPair()
		addr := ethutil.Sha3Bin(pub[1:])[12:]

		fmt.Printf(`
Generating new address and keypair.
Please keep your keys somewhere save.

++++++++++++++++ KeyRing +++++++++++++++++++
addr: %x
prvk: %x
pubk: %x
++++++++++++++++++++++++++++++++++++++++++++

`, addr, prv, pub)

		keyRing := ethutil.NewValue([]interface{}{prv, addr, pub[1:]})
		ethutil.Config.Db.Put([]byte("KeyRing"), keyRing.Encode())
	}
}

func ImportPrivateKey(prvKey string) {
	key := ethutil.FromHex(prvKey)
	msg := []byte("tmp")
	// Couldn't think of a better way to get the pub key
	sig, _ := secp256k1.Sign(msg, key)
	pub, _ := secp256k1.RecoverPubkey(msg, sig)
	addr := ethutil.Sha3Bin(pub[1:])[12:]

	fmt.Printf(`
Importing private key

++++++++++++++++ KeyRing +++++++++++++++++++
addr: %x
prvk: %x
pubk: %x
++++++++++++++++++++++++++++++++++++++++++++

`, addr, key, pub)

	keyRing := ethutil.NewValue([]interface{}{key, addr, pub[1:]})
	ethutil.Config.Db.Put([]byte("KeyRing"), keyRing.Encode())
}

func main() {
	Init()

	// Qt has to be initialized in the main thread or it will throw errors
	// It has to be called BEFORE setting the maximum procs.
	if UseGui {
		qml.Init(nil)
	}

	runtime.GOMAXPROCS(runtime.NumCPU())

	ethchain.InitFees()
	ethutil.ReadConfig(DataDir)
	ethutil.Config.Seed = UseSeed

	// Instantiated a eth stack
	ethereum, err := eth.New(eth.CapDefault, UseUPnP)
	ethereum.Port = OutboundPort
	if err != nil {
		log.Println("eth start err:", err)
		return
	}

	if GenAddr {
		fmt.Println("This action overwrites your old private key. Are you sure? (y/n)")

		var r string
		fmt.Scanln(&r)
		for ; ; fmt.Scanln(&r) {
			if r == "n" || r == "y" {
				break
			} else {
				fmt.Printf("Yes or no?", r)
			}
		}

		if r == "y" {
			CreateKeyPair(true)
		}
		os.Exit(0)
	} else {
		if len(ImportKey) > 0 {
			fmt.Println("This action overwrites your old private key. Are you sure? (y/n)")
			var r string
			fmt.Scanln(&r)
			for ; ; fmt.Scanln(&r) {
				if r == "n" || r == "y" {
					break
				} else {
					fmt.Printf("Yes or no?", r)
				}
			}

			if r == "y" {
				ImportPrivateKey(ImportKey)
			}
		} else {
			CreateKeyPair(false)
		}
	}

	if ExportKey {
		data, _ := ethutil.Config.Db.Get([]byte("KeyRing"))
		keyRing := ethutil.NewValueFromBytes(data)
		fmt.Printf("%x\n", keyRing.Get(0).Bytes())
		os.Exit(0)
	}

	if ShowGenesis {
		fmt.Println(ethereum.BlockManager.BlockChain().Genesis())
		os.Exit(0)
	}

	log.Printf("Starting Ethereum v%s\n", ethutil.Config.Ver)

	// Set the max peers
	ethereum.MaxPeers = MaxPeer

	if StartConsole {
		err := os.Mkdir(ethutil.Config.ExecPath, os.ModePerm)
		// Error is OK if the error is ErrExist
		if err != nil && !os.IsExist(err) {
			log.Panic("Unable to create EXECPATH:", err)
		}

		console := NewConsole(ethereum)
		go console.Start()
	}

	if UseGui {
		gui := ethui.New(ethereum)
		gui.Start()
		//ethereum.Stop()
	} else {
		RegisterInterupts(ethereum)
		ethereum.Start()

		if StartMining {
			log.Printf("Miner started\n")

			// Fake block mining. It broadcasts a new block every 5 seconds
			go func() {
				pow := &ethchain.EasyPow{}
				data, _ := ethutil.Config.Db.Get([]byte("KeyRing"))
				keyRing := ethutil.NewValueFromBytes(data)
				addr := keyRing.Get(1).Bytes()

				for {
					txs := ethereum.TxPool.Flush()
					// Create a new block which we're going to mine
					block := ethereum.BlockManager.BlockChain().NewBlock(addr, txs)
					// Apply all transactions to the block
					ethereum.BlockManager.ApplyTransactions(block, block.Transactions())

					ethereum.BlockManager.AccumelateRewards(block, block)

					// Search the nonce
					block.Nonce = pow.Search(block)
					ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{block.Value().Val})
					err := ethereum.BlockManager.ProcessBlock(block)
					if err != nil {
						log.Println(err)
					} else {
						log.Println("\n+++++++ MINED BLK +++++++\n", ethereum.BlockManager.BlockChain().CurrentBlock)
					}
				}
			}()
		}

		// Wait for shutdown
		ethereum.WaitForShutdown()
	}
}
<commit_msg>Exit after importing a key<commit_after>package main

import (
	"fmt"
	"github.com/ethereum/eth-go"
	"github.com/ethereum/eth-go/ethchain"
	"github.com/ethereum/eth-go/ethutil"
	"github.com/ethereum/eth-go/ethwire"
	"github.com/ethereum/go-ethereum/ui"
	"github.com/niemeyer/qml"
	"github.com/obscuren/secp256k1-go"
	"log"
	"os"
	"os/signal"
	"runtime"
)

const Debug = true

// Register interrupt handlers so we can stop the ethereum
func RegisterInterupts(s *eth.Ethereum) {
	// Buffered chan of one is enough
	c := make(chan os.Signal, 1)
	// Notify about interrupts for now
	signal.Notify(c, os.Interrupt)
	go func() {
		for sig := range c {
			fmt.Printf("Shutting down (%v) ... \n", sig)

			s.Stop()
		}
	}()
}

func CreateKeyPair(force bool) {
	data, _ := ethutil.Config.Db.Get([]byte("KeyRing"))
	if len(data) == 0 || force {
		pub, prv := secp256k1.GenerateKeyPair()
		pair := &ethutil.Key{PrivateKey: prv, PublicKey: pub}
		ethutil.Config.Db.Put([]byte("KeyRing"), pair.RlpEncode())

		fmt.Printf(`
Generating new address and keypair.
Please keep your keys somewhere save.

++++++++++++++++ KeyRing +++++++++++++++++++
addr: %x
prvk: %x
pubk: %x
++++++++++++++++++++++++++++++++++++++++++++

`, pair.Address(), prv, pub)

	}
}

func ImportPrivateKey(prvKey string) {
	key := ethutil.FromHex(prvKey)
	msg := []byte("tmp")
	// Couldn't think of a better way to get the pub key
	sig, _ := secp256k1.Sign(msg, key)
	pub, _ := secp256k1.RecoverPubkey(msg, sig)
	pair := &ethutil.Key{PrivateKey: key, PublicKey: pub}
	ethutil.Config.Db.Put([]byte("KeyRing"), pair.RlpEncode())

	fmt.Printf(`
Importing private key

++++++++++++++++ KeyRing +++++++++++++++++++
addr: %x
prvk: %x
pubk: %x
++++++++++++++++++++++++++++++++++++++++++++

`, pair.Address(), key, pub)
}

func main() {
	Init()

	// Qt has to be initialized in the main thread or it will throw errors
	// It has to be called BEFORE setting the maximum procs.
	if UseGui {
		qml.Init(nil)
	}

	runtime.GOMAXPROCS(runtime.NumCPU())

	ethchain.InitFees()
	ethutil.ReadConfig(DataDir)
	ethutil.Config.Seed = UseSeed

	// Instantiated a eth stack
	ethereum, err := eth.New(eth.CapDefault, UseUPnP)
	if err != nil {
		log.Println("eth start err:", err)
		return
	}
	ethereum.Port = OutboundPort

	if GenAddr {
		fmt.Println("This action overwrites your old private key. Are you sure? (y/n)")

		var r string
		fmt.Scanln(&r)
		for ; ; fmt.Scanln(&r) {
			if r == "n" || r == "y" {
				break
			} else {
				fmt.Printf("Yes or no?", r)
			}
		}

		if r == "y" {
			CreateKeyPair(true)
		}
		os.Exit(0)
	} else {
		if len(ImportKey) > 0 {
			fmt.Println("This action overwrites your old private key. Are you sure? (y/n)")
			var r string
			fmt.Scanln(&r)
			for ; ; fmt.Scanln(&r) {
				if r == "n" || r == "y" {
					break
				} else {
					fmt.Printf("Yes or no?", r)
				}
			}

			if r == "y" {
				ImportPrivateKey(ImportKey)
				os.Exit(0)
			}
		} else {
			CreateKeyPair(false)
		}
	}

	if ExportKey {
		key := ethutil.Config.Db.GetKeys()[0]
		fmt.Printf("%x\n", key.PrivateKey)
		os.Exit(0)
	}

	if ShowGenesis {
		fmt.Println(ethereum.BlockManager.BlockChain().Genesis())
		os.Exit(0)
	}

	log.Printf("Starting Ethereum v%s\n", ethutil.Config.Ver)

	// Set the max peers
	ethereum.MaxPeers = MaxPeer

	if StartConsole {
		err := os.Mkdir(ethutil.Config.ExecPath, os.ModePerm)
		// Error is OK if the error is ErrExist
		if err != nil && !os.IsExist(err) {
			log.Panic("Unable to create EXECPATH:", err)
		}

		console := NewConsole(ethereum)
		go console.Start()
	}

	if UseGui {
		gui := ethui.New(ethereum)
		gui.Start()
		//ethereum.Stop()
	} else {
		RegisterInterupts(ethereum)
		ethereum.Start()

		if StartMining {
			log.Printf("Miner started\n")

			// Fake block mining. It broadcasts a new block every 5 seconds
			go func() {
				pow := &ethchain.EasyPow{}
				data, _ := ethutil.Config.Db.Get([]byte("KeyRing"))
				keyRing := ethutil.NewValueFromBytes(data)
				addr := keyRing.Get(1).Bytes()

				for {
					txs := ethereum.TxPool.Flush()
					// Create a new block which we're going to mine
					block := ethereum.BlockManager.BlockChain().NewBlock(addr, txs)
					// Apply all transactions to the block
					ethereum.BlockManager.ApplyTransactions(block, block.Transactions())

					ethereum.BlockManager.AccumelateRewards(block, block)

					// Search the nonce
					block.Nonce = pow.Search(block)
					ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{block.Value().Val})
					err := ethereum.BlockManager.ProcessBlock(block)
					if err != nil {
						log.Println(err)
					} else {
						log.Println("\n+++++++ MINED BLK +++++++\n", ethereum.BlockManager.BlockChain().CurrentBlock)
					}
				}
			}()
		}

		// Wait for shutdown
		ethereum.WaitForShutdown()
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"github.com/urfave/cli"
)

type EthernetState struct {
	Enabled bool      `json:"enabled"`
	Configg *Ethernet `json:"config"`
}

func EthernetCMD(ctx *cli.Context) error {
	if ctx.IsSet(enableFlag) {
		return EnableEthernet(ctx)
	}
	if ctx.IsSet(disableFlag) {
		return DisableEthernet(ctx)
	}
	if ctx.IsSet(removeFlag) {
		return RemoveEthernet(ctx)
	}
	if ctx.IsSet(configFlag) {
		return configEthernetCMD(ctx)
	}
	return nil
}

// Enable ethernet enables ethernet network in the host machine. This relies on
// systemd to be the init system of the host machine.
//
// If the config flag is set, ethernet will be configured before  enabling it.
// Ommit the config flag if  ethernet is already configured using this tool.
func EnableEthernet(ctx *cli.Context) error {
	if ctx.IsSet(configFlag) {
		err := configEthernetCMD(ctx)
		if err != nil {
			return err
		}
	}
	var i string
	if ctx.IsSet("interface") {
		i = ctx.String("interface")
	} else {
		i = ctx.Args().First()
	}
	e, err := ethernetState(i)
	if err != nil {
		return err
	}
	_, err = exec.Command("ip", "link", "set", "up", e.Configg.Interface).Output()
	if err != nil {
		return err
	}
	err = restartService("systemd-networkd")
	if err != nil {
		return err
	}
	e.Enabled = true
	data, err := json.Marshal(e)
	if err != nil {
		return err
	}
	return keepState(
		fmt.Sprintf(defaultEthernetConfig, i), data)
}

// gives the current state of the ethernet configuration. This will return an
// error if the system hast been configured yet.
//
// Configuration state files are written in $FCONF_CONFIGDIR directory.
func ethernetState(i string) (*EthernetState, error) {
	dir := os.Getenv("FCONF_CONFIGDIR")
	if dir == "" {
		dir = fconfConfigDir
	}
	b, err := ioutil.ReadFile(filepath.Join(dir,
		fmt.Sprintf(defaultEthernetConfig, i)))
	if err != nil {
		return nil, err
	}
	e := &EthernetState{}
	err = json.Unmarshal(b, e)
	if err != nil {
		return nil, err
	}
	if e.Configg == nil {
		return nil, ErrWrongStateFile
	}
	if e.Configg.Interface == "" {
		e.Configg.Interface = "eth0"
	}
	return e, nil
}

func configEthernetCMD(ctx *cli.Context) error {
	base := ctx.String("dir")
	name := ctx.String("name")
	src := ctx.String("config")
	if src == "" {
		return errors.New("fconf: missing configuration source file")
	}
	var b []byte
	var err error
	if src == "stdin" {
		b, err = ReadFromStdin()
		if err != nil {
			return err
		}
	} else {
		b, err = ioutil.ReadFile(src)
		if err != nil {
			return err
		}
	}
	e := Ethernet{}
	err = json.Unmarshal(b, &e)
	if err != nil {
		return err
	}
	err = checkDir(base)
	if err != nil {
		return err
	}
	if e.Interface == "" {
		e.Interface = "eth0"
	}
	if strings.Contains(name, "%s") {
		name = fmt.Sprintf(name, e.Interface)
	}
	filename := filepath.Join(base, name)
	err = CreateSystemdFile(e, filename, 0644)
	if err != nil {
		return err
	}
	ctx.Set("interface", e.Interface)
	fmt.Printf("successful written ethernet configuration to %s \n", filename)
	state := &EthernetState{Configg: &e}
	b, _ = json.Marshal(state)
	return keepState(
		fmt.Sprintf(defaultEthernetConfig, e.Interface), b)
}

func keepState(filename string, src []byte) error {
	dir := os.Getenv("FCONF_CONFIGDIR")
	if dir == "" {
		dir = fconfConfigDir
	}
	err := checkDir(dir)
	if err != nil {
		return err
	}
	return ioutil.WriteFile(filepath.Join(dir, filename), src, 0644)
}

//DisableEthernet disables ethernet temporaly.
func DisableEthernet(ctx *cli.Context) error {
	var i string
	if ctx.IsSet("interface") {
		i = ctx.String("interface")
	} else {
		i = ctx.Args().First()
	}
	if i == "" {
		return errors.New("missing interface, you must specify interface")
	}
	ctx.Set("interface", i)
	e, err := ethernetState(i)
	if err != nil {
		return err
	}
	_, err = exec.Command("ip", "link", "set", "down", "dev", e.Configg.Interface).Output()
	if err != nil {
		return err
	}
	fmt.Println("successfully disabled ethernet")
	//e.Enabled = false
	data, err := json.Marshal(e)
	if err != nil {
		return err
	}
	return keepState(
		fmt.Sprintf(defaultEthernetConfig, i), data)
}

//RemoveEthernet removes ethernet service.
func RemoveEthernet(ctx *cli.Context) error {
	err := DisableEthernet(ctx)
	if err != nil {
		return err
	}
	var i string
	if ctx.IsSet("interface") {
		i = ctx.String("interface")
	} else {
		i = ctx.Args().First()
	}
	if i == "" {
		return errors.New("missing interface, you must specify interface")
	}
	e, err := ethernetState(i)
	if err != nil {
		return err
	}
	// removestate file
	stateFile := filepath.Join(stateDir(),
		fmt.Sprintf(defaultEthernetConfig, i))
	err = removeFile(stateFile)
	if err != nil {
		return err
	}
	// remove systemd file
	unit := filepath.Join(networkBase, ethernetService)
	err = removeFile(unit)
	if err != nil {
		return err
	}
	if err != nil {
		return err
	}

	// Flush settings for the interface
	err = FlushInterface(e.Configg.Interface)
	if err != nil {
		return err
	}

	// reload systemd-networkd
	return restartService("systemd-networkd")
}

func removeFile(name string) error {
	fmt.Printf("removing %s ...", name)
	err := os.Remove(name)
	if err != nil {
		fmt.Println(" error")
		return err
	}
	fmt.Println(" done without error")
	return nil
}

func stateDir() string {
	dir := os.Getenv("FCONF_CONFIGDIR")
	if dir == "" {
		dir = fconfConfigDir
	}
	return dir
}
<commit_msg>Ethernet: Fix getting interface<commit_after>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"github.com/urfave/cli"
)

type EthernetState struct {
	Enabled bool      `json:"enabled"`
	Configg *Ethernet `json:"config"`
}

func EthernetCMD(ctx *cli.Context) error {
	if ctx.IsSet(enableFlag) {
		return EnableEthernet(ctx)
	}
	if ctx.IsSet(disableFlag) {
		return DisableEthernet(ctx)
	}
	if ctx.IsSet(removeFlag) {
		return RemoveEthernet(ctx)
	}
	if ctx.IsSet(configFlag) {
		return configEthernetCMD(ctx)
	}
	return nil
}

// Enable ethernet enables ethernet network in the host machine. This relies on
// systemd to be the init system of the host machine.
//
// If the config flag is set, ethernet will be configured before  enabling it.
// Ommit the config flag if  ethernet is already configured using this tool.
func EnableEthernet(ctx *cli.Context) error {
	if ctx.IsSet(configFlag) {
		err := configEthernetCMD(ctx)
		if err != nil {
			return err
		}
	}
	var i string
	if ctx.IsSet("interface") {
		i = ctx.String("interface")
	} else {
		i = ctx.Args().First()
	}
	e, err := ethernetState(i)
	if err != nil {
		return err
	}
	_, err = exec.Command("ip", "link", "set", "up", e.Configg.Interface).Output()
	if err != nil {
		return err
	}
	err = restartService("systemd-networkd")
	if err != nil {
		return err
	}
	e.Enabled = true
	data, err := json.Marshal(e)
	if err != nil {
		return err
	}
	return keepState(
		fmt.Sprintf(defaultEthernetConfig, i), data)
}

// gives the current state of the ethernet configuration. This will return an
// error if the system hast been configured yet.
//
// Configuration state files are written in $FCONF_CONFIGDIR directory.
func ethernetState(i string) (*EthernetState, error) {
	dir := os.Getenv("FCONF_CONFIGDIR")
	if dir == "" {
		dir = fconfConfigDir
	}
	b, err := ioutil.ReadFile(filepath.Join(dir,
		fmt.Sprintf(defaultEthernetConfig, i)))
	if err != nil {
		return nil, err
	}
	e := &EthernetState{}
	err = json.Unmarshal(b, e)
	if err != nil {
		return nil, err
	}
	if e.Configg == nil {
		return nil, ErrWrongStateFile
	}
	if e.Configg.Interface == "" {
		e.Configg.Interface = "eth0"
	}
	return e, nil
}

func configEthernetCMD(ctx *cli.Context) error {
	base := ctx.String("dir")
	name := ctx.String("name")
	src := ctx.String("config")
	if src == "" {
		return errors.New("fconf: missing configuration source file")
	}
	var b []byte
	var err error
	if src == "stdin" {
		b, err = ReadFromStdin()
		if err != nil {
			return err
		}
	} else {
		b, err = ioutil.ReadFile(src)
		if err != nil {
			return err
		}
	}
	e := Ethernet{}
	err = json.Unmarshal(b, &e)
	if err != nil {
		return err
	}
	err = checkDir(base)
	if err != nil {
		return err
	}
	if e.Interface == "" {
		e.Interface = "eth0"
	}
	if strings.Contains(name, "%s") {
		name = fmt.Sprintf(name, e.Interface)
	}
	filename := filepath.Join(base, name)
	err = CreateSystemdFile(e, filename, 0644)
	if err != nil {
		return err
	}
	ctx.GlobalSet("interface", e.Interface)
	fmt.Printf("successful written ethernet configuration to %s \n", filename)
	state := &EthernetState{Configg: &e}
	b, _ = json.Marshal(state)
	return keepState(
		fmt.Sprintf(defaultEthernetConfig, e.Interface), b)
}

func keepState(filename string, src []byte) error {
	dir := os.Getenv("FCONF_CONFIGDIR")
	if dir == "" {
		dir = fconfConfigDir
	}
	err := checkDir(dir)
	if err != nil {
		return err
	}
	return ioutil.WriteFile(filepath.Join(dir, filename), src, 0644)
}

//DisableEthernet disables ethernet temporaly.
func DisableEthernet(ctx *cli.Context) error {
	i := getInterface(ctx)
	if i == "" {
		return errors.New("missing interface, you must specify interface")
	}
	ctx.Set("interface", i)
	e, err := ethernetState(i)
	if err != nil {
		return err
	}
	_, err = exec.Command("ip", "link", "set", "down", "dev", e.Configg.Interface).Output()
	if err != nil {
		return err
	}
	fmt.Println("successfully disabled ethernet")
	//e.Enabled = false
	data, err := json.Marshal(e)
	if err != nil {
		return err
	}
	return keepState(
		fmt.Sprintf(defaultEthernetConfig, i), data)
}

//RemoveEthernet removes ethernet service.
func RemoveEthernet(ctx *cli.Context) error {
	err := DisableEthernet(ctx)
	if err != nil {
		return err
	}
	i := getInterface(ctx)
	if i == "" {
		return errors.New("missing interface, you must specify interface")
	}
	e, err := ethernetState(i)
	if err != nil {
		return err
	}
	// removestate file
	stateFile := filepath.Join(stateDir(),
		fmt.Sprintf(defaultEthernetConfig, i))
	err = removeFile(stateFile)
	if err != nil {
		return err
	}
	// remove systemd file
	unit := filepath.Join(networkBase, ethernetService)
	err = removeFile(unit)
	if err != nil {
		return err
	}
	if err != nil {
		return err
	}

	// Flush settings for the interface
	err = FlushInterface(e.Configg.Interface)
	if err != nil {
		return err
	}

	// reload systemd-networkd
	return restartService("systemd-networkd")
}

func removeFile(name string) error {
	fmt.Printf("removing %s ...", name)
	err := os.Remove(name)
	if err != nil {
		fmt.Println(" error")
		return err
	}
	fmt.Println(" done without error")
	return nil
}

func stateDir() string {
	dir := os.Getenv("FCONF_CONFIGDIR")
	if dir == "" {
		dir = fconfConfigDir
	}
	return dir
}
<|endoftext|>


<commit_before>package eval

import (
	"fmt"
	"github.com/suzuken/gs/types"
	"sync"
)

// Frame is symbol to Expression map
type Frame map[types.Symbol]types.Expression

// Env is scheme environment for evaluation
type Env struct {
	sync.RWMutex
	m      Frame // m is symbol table for expression
	parent *Env  // parent is parent Environment. Env is nested.
}

// NewEnv creates new environment
func NewEnv() *Env {
	symbols := make(Frame) // TODO: more flexible stack size control
	return &Env{m: symbols, parent: nil}
}

// Extend extends environments by given variables and values.
func (e *Env) Extend(frame Frame) {
	for s, exp := range frame {
		e.Put(s, exp)
	}
}

// Setup returns initial environment for evaluation.
func (e *Env) Setup() {
	e.Extend(NewPrimitiveProcedureFrame())
}

// NewPrimitiveProcedureFrame returns frame of primitive procedures.
// GS provides functionality of base scheme procedure.
func NewPrimitiveProcedureFrame() Frame {
	return Frame{
		"car":   Car,
		"cdr":   Cdr,
		"cons":  Cons,
		"print": Print,
		"+":     Add,
		"-":     Subtract,
		"*":     Multiply,
		"/":     Divide,
		">":     GreaterThan,
		"<":     LessThan,
		"eq?":   IsEqual,
		"null?": IsNull,
		"list":  List,
	}
}

// Car is implementation of car
func Car(args ...types.Expression) (types.Expression, error) {
	return args[0], nil
}

func Cdr(args ...types.Expression) (types.Expression, error) {
	return args[1:], nil
}

func Cons(args ...types.Expression) (types.Expression, error) {
	return types.Pair{args[0], args[1]}, nil
}

func Print(args ...types.Expression) (types.Expression, error) {
	fmt.Print(args)
	return nil, nil
}

func Add(args ...types.Expression) (types.Expression, error) {
	sum, ok := args[0].(types.Number)
	if !ok {
		return nil, fmt.Errorf("given args is not number: %#v", args[0])
	}
	for _, adder := range args[1:] {
		sum = sum + adder.(types.Number)
	}
	return sum, nil
}

func Subtract(args ...types.Expression) (types.Expression, error) {
	sub, ok := args[0].(types.Number)
	if !ok {
		return nil, fmt.Errorf("given args is not number: %v", args[0])
	}
	for _, s := range args[1:] {
		sub = sub - s.(types.Number)
	}
	return sub, nil
}

func Multiply(args ...types.Expression) (types.Expression, error) {
	mul, ok := args[0].(types.Number)
	if !ok {
		return nil, fmt.Errorf("given args is not number: %v", args[0])
	}
	for _, m := range args[1:] {
		mul = mul * m.(types.Number)
	}
	return mul, nil
}

func Divide(args ...types.Expression) (types.Expression, error) {
	div, ok := args[0].(types.Number)
	if !ok {
		return nil, fmt.Errorf("given args is not number: %v", args[0])
	}
	for _, d := range args[1:] {
		div = div / d.(types.Number)
	}
	return div, nil
}

func GreaterThan(args ...types.Expression) (types.Expression, error) {
	return types.Boolean(args[0].(types.Number) > args[1].(types.Number)), nil
}

func LessThan(args ...types.Expression) (types.Expression, error) {
	return types.Boolean(args[0].(types.Number) < args[1].(types.Number)), nil
}

func IsEqual(args ...types.Expression) (types.Expression, error) {
	return types.Boolean(args[0] == args[1]), nil
}

func IsNull(args ...types.Expression) (types.Expression, error) {
	return types.Boolean(args[0] == nil), nil
}

func List(args ...types.Expression) (types.Expression, error) {
	return args, nil
}

// Put creates new symbol to table
func (e *Env) Put(s types.Symbol, exp types.Expression) {
	e.Lock()
	defer e.Unlock()
	e.m[s] = exp
}

// Get fetch expression by symbol from environment
func (e *Env) Get(s types.Symbol) (types.Expression, error) {
	e.RLock()
	defer e.RUnlock()
	v, ok := e.m[s]
	if !ok {
		// or return nil?
		return nil, fmt.Errorf("symbol not found from the environment: symbol %s", s)
	}
	return v, nil
}

// Remove symbol from environment
func (e *Env) Remove(s types.Symbol) {
	e.Lock()
	defer e.Unlock()
	delete(e.m, s)
}

// Lambda is definition of lambda
type Lambda struct {
	// Args are temporary parameters
	Args types.Expression
	// Body is expression to evalute
	Body types.Expression
	// Env is environent for evaluate this lambda function
	Env *Env
}
<commit_msg>newline by print<commit_after>package eval

import (
	"fmt"
	"github.com/suzuken/gs/types"
	"sync"
)

// Frame is symbol to Expression map
type Frame map[types.Symbol]types.Expression

// Env is scheme environment for evaluation
type Env struct {
	sync.RWMutex
	m      Frame // m is symbol table for expression
	parent *Env  // parent is parent Environment. Env is nested.
}

// NewEnv creates new environment
func NewEnv() *Env {
	symbols := make(Frame) // TODO: more flexible stack size control
	return &Env{m: symbols, parent: nil}
}

// Extend extends environments by given variables and values.
func (e *Env) Extend(frame Frame) {
	for s, exp := range frame {
		e.Put(s, exp)
	}
}

// Setup returns initial environment for evaluation.
func (e *Env) Setup() {
	e.Extend(NewPrimitiveProcedureFrame())
}

// NewPrimitiveProcedureFrame returns frame of primitive procedures.
// GS provides functionality of base scheme procedure.
func NewPrimitiveProcedureFrame() Frame {
	return Frame{
		"car":   Car,
		"cdr":   Cdr,
		"cons":  Cons,
		"print": Print,
		"+":     Add,
		"-":     Subtract,
		"*":     Multiply,
		"/":     Divide,
		">":     GreaterThan,
		"<":     LessThan,
		"eq?":   IsEqual,
		"null?": IsNull,
		"list":  List,
	}
}

// Car is implementation of car
func Car(args ...types.Expression) (types.Expression, error) {
	return args[0], nil
}

func Cdr(args ...types.Expression) (types.Expression, error) {
	return args[1:], nil
}

func Cons(args ...types.Expression) (types.Expression, error) {
	return types.Pair{args[0], args[1]}, nil
}

func Print(args ...types.Expression) (types.Expression, error) {
	if len(args) == 1 {
		fmt.Println(args[0])
	} else {
		fmt.Println(args)
	}
	return nil, nil
}

func Add(args ...types.Expression) (types.Expression, error) {
	sum, ok := args[0].(types.Number)
	if !ok {
		return nil, fmt.Errorf("given args is not number: %#v", args[0])
	}
	for _, adder := range args[1:] {
		sum = sum + adder.(types.Number)
	}
	return sum, nil
}

func Subtract(args ...types.Expression) (types.Expression, error) {
	sub, ok := args[0].(types.Number)
	if !ok {
		return nil, fmt.Errorf("given args is not number: %v", args[0])
	}
	for _, s := range args[1:] {
		sub = sub - s.(types.Number)
	}
	return sub, nil
}

func Multiply(args ...types.Expression) (types.Expression, error) {
	mul, ok := args[0].(types.Number)
	if !ok {
		return nil, fmt.Errorf("given args is not number: %v", args[0])
	}
	for _, m := range args[1:] {
		mul = mul * m.(types.Number)
	}
	return mul, nil
}

func Divide(args ...types.Expression) (types.Expression, error) {
	div, ok := args[0].(types.Number)
	if !ok {
		return nil, fmt.Errorf("given args is not number: %v", args[0])
	}
	for _, d := range args[1:] {
		div = div / d.(types.Number)
	}
	return div, nil
}

func GreaterThan(args ...types.Expression) (types.Expression, error) {
	return types.Boolean(args[0].(types.Number) > args[1].(types.Number)), nil
}

func LessThan(args ...types.Expression) (types.Expression, error) {
	return types.Boolean(args[0].(types.Number) < args[1].(types.Number)), nil
}

func IsEqual(args ...types.Expression) (types.Expression, error) {
	return types.Boolean(args[0] == args[1]), nil
}

func IsNull(args ...types.Expression) (types.Expression, error) {
	return types.Boolean(args[0] == nil), nil
}

func List(args ...types.Expression) (types.Expression, error) {
	return args, nil
}

// Put creates new symbol to table
func (e *Env) Put(s types.Symbol, exp types.Expression) {
	e.Lock()
	defer e.Unlock()
	e.m[s] = exp
}

// Get fetch expression by symbol from environment
func (e *Env) Get(s types.Symbol) (types.Expression, error) {
	e.RLock()
	defer e.RUnlock()
	v, ok := e.m[s]
	if !ok {
		// or return nil?
		return nil, fmt.Errorf("symbol not found from the environment: symbol %s", s)
	}
	return v, nil
}

// Remove symbol from environment
func (e *Env) Remove(s types.Symbol) {
	e.Lock()
	defer e.Unlock()
	delete(e.m, s)
}

// Lambda is definition of lambda
type Lambda struct {
	// Args are temporary parameters
	Args types.Expression
	// Body is expression to evalute
	Body types.Expression
	// Env is environent for evaluate this lambda function
	Env *Env
}
<|endoftext|>


<commit_before>package clicommand

import (
	"fmt"
	"net/http"
	"os"
	"time"

	"github.com/buildkite/agent/v3/api"
	"github.com/buildkite/agent/v3/cliconfig"
	"github.com/buildkite/roko"
	"github.com/urfave/cli"
)

type OIDCTokenConfig struct {
	Audience string `cli:"audience"`
	Lifetime int    `cli:"lifetime"`
	Job      string `cli:"job"      validate:"required"`

	// Global flags
	Debug       bool     `cli:"debug"`
	LogLevel    string   `cli:"log-level"`
	NoColor     bool     `cli:"no-color"`
	Experiments []string `cli:"experiment" normalize:"list"`
	Profile     string   `cli:"profile"`

	// API config
	DebugHTTP        bool   `cli:"debug-http"`
	AgentAccessToken string `cli:"agent-access-token" validate:"required"`
	Endpoint         string `cli:"endpoint"           validate:"required"`
	NoHTTP2          bool   `cli:"no-http2"`
}

const (
	oidcTokenDescription = `Usage:

   buildkite-agent oidc request-token [options...]

Description:
   Requests and prints an OIDC token from Buildkite that claims the Job ID
   (amongst other things) and the specified audience. If no audience is
   specified, the endpoint's default audience will be claimed.

Example:
   $ buildkite-agent oidc request-token --audience sts.amazonaws.com

   Requests and prints an OIDC token from Buildkite that claims the Job ID
   (amongst other things) and the audience "sts.amazonaws.com".
`
	backoffSeconds = 2
	maxAttempts    = 5
)

var OIDCRequestTokenCommand = cli.Command{
	Name:        "request-token",
	Usage:       "Requests and prints an OIDC token from Buildkite with the specified audience,",
	Description: oidcTokenDescription,
	Flags: []cli.Flag{
		cli.StringFlag{
			Name:  "audience",
			Usage: "The audience that will consume the OIDC token. The API will supply a default audience if it is ommited.",
		},
		cli.IntFlag{
			Name:  "lifetime",
			Value: 0,
			Usage: "The time (in seconds) the OIDC token will be valid for before expiry. Must be a non-negative integer. Ommitting this flag or specifying 0 will result the in the API substituting its default value and NOT a non-expriing token.",
		},
		cli.StringFlag{
			Name:   "job",
			Value:  "",
			Usage:  "Buildkite Job Id to claim in the OIDC token",
			EnvVar: "BUILDKITE_JOB_ID",
		},

		// API Flags
		AgentAccessTokenFlag,
		EndpointFlag,
		NoHTTP2Flag,
		DebugHTTPFlag,

		// Global flags
		NoColorFlag,
		DebugFlag,
		LogLevelFlag,
		ExperimentsFlag,
		ProfileFlag,
	},
	Action: func(c *cli.Context) error {
		// The configuration will be loaded into this struct
		cfg := OIDCTokenConfig{}

		loader := cliconfig.Loader{CLI: c, Config: &cfg}
		warnings, err := loader.Load()
		if err != nil {
			fmt.Fprintf(c.App.ErrWriter, "%s\n", err)
			os.Exit(1)
		}

		l := CreateLogger(&cfg)

		// Now that we have a logger, log out the warnings that loading config generated
		for _, warning := range warnings {
			l.Warn("%s", warning)
		}

		// Setup any global configuration options
		done := HandleGlobalFlags(l, cfg)
		defer done()

		// Create the API client
		client := api.NewClient(l, loadAPIClientConfig(cfg, "AgentAccessToken"))

		// Request the token
		var token *api.OIDCToken

		if err := roko.NewRetrier(
			roko.WithMaxAttempts(maxAttempts),
			roko.WithStrategy(roko.Exponential(backoffSeconds*time.Second, 0)),
		).Do(func(r *roko.Retrier) error {
			req := &api.OIDCTokenRequest{
				Job:      cfg.Job,
				Audience: cfg.Audience,
				Lifetime: cfg.Lifetime,
			}

			var resp *api.Response
			token, resp, err = client.OIDCToken(req)
			if resp != nil {
				switch resp.StatusCode {
				// Don't bother retrying if the response was one of these statuses
				case http.StatusBadRequest, http.StatusUnauthorized, http.StatusForbidden, http.StatusUnprocessableEntity:
					r.Break()
					return err
				}
			}

			if err != nil {
				l.Warn("%s (%s)", err, r)
			}

			return err
		}); err != nil {
			if len(cfg.Audience) > 0 {
				l.Error("Could not obtain OIDC token for audience %s", cfg.Audience)
			} else {
				l.Error("Could not obtain OIDC token for default audience")
			}
			return err
		}

		fmt.Println(token.Token)
		return nil
	},
}
<commit_msg>Add fatal error if lifetime is negative<commit_after>package clicommand

import (
	"fmt"
	"net/http"
	"os"
	"time"

	"github.com/buildkite/agent/v3/api"
	"github.com/buildkite/agent/v3/cliconfig"
	"github.com/buildkite/roko"
	"github.com/urfave/cli"
)

type OIDCTokenConfig struct {
	Audience string `cli:"audience"`
	Lifetime int    `cli:"lifetime"`
	Job      string `cli:"job"      validate:"required"`

	// Global flags
	Debug       bool     `cli:"debug"`
	LogLevel    string   `cli:"log-level"`
	NoColor     bool     `cli:"no-color"`
	Experiments []string `cli:"experiment" normalize:"list"`
	Profile     string   `cli:"profile"`

	// API config
	DebugHTTP        bool   `cli:"debug-http"`
	AgentAccessToken string `cli:"agent-access-token" validate:"required"`
	Endpoint         string `cli:"endpoint"           validate:"required"`
	NoHTTP2          bool   `cli:"no-http2"`
}

const (
	oidcTokenDescription = `Usage:

   buildkite-agent oidc request-token [options...]

Description:
   Requests and prints an OIDC token from Buildkite that claims the Job ID
   (amongst other things) and the specified audience. If no audience is
   specified, the endpoint's default audience will be claimed.

Example:
   $ buildkite-agent oidc request-token --audience sts.amazonaws.com

   Requests and prints an OIDC token from Buildkite that claims the Job ID
   (amongst other things) and the audience "sts.amazonaws.com".
`
	backoffSeconds = 2
	maxAttempts    = 5
)

var OIDCRequestTokenCommand = cli.Command{
	Name:        "request-token",
	Usage:       "Requests and prints an OIDC token from Buildkite with the specified audience,",
	Description: oidcTokenDescription,
	Flags: []cli.Flag{
		cli.StringFlag{
			Name:  "audience",
			Usage: "The audience that will consume the OIDC token. The API will supply a default audience if it is ommited.",
		},
		cli.IntFlag{
			Name:  "lifetime",
			Value: 0,
			Usage: "The time (in seconds) the OIDC token will be valid for before expiry. Must be a non-negative integer. Ommitting this flag or specifying 0 will result the in the API substituting its default value and NOT a non-expriing token.",
		},
		cli.StringFlag{
			Name:   "job",
			Value:  "",
			Usage:  "Buildkite Job Id to claim in the OIDC token",
			EnvVar: "BUILDKITE_JOB_ID",
		},

		// API Flags
		AgentAccessTokenFlag,
		EndpointFlag,
		NoHTTP2Flag,
		DebugHTTPFlag,

		// Global flags
		NoColorFlag,
		DebugFlag,
		LogLevelFlag,
		ExperimentsFlag,
		ProfileFlag,
	},
	Action: func(c *cli.Context) error {
		// The configuration will be loaded into this struct
		cfg := OIDCTokenConfig{}

		loader := cliconfig.Loader{CLI: c, Config: &cfg}
		warnings, err := loader.Load()
		if err != nil {
			fmt.Fprintf(c.App.ErrWriter, "%s\n", err)
			os.Exit(1)
		}

		l := CreateLogger(&cfg)

		// Now that we have a logger, log out the warnings that loading config generated
		for _, warning := range warnings {
			l.Warn("%s", warning)
		}

		// Setup any global configuration options
		done := HandleGlobalFlags(l, cfg)
		defer done()

		// Note: if --lifetime is omitted, cfg.Lifetime = 0
		if cfg.Lifetime < 0 {
			l.Fatal("Lifetime %d must be a non-negative integer.", cfg.Lifetime)
		}

		// Create the API client
		client := api.NewClient(l, loadAPIClientConfig(cfg, "AgentAccessToken"))

		// Request the token
		var token *api.OIDCToken

		if err := roko.NewRetrier(
			roko.WithMaxAttempts(maxAttempts),
			roko.WithStrategy(roko.Exponential(backoffSeconds*time.Second, 0)),
		).Do(func(r *roko.Retrier) error {
			req := &api.OIDCTokenRequest{
				Job:      cfg.Job,
				Audience: cfg.Audience,
				Lifetime: cfg.Lifetime,
			}

			var resp *api.Response
			token, resp, err = client.OIDCToken(req)
			if resp != nil {
				switch resp.StatusCode {
				// Don't bother retrying if the response was one of these statuses
				case http.StatusBadRequest, http.StatusUnauthorized, http.StatusForbidden, http.StatusUnprocessableEntity:
					r.Break()
					return err
				}
			}

			if err != nil {
				l.Warn("%s (%s)", err, r)
			}

			return err
		}); err != nil {
			if len(cfg.Audience) > 0 {
				l.Error("Could not obtain OIDC token for audience %s", cfg.Audience)
			} else {
				l.Error("Could not obtain OIDC token for default audience")
			}
			return err
		}

		fmt.Println(token.Token)
		return nil
	},
}
<|endoftext|>


<commit_before>// Copyright 2015 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 registry

import (
	"crypto/rand"
	"encoding/base64"
	"fmt"
	"io"
	"strings"
	"time"

	"github.com/jacobsa/comeback/crypto"
	"github.com/jacobsa/gcloud/gcs"
	"golang.org/x/net/context"
)

// Create a registry that stores data in the supplied GCS bucket, deriving a
// crypto key from the supplied password and ensuring that the bucket may not
// in the future be used with any other key and has not in the past, either.
// Return a crypter configured to use the key.
func NewGCSRegistry(
	bucket gcs.Bucket,
	cryptoPassword string,
	deriver crypto.KeyDeriver) (r Registry, crypter crypto.Crypter, err error) {
	return newGCSRegistry(
		bucket,
		cryptoPassword,
		deriver,
		crypto.NewCrypter,
		rand.Reader)
}

const (
	gcsJobKeyPrefix      = "jobs/"
	gcsMetadataKey_Name  = "job_name"
	gcsMetadataKey_Score = "hex_score"

	// Constants related to the "marker" object, used to ensure that the user has
	// the right password. See notes on gcsRegistry.
	markerObjectName                = "marker"
	markerObjectMetadata_Salt       = "base64_salt"
	markerObjectMetadata_Ciphertext = "base64_ciphertext"
)

// A registry that stores job records in a GCS bucket. Object names are of the
// form
//
//     <gcsJobKeyPrefix><time>
//
// where <time> is a time.Time with UTC location formatted according to
// time.RFC3339Nano. Additional information is stored as object metadata fields
// keyed by the constants above. Metadata fields are used in preference to
// object content so that they are accessible on a ListObjects request.
//
// The bucket additionally contains a "marker" object (named by the constant
// markerObjectName) with metadata keys specifying a salt and a ciphertext for
// some random plaintext, generated ant written the first time the bucket is
// used. This marker allows us to verify that the user-provided crypto password
// is correct by deriving a key using the password and the salt and making sure
// that the ciphertext can be decrypted using that key.
type gcsRegistry struct {
	bucket gcs.Bucket
}

func (r *gcsRegistry) RecordBackup(j CompletedJob) (err error) {
	// Write an object to the bucket. On the small change that the time collides
	// (or we've done something dumb like use the zero time), use a generation
	// precondition to ensure we don't overwrite anything.
	var precond int64
	req := &gcs.CreateObjectRequest{
		Name:                   gcsJobKeyPrefix + j.StartTime.Format(time.RFC3339Nano),
		Contents:               strings.NewReader(""),
		GenerationPrecondition: &precond,

		Metadata: map[string]string{
			gcsMetadataKey_Name:  j.Name,
			gcsMetadataKey_Score: j.Score.Hex(),
		},
	}

	_, err = r.bucket.CreateObject(context.Background(), req)
	if err != nil {
		err = fmt.Errorf("CreateObject: %v", err)
		return
	}

	return
}

func (r *gcsRegistry) ListRecentBackups() (jobs []CompletedJob, err error) {
	err = fmt.Errorf("gcsRegistry.ListRecentBackups is not implemented.")
	return
}

func (r *gcsRegistry) FindBackup(
	startTime time.Time) (job CompletedJob, err error) {
	err = fmt.Errorf("gcsRegistry.FindBackup is not implemented.")
	return
}

// Like NewGCSRegistry, but with more injected.
func newGCSRegistry(
	bucket gcs.Bucket,
	cryptoPassword string,
	deriver crypto.KeyDeriver,
	createCrypter func(key []byte) (crypto.Crypter, error),
	cryptoRandSrc io.Reader) (r Registry, crypter crypto.Crypter, err error) {
	// Find the previously-written encrypted marker object, if any.
	statReq := &gcs.StatObjectRequest{Name: markerObjectName}
	o, err := bucket.StatObject(context.Background(), statReq)

	if _, ok := err.(*gcs.NotFoundError); ok {
		err = nil
		o = nil
	}

	if err != nil {
		err = fmt.Errorf("StatObject: %v", err)
		return
	}

	// If the object was found, we must verify it is compatible.
	if o != nil {
		crypter, err = verifyCompatibleAndSetUpCrypter(
			o,
			cryptoPassword,
			deriver,
			createCrypter,
		)

		if err != nil {
			return
		}

		// All is good.
		r = &gcsRegistry{
			bucket: bucket,
		}

		return
	}

	// Otherwise, we want to claim this bucket. Encrypt some random data, base64
	// encode it, then write it out. Make sure to use a precondition to defeat
	// the race condition where another machine is doing the same simultaneously.

	// Generate a random salt.
	salt := make([]byte, 8)
	if _, err = io.ReadAtLeast(cryptoRandSrc, salt, len(salt)); err != nil {
		err = fmt.Errorf("Reading random bytes for salt: %v", err)
		return
	}

	// Derive a crypto key and create the crypter.
	cryptoKey := deriver.DeriveKey(cryptoPassword, salt)
	crypter, err = createCrypter(cryptoKey)
	if err != nil {
		err = fmt.Errorf("createCrypter: %v", err)
		return
	}

	// Create some plaintext.
	plaintext := make([]byte, 8)
	_, err = io.ReadAtLeast(cryptoRandSrc, plaintext, len(plaintext))
	if err != nil {
		err = fmt.Errorf("Reading random bytes for plaintext: %v", err)
		return
	}

	// Encrypt the plaintext.
	ciphertext, err := crypter.Encrypt(plaintext)
	if err != nil {
		err = fmt.Errorf("Encrypt: %v", err)
		return
	}

	// Base-64 encode.
	encodedCiphertext := base64.StdEncoding.EncodeToString(ciphertext)
	encodedSalt := base64.StdEncoding.EncodeToString(salt)

	// Write out the marker object.
	var precond int64
	createReq := &gcs.CreateObjectRequest{
		Name: markerObjectName,
		Metadata: map[string]string{
			markerObjectMetadata_Salt:       encodedSalt,
			markerObjectMetadata_Ciphertext: encodedCiphertext,
		},
		Contents:               strings.NewReader(""),
		GenerationPrecondition: &precond,
	}

	_, err = bucket.CreateObject(context.Background(), createReq)
	if err != nil {
		err = fmt.Errorf("CreateObject: %v", err)
		return
	}

	// All is good.
	r = &gcsRegistry{
		bucket: bucket,
	}

	return
}

func verifyCompatibleAndSetUpCrypter(
	markerObject *gcs.Object,
	cryptoPassword string,
	deriver crypto.KeyDeriver,
	createCrypter func(key []byte) (crypto.Crypter, error)) (
	crypter crypto.Crypter,
	err error) {
	o := markerObject

	// Find the metadata keys.
	var passwordSaltBase64 string
	var ciphertextBase64 string
	var ok bool

	if passwordSaltBase64, ok = o.Metadata[markerObjectMetadata_Salt]; !ok {
		err = fmt.Errorf("Missing salt metadata key.")
		return
	}

	if ciphertextBase64, ok = o.Metadata[markerObjectMetadata_Ciphertext]; !ok {
		err = fmt.Errorf("Missing ciphertext metadata key.")
		return
	}

	// Base64-decode.
	passwordSalt, err := base64.StdEncoding.DecodeString(passwordSaltBase64)
	if err != nil {
		err = fmt.Errorf("Decoding password salt: %v", err)
		return
	}

	ciphertext, err := base64.StdEncoding.DecodeString(ciphertextBase64)
	if err != nil {
		err = fmt.Errorf("Decoding ciphertext: %v", err)
		return
	}

	// Derive a key and create a crypter.
	cryptoKey := deriver.DeriveKey(cryptoPassword, passwordSalt)
	if crypter, err = createCrypter(cryptoKey); err != nil {
		err = fmt.Errorf("createCrypter: %v", err)
		return
	}

	// Attempt to decrypt the ciphertext.
	if _, err = crypter.Decrypt(ciphertext); err != nil {
		// Special case: Did the crypter signal that the key was wrong?
		if _, ok := err.(*crypto.NotAuthenticError); ok {
			err = fmt.Errorf("The supplied password is incorrect.")
			return
		}

		// Generic error.
		err = fmt.Errorf("Decrypt: %v", err)
		return
	}

	return
}
<commit_msg>gcsRegistry.ListRecentBackups<commit_after>// Copyright 2015 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 registry

import (
	"crypto/rand"
	"encoding/base64"
	"fmt"
	"io"
	"strings"
	"time"

	"github.com/jacobsa/comeback/blob"
	"github.com/jacobsa/comeback/crypto"
	"github.com/jacobsa/gcloud/gcs"
	"github.com/jacobsa/gcloud/gcs/gcsutil"
	"golang.org/x/net/context"
)

// Create a registry that stores data in the supplied GCS bucket, deriving a
// crypto key from the supplied password and ensuring that the bucket may not
// in the future be used with any other key and has not in the past, either.
// Return a crypter configured to use the key.
func NewGCSRegistry(
	bucket gcs.Bucket,
	cryptoPassword string,
	deriver crypto.KeyDeriver) (r Registry, crypter crypto.Crypter, err error) {
	return newGCSRegistry(
		bucket,
		cryptoPassword,
		deriver,
		crypto.NewCrypter,
		rand.Reader)
}

const (
	gcsJobKeyPrefix      = "jobs/"
	gcsMetadataKey_Name  = "job_name"
	gcsMetadataKey_Score = "hex_score"

	// Constants related to the "marker" object, used to ensure that the user has
	// the right password. See notes on gcsRegistry.
	markerObjectName                = "marker"
	markerObjectMetadata_Salt       = "base64_salt"
	markerObjectMetadata_Ciphertext = "base64_ciphertext"
)

// A registry that stores job records in a GCS bucket. Object names are of the
// form
//
//     <gcsJobKeyPrefix><time>
//
// where <time> is a time.Time with UTC location formatted according to
// time.RFC3339Nano. Additional information is stored as object metadata fields
// keyed by the constants above. Metadata fields are used in preference to
// object content so that they are accessible on a ListObjects request.
//
// The bucket additionally contains a "marker" object (named by the constant
// markerObjectName) with metadata keys specifying a salt and a ciphertext for
// some random plaintext, generated ant written the first time the bucket is
// used. This marker allows us to verify that the user-provided crypto password
// is correct by deriving a key using the password and the salt and making sure
// that the ciphertext can be decrypted using that key.
type gcsRegistry struct {
	bucket gcs.Bucket
}

func (r *gcsRegistry) RecordBackup(j CompletedJob) (err error) {
	// Write an object to the bucket. On the small change that the time collides
	// (or we've done something dumb like use the zero time), use a generation
	// precondition to ensure we don't overwrite anything.
	var precond int64
	req := &gcs.CreateObjectRequest{
		Name:                   gcsJobKeyPrefix + j.StartTime.Format(time.RFC3339Nano),
		Contents:               strings.NewReader(""),
		GenerationPrecondition: &precond,

		Metadata: map[string]string{
			gcsMetadataKey_Name:  j.Name,
			gcsMetadataKey_Score: j.Score.Hex(),
		},
	}

	_, err = r.bucket.CreateObject(context.Background(), req)
	if err != nil {
		err = fmt.Errorf("CreateObject: %v", err)
		return
	}

	return
}

func parseObjectAsJob(o *gcs.Object) (j CompletedJob, err error) {
	// Extract the formatted time.
	if !strings.HasPrefix(o.Name, gcsJobKeyPrefix) {
		err = fmt.Errorf("Unexpected object name: \"%s\"", o.Name)
		return
	}

	formattedTime := strings.TrimPrefix(o.Name, gcsJobKeyPrefix)

	// Parse it.
	j.StartTime, err = time.Parse(time.RFC3339Nano, formattedTime)
	if err != nil {
		err = fmt.Errorf("Parsing time \"%s\": %v", formattedTime, err)
		return
	}

	// Extract the job name.
	{
		var ok bool
		if j.Name, ok = o.Metadata[gcsMetadataKey_Name]; !ok {
			err = fmt.Errorf(
				"Object with name \"%s\" is missing metadata key %s",
				o.Name,
				gcsMetadataKey_Name)

			return
		}
	}

	// Extract the score.
	{
		hexScore, ok := o.Metadata[gcsMetadataKey_Score]
		if !ok {
			err = fmt.Errorf(
				"Object with name \"%s\" is missing metadata key %s",
				o.Name,
				gcsMetadataKey_Score)

			return
		}

		j.Score, err = blob.ParseHexScore(hexScore)
		if err != nil {
			err = fmt.Errorf("Parsing hex score \"%s\": %v", hexScore, err)
			return
		}
	}

	return
}

func (r *gcsRegistry) ListRecentBackups() (jobs []CompletedJob, err error) {
	// List all of the objects with the appropriate name prefix.
	req := &gcs.ListObjectsRequest{
		Prefix: gcsJobKeyPrefix,
	}

	objects, _, err := gcsutil.List(context.Background(), r.bucket, req)
	if err != nil {
		err = fmt.Errorf("gcsutil.List: %v", err)
		return
	}

	// Process each object.
	for _, o := range objects {
		var j CompletedJob
		j, err = parseObjectAsJob(o)
		if err != nil {
			err = fmt.Errorf("parseObjectAsJob: %v", err)
			return
		}

		jobs = append(jobs, j)
	}

	return
}

func (r *gcsRegistry) FindBackup(
	startTime time.Time) (job CompletedJob, err error) {
	err = fmt.Errorf("gcsRegistry.FindBackup is not implemented.")
	return
}

// Like NewGCSRegistry, but with more injected.
func newGCSRegistry(
	bucket gcs.Bucket,
	cryptoPassword string,
	deriver crypto.KeyDeriver,
	createCrypter func(key []byte) (crypto.Crypter, error),
	cryptoRandSrc io.Reader) (r Registry, crypter crypto.Crypter, err error) {
	// Find the previously-written encrypted marker object, if any.
	statReq := &gcs.StatObjectRequest{Name: markerObjectName}
	o, err := bucket.StatObject(context.Background(), statReq)

	if _, ok := err.(*gcs.NotFoundError); ok {
		err = nil
		o = nil
	}

	if err != nil {
		err = fmt.Errorf("StatObject: %v", err)
		return
	}

	// If the object was found, we must verify it is compatible.
	if o != nil {
		crypter, err = verifyCompatibleAndSetUpCrypter(
			o,
			cryptoPassword,
			deriver,
			createCrypter,
		)

		if err != nil {
			return
		}

		// All is good.
		r = &gcsRegistry{
			bucket: bucket,
		}

		return
	}

	// Otherwise, we want to claim this bucket. Encrypt some random data, base64
	// encode it, then write it out. Make sure to use a precondition to defeat
	// the race condition where another machine is doing the same simultaneously.

	// Generate a random salt.
	salt := make([]byte, 8)
	if _, err = io.ReadAtLeast(cryptoRandSrc, salt, len(salt)); err != nil {
		err = fmt.Errorf("Reading random bytes for salt: %v", err)
		return
	}

	// Derive a crypto key and create the crypter.
	cryptoKey := deriver.DeriveKey(cryptoPassword, salt)
	crypter, err = createCrypter(cryptoKey)
	if err != nil {
		err = fmt.Errorf("createCrypter: %v", err)
		return
	}

	// Create some plaintext.
	plaintext := make([]byte, 8)
	_, err = io.ReadAtLeast(cryptoRandSrc, plaintext, len(plaintext))
	if err != nil {
		err = fmt.Errorf("Reading random bytes for plaintext: %v", err)
		return
	}

	// Encrypt the plaintext.
	ciphertext, err := crypter.Encrypt(plaintext)
	if err != nil {
		err = fmt.Errorf("Encrypt: %v", err)
		return
	}

	// Base-64 encode.
	encodedCiphertext := base64.StdEncoding.EncodeToString(ciphertext)
	encodedSalt := base64.StdEncoding.EncodeToString(salt)

	// Write out the marker object.
	var precond int64
	createReq := &gcs.CreateObjectRequest{
		Name: markerObjectName,
		Metadata: map[string]string{
			markerObjectMetadata_Salt:       encodedSalt,
			markerObjectMetadata_Ciphertext: encodedCiphertext,
		},
		Contents:               strings.NewReader(""),
		GenerationPrecondition: &precond,
	}

	_, err = bucket.CreateObject(context.Background(), createReq)
	if err != nil {
		err = fmt.Errorf("CreateObject: %v", err)
		return
	}

	// All is good.
	r = &gcsRegistry{
		bucket: bucket,
	}

	return
}

func verifyCompatibleAndSetUpCrypter(
	markerObject *gcs.Object,
	cryptoPassword string,
	deriver crypto.KeyDeriver,
	createCrypter func(key []byte) (crypto.Crypter, error)) (
	crypter crypto.Crypter,
	err error) {
	o := markerObject

	// Find the metadata keys.
	var passwordSaltBase64 string
	var ciphertextBase64 string
	var ok bool

	if passwordSaltBase64, ok = o.Metadata[markerObjectMetadata_Salt]; !ok {
		err = fmt.Errorf("Missing salt metadata key.")
		return
	}

	if ciphertextBase64, ok = o.Metadata[markerObjectMetadata_Ciphertext]; !ok {
		err = fmt.Errorf("Missing ciphertext metadata key.")
		return
	}

	// Base64-decode.
	passwordSalt, err := base64.StdEncoding.DecodeString(passwordSaltBase64)
	if err != nil {
		err = fmt.Errorf("Decoding password salt: %v", err)
		return
	}

	ciphertext, err := base64.StdEncoding.DecodeString(ciphertextBase64)
	if err != nil {
		err = fmt.Errorf("Decoding ciphertext: %v", err)
		return
	}

	// Derive a key and create a crypter.
	cryptoKey := deriver.DeriveKey(cryptoPassword, passwordSalt)
	if crypter, err = createCrypter(cryptoKey); err != nil {
		err = fmt.Errorf("createCrypter: %v", err)
		return
	}

	// Attempt to decrypt the ciphertext.
	if _, err = crypter.Decrypt(ciphertext); err != nil {
		// Special case: Did the crypter signal that the key was wrong?
		if _, ok := err.(*crypto.NotAuthenticError); ok {
			err = fmt.Errorf("The supplied password is incorrect.")
			return
		}

		// Generic error.
		err = fmt.Errorf("Decrypt: %v", err)
		return
	}

	return
}
<|endoftext|>


<commit_before>package driver

import (
	"bytes"
	"encoding/json"
	"github.com/realglobe-Inc/edo/util"
	"github.com/realglobe-Inc/go-lib-rg/erro"
	"net/http"
	"net/url"
	"path"
	"time"
)

// Web API を提供するレジストリから取ってくる。

type webDriver struct {
	prefix string
	*http.Client
}

func newWebDriver(addr string, ssl bool) (*webDriver, error) {
	var prefix string
	if ssl {
		prefix = "http://"
	} else {
		prefix = "https://"
	}
	prefix += addr

	client := &http.Client{}

	// 途中で死んだときの対処をしっかりやる方向で。
	// // 接続テスト。
	// resp, err := client.Head(prefix)
	// if err != nil {
	// 	return nil, erro.Wrap(err)
	// }
	// resp.Body.Close()

	return &webDriver{prefix, client}, nil
}

// ログイン。
func NewWebLoginRegistry(addr string, ssl bool) (LoginRegistry, error) {
	return newWebDriver(addr, ssl)
}

func (reg *webDriver) User(accToken string) (usrUuid string, err error) {
	resp, err := reg.Get(reg.prefix + "/" + accToken)
	if err != nil {
		return "", erro.Wrap(err)
	}
	defer resp.Body.Close()
	if resp.StatusCode == http.StatusNotFound {
		return "", nil
	} else if resp.StatusCode != http.StatusOK {
		return "", erro.New("invalid status ", resp.StatusCode, " "+http.StatusText(resp.StatusCode)+".")
	}
	if err := json.NewDecoder(resp.Body).Decode(&usrUuid); err != nil {
		return "", erro.Wrap(err)
	}
	return usrUuid, nil
}

// JavaScript.
func NewWebJsRegistry(addr string, ssl bool) (JsRegistry, error) {
	return newWebDriver(addr, ssl)
}

func (reg *webDriver) Object(dir, objName string) (*Object, error) {
	resp, err := reg.Get(reg.prefix + path.Join(dir, objName))
	if err != nil {
		return nil, erro.Wrap(err)
	}
	defer resp.Body.Close()
	//util.LogResponse(resp, true)

	if resp.StatusCode == http.StatusNotFound {
		return nil, nil
	} else if resp.StatusCode != http.StatusOK {
		return nil, erro.New("invalid status ", resp.StatusCode, " "+http.StatusText(resp.StatusCode)+".")
	}
	var obj Object
	if err := json.NewDecoder(resp.Body).Decode(&obj); err != nil {
		return nil, erro.Wrap(err)
	}
	return &obj, nil
}
func (reg *webDriver) AddObject(dir, objName string, obj *Object) error {
	buff, err := json.Marshal(obj)
	if err != nil {
		return erro.Wrap(err)
	}

	req, err := http.NewRequest("PUT", reg.prefix+path.Join(dir, objName), bytes.NewReader(buff))
	if err != nil {
		return erro.Wrap(err)
	}
	req.Header.Set("Content-Type", util.ContentTypeJson)

	//util.LogRequest(req, true)
	resp, err := reg.Do(req)
	if err != nil {
		return erro.Wrap(err)
	}
	defer resp.Body.Close()
	//util.LogResponse(resp, true)

	if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated {
		return erro.New("invalid status ", resp.StatusCode, " "+http.StatusText(resp.StatusCode)+".")
	}
	return nil
}
func (reg *webDriver) RemoveObject(dir, objName string) error {
	req, err := http.NewRequest("DELETE", reg.prefix+path.Join(dir, objName), nil)
	if err != nil {
		return erro.Wrap(err)
	}
	resp, err := reg.Do(req)
	if err != nil {
		return erro.Wrap(err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return erro.New("invalid status ", resp.StatusCode, " "+http.StatusText(resp.StatusCode)+".")
	}
	return nil
}

// ユーザー情報。
func NewWebUserRegistry(addr string, ssl bool) (UserRegistry, error) {
	return newWebDriver(addr, ssl)
}

func (reg *webDriver) Attributes(usrUuid string) (map[string]interface{}, error) {
	resp, err := reg.Get(reg.prefix + "/" + usrUuid)
	if err != nil {
		return nil, erro.Wrap(err)
	}
	defer resp.Body.Close()
	if resp.StatusCode == http.StatusNotFound {
		return nil, nil
	} else if resp.StatusCode != http.StatusOK {
		return nil, erro.New("invalid status ", resp.StatusCode, " "+http.StatusText(resp.StatusCode)+".")
	}
	var attrs map[string]interface{}
	if err := json.NewDecoder(resp.Body).Decode(&attrs); err != nil {
		return nil, erro.Wrap(err)
	}
	return attrs, nil
}
func (reg *webDriver) Attribute(usrUuid, attrName string) (interface{}, error) {
	resp, err := reg.Get(reg.prefix + "/" + usrUuid + "/" + attrName)
	if err != nil {
		return nil, erro.Wrap(err)
	}
	defer resp.Body.Close()
	//util.LogResponse(resp, true)

	if resp.StatusCode == http.StatusNotFound {
		return nil, nil
	} else if resp.StatusCode != http.StatusOK {
		return nil, erro.New("invalid status ", resp.StatusCode, " "+http.StatusText(resp.StatusCode)+".")
	}
	var attr interface{}
	if err := json.NewDecoder(resp.Body).Decode(&attr); err != nil {
		return nil, erro.Wrap(err)
	}
	return attr, nil
}
func (reg *webDriver) AddAttribute(usrUuid, attrName string, attr interface{}) error {
	buff, err := json.Marshal(attr)
	if err != nil {
		return erro.Wrap(err)
	}

	req, err := http.NewRequest("PUT", reg.prefix+"/"+usrUuid+"/"+attrName, bytes.NewReader(buff))
	if err != nil {
		return erro.Wrap(err)
	}
	req.Header.Set("Content-Type", util.ContentTypeJson)

	//util.LogRequest(req, true)
	resp, err := reg.Do(req)
	if err != nil {
		return erro.Wrap(err)
	}
	defer resp.Body.Close()
	//util.LogResponse(resp, true)

	if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated {
		return erro.New("invalid status ", resp.StatusCode, " "+http.StatusText(resp.StatusCode)+".")
	}
	return nil
}
func (reg *webDriver) RemoveAttribute(usrUuid, attrName string) error {
	req, err := http.NewRequest("DELETE", reg.prefix+"/"+usrUuid+"/"+attrName, nil)
	if err != nil {
		return erro.Wrap(err)
	}
	resp, err := reg.Do(req)
	if err != nil {
		return erro.Wrap(err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return erro.New("invalid status ", resp.StatusCode, " "+http.StatusText(resp.StatusCode)+".")
	}
	return nil
}

// ジョブ。
func NewWebJobRegistry(addr string, ssl bool) (JobRegistry, error) {
	return newWebDriver(addr, ssl)
}

func (reg *webDriver) Result(jobId string) (*JobResult, error) {
	resp, err := reg.Get(reg.prefix + "/" + jobId)
	if err != nil {
		return nil, erro.Wrap(err)
	}
	defer resp.Body.Close()
	if resp.StatusCode == http.StatusNotModified || resp.StatusCode == http.StatusNotFound {
		return nil, nil
	} else if resp.StatusCode != http.StatusOK {
		return nil, erro.New("invalid status ", resp.StatusCode, " "+http.StatusText(resp.StatusCode)+".")
	}
	var res JobResult
	if err := json.NewDecoder(resp.Body).Decode(&res); err != nil {
		return nil, erro.Wrap(err)
	}
	return &res, nil
}

type resultPack struct {
	*JobResult
	Deadline time.Time `json:"deadline"`
}

func (reg *webDriver) AddResult(jobId string, res *JobResult, deadline time.Time) error {
	buff, err := json.Marshal(&resultPack{res, deadline})
	if err != nil {
		return erro.Wrap(err)
	}

	req, err := http.NewRequest("PUT", reg.prefix+"/"+jobId, bytes.NewReader(buff))
	if err != nil {
		return erro.Wrap(err)
	}
	req.Header.Set("Content-Type", util.ContentTypeJson)
	resp, err := reg.Do(req)
	if err != nil {
		return erro.Wrap(err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated {
		return erro.New("invalid status ", resp.StatusCode, " "+http.StatusText(resp.StatusCode)+".")
	}
	return nil
}

// 住所。
func NewWebNameRegistry(addr string, ssl bool) (NameRegistry, error) {
	return newWebDriver(addr, ssl)
}

func (reg *webDriver) Address(name string) (addr string, err error) {
	resp, err := reg.Get(reg.prefix + "/node/" + name)
	if err != nil {
		return "", erro.Wrap(err)
	}
	defer resp.Body.Close()
	if resp.StatusCode == http.StatusNotFound {
		return "", nil
	} else if resp.StatusCode != http.StatusOK {
		return "", erro.New("invalid status ", resp.StatusCode, " "+http.StatusText(resp.StatusCode)+".")
	}
	if err := json.NewDecoder(resp.Body).Decode(&addr); err != nil {
		return "", erro.Wrap(err)
	}
	return addr, nil
}
func (reg *webDriver) Addresses(name string) (addrs []string, err error) {
	resp, err := reg.Get(reg.prefix + "/tree/" + name)
	if err != nil {
		return nil, erro.Wrap(err)
	}
	defer resp.Body.Close()
	if resp.StatusCode == http.StatusNotFound {
		return nil, nil
	} else if resp.StatusCode != http.StatusOK {
		return nil, erro.New("invalid status ", resp.StatusCode, " "+http.StatusText(resp.StatusCode)+".")
	}
	if err := json.NewDecoder(resp.Body).Decode(&addrs); err != nil {
		return nil, erro.Wrap(err)
	}
	return addrs, nil
}

// イベント。
func NewWebEventRegistry(addr string, ssl bool) (EventRegistry, error) {
	return newWebDriver(addr, ssl)
}

func (reg *webDriver) Handler(usrUuid, event string) (Handler, error) {
	resp, err := reg.Get(reg.prefix + "/" + usrUuid + event)
	if err != nil {
		return nil, erro.Wrap(err)
	}
	defer resp.Body.Close()
	if resp.StatusCode == http.StatusNotFound {
		return nil, nil
	} else if resp.StatusCode != http.StatusOK {
		return nil, erro.New("invalid status ", resp.StatusCode, " "+http.StatusText(resp.StatusCode)+".")
	}
	var hndl Handler
	if err := json.NewDecoder(resp.Body).Decode(&hndl); err != nil {
		return nil, erro.Wrap(err)
	}
	return hndl, nil
}
func (reg *webDriver) AddHandler(usrUuid, event string, hndl Handler) error {
	buff, err := json.Marshal(hndl)
	if err != nil {
		return erro.Wrap(err)
	}

	req, err := http.NewRequest("PUT", reg.prefix+"/"+usrUuid+event, bytes.NewReader(buff))
	if err != nil {
		return erro.Wrap(err)
	}
	req.Header.Set("Content-Type", util.ContentTypeJson)

	//util.LogRequest(req, true)
	resp, err := reg.Do(req)
	if err != nil {
		return erro.Wrap(err)
	}
	defer resp.Body.Close()
	//util.LogResponse(resp, true)

	if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated {
		return erro.New("invalid status ", resp.StatusCode, " "+http.StatusText(resp.StatusCode)+".")
	}
	return nil
}
func (reg *webDriver) RemoveHandler(usrUuid, event string) error {
	req, err := http.NewRequest("DELETE", reg.prefix+"/"+usrUuid+event, nil)
	if err != nil {
		return erro.Wrap(err)
	}
	resp, err := reg.Do(req)
	if err != nil {
		return erro.Wrap(err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return erro.New("invalid status ", resp.StatusCode, " "+http.StatusText(resp.StatusCode)+".")
	}
	return nil
}

// サービス。
func NewWebServiceRegistry(addr string, ssl bool) (ServiceRegistry, error) {
	return newWebDriver(addr, ssl)
}

func (reg *webDriver) Service(addr string) (servUuid string, err error) {
	resp, err := reg.Get(reg.prefix + "?address=" + url.QueryEscape(addr))
	if err != nil {
		return "", erro.Wrap(err)
	}
	defer resp.Body.Close()
	if resp.StatusCode == http.StatusNotFound {
		return "", nil
	} else if resp.StatusCode != http.StatusOK {
		return "", erro.New("invalid status ", resp.StatusCode, " "+http.StatusText(resp.StatusCode)+".")
	}
	if err := json.NewDecoder(resp.Body).Decode(&servUuid); err != nil {
		return "", erro.Wrap(err)
	}
	return servUuid, nil
}
<commit_msg>JSON のキーの間違いを修正<commit_after>package driver

import (
	"bytes"
	"encoding/json"
	"github.com/realglobe-Inc/edo/util"
	"github.com/realglobe-Inc/go-lib-rg/erro"
	"net/http"
	"net/url"
	"path"
	"time"
)

// Web API を提供するレジストリから取ってくる。

type webDriver struct {
	prefix string
	*http.Client
}

func newWebDriver(addr string, ssl bool) (*webDriver, error) {
	var prefix string
	if ssl {
		prefix = "http://"
	} else {
		prefix = "https://"
	}
	prefix += addr

	client := &http.Client{}

	// 途中で死んだときの対処をしっかりやる方向で。
	// // 接続テスト。
	// resp, err := client.Head(prefix)
	// if err != nil {
	// 	return nil, erro.Wrap(err)
	// }
	// resp.Body.Close()

	return &webDriver{prefix, client}, nil
}

// ログイン。
func NewWebLoginRegistry(addr string, ssl bool) (LoginRegistry, error) {
	return newWebDriver(addr, ssl)
}

func (reg *webDriver) User(accToken string) (usrUuid string, err error) {
	resp, err := reg.Get(reg.prefix + "/" + accToken)
	if err != nil {
		return "", erro.Wrap(err)
	}
	defer resp.Body.Close()
	if resp.StatusCode == http.StatusNotFound {
		return "", nil
	} else if resp.StatusCode != http.StatusOK {
		return "", erro.New("invalid status ", resp.StatusCode, " "+http.StatusText(resp.StatusCode)+".")
	}
	if err := json.NewDecoder(resp.Body).Decode(&usrUuid); err != nil {
		return "", erro.Wrap(err)
	}
	return usrUuid, nil
}

// JavaScript.
func NewWebJsRegistry(addr string, ssl bool) (JsRegistry, error) {
	return newWebDriver(addr, ssl)
}

func (reg *webDriver) Object(dir, objName string) (*Object, error) {
	resp, err := reg.Get(reg.prefix + path.Join(dir, objName))
	if err != nil {
		return nil, erro.Wrap(err)
	}
	defer resp.Body.Close()
	//util.LogResponse(resp, true)

	if resp.StatusCode == http.StatusNotFound {
		return nil, nil
	} else if resp.StatusCode != http.StatusOK {
		return nil, erro.New("invalid status ", resp.StatusCode, " "+http.StatusText(resp.StatusCode)+".")
	}
	var obj Object
	if err := json.NewDecoder(resp.Body).Decode(&obj); err != nil {
		return nil, erro.Wrap(err)
	}
	return &obj, nil
}
func (reg *webDriver) AddObject(dir, objName string, obj *Object) error {
	buff, err := json.Marshal(obj)
	if err != nil {
		return erro.Wrap(err)
	}

	req, err := http.NewRequest("PUT", reg.prefix+path.Join(dir, objName), bytes.NewReader(buff))
	if err != nil {
		return erro.Wrap(err)
	}
	req.Header.Set("Content-Type", util.ContentTypeJson)

	//util.LogRequest(req, true)
	resp, err := reg.Do(req)
	if err != nil {
		return erro.Wrap(err)
	}
	defer resp.Body.Close()
	//util.LogResponse(resp, true)

	if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated {
		return erro.New("invalid status ", resp.StatusCode, " "+http.StatusText(resp.StatusCode)+".")
	}
	return nil
}
func (reg *webDriver) RemoveObject(dir, objName string) error {
	req, err := http.NewRequest("DELETE", reg.prefix+path.Join(dir, objName), nil)
	if err != nil {
		return erro.Wrap(err)
	}
	resp, err := reg.Do(req)
	if err != nil {
		return erro.Wrap(err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return erro.New("invalid status ", resp.StatusCode, " "+http.StatusText(resp.StatusCode)+".")
	}
	return nil
}

// ユーザー情報。
func NewWebUserRegistry(addr string, ssl bool) (UserRegistry, error) {
	return newWebDriver(addr, ssl)
}

func (reg *webDriver) Attributes(usrUuid string) (map[string]interface{}, error) {
	resp, err := reg.Get(reg.prefix + "/" + usrUuid)
	if err != nil {
		return nil, erro.Wrap(err)
	}
	defer resp.Body.Close()
	if resp.StatusCode == http.StatusNotFound {
		return nil, nil
	} else if resp.StatusCode != http.StatusOK {
		return nil, erro.New("invalid status ", resp.StatusCode, " "+http.StatusText(resp.StatusCode)+".")
	}
	var attrs map[string]interface{}
	if err := json.NewDecoder(resp.Body).Decode(&attrs); err != nil {
		return nil, erro.Wrap(err)
	}
	return attrs, nil
}
func (reg *webDriver) Attribute(usrUuid, attrName string) (interface{}, error) {
	resp, err := reg.Get(reg.prefix + "/" + usrUuid + "/" + attrName)
	if err != nil {
		return nil, erro.Wrap(err)
	}
	defer resp.Body.Close()
	//util.LogResponse(resp, true)

	if resp.StatusCode == http.StatusNotFound {
		return nil, nil
	} else if resp.StatusCode != http.StatusOK {
		return nil, erro.New("invalid status ", resp.StatusCode, " "+http.StatusText(resp.StatusCode)+".")
	}
	var attr interface{}
	if err := json.NewDecoder(resp.Body).Decode(&attr); err != nil {
		return nil, erro.Wrap(err)
	}
	return attr, nil
}
func (reg *webDriver) AddAttribute(usrUuid, attrName string, attr interface{}) error {
	buff, err := json.Marshal(attr)
	if err != nil {
		return erro.Wrap(err)
	}

	req, err := http.NewRequest("PUT", reg.prefix+"/"+usrUuid+"/"+attrName, bytes.NewReader(buff))
	if err != nil {
		return erro.Wrap(err)
	}
	req.Header.Set("Content-Type", util.ContentTypeJson)

	//util.LogRequest(req, true)
	resp, err := reg.Do(req)
	if err != nil {
		return erro.Wrap(err)
	}
	defer resp.Body.Close()
	//util.LogResponse(resp, true)

	if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated {
		return erro.New("invalid status ", resp.StatusCode, " "+http.StatusText(resp.StatusCode)+".")
	}
	return nil
}
func (reg *webDriver) RemoveAttribute(usrUuid, attrName string) error {
	req, err := http.NewRequest("DELETE", reg.prefix+"/"+usrUuid+"/"+attrName, nil)
	if err != nil {
		return erro.Wrap(err)
	}
	resp, err := reg.Do(req)
	if err != nil {
		return erro.Wrap(err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return erro.New("invalid status ", resp.StatusCode, " "+http.StatusText(resp.StatusCode)+".")
	}
	return nil
}

// ジョブ。
func NewWebJobRegistry(addr string, ssl bool) (JobRegistry, error) {
	return newWebDriver(addr, ssl)
}

func (reg *webDriver) Result(jobId string) (*JobResult, error) {
	resp, err := reg.Get(reg.prefix + "/" + jobId)
	if err != nil {
		return nil, erro.Wrap(err)
	}
	defer resp.Body.Close()
	if resp.StatusCode == http.StatusNotModified || resp.StatusCode == http.StatusNotFound {
		return nil, nil
	} else if resp.StatusCode != http.StatusOK {
		return nil, erro.New("invalid status ", resp.StatusCode, " "+http.StatusText(resp.StatusCode)+".")
	}
	var res JobResult
	if err := json.NewDecoder(resp.Body).Decode(&res); err != nil {
		return nil, erro.Wrap(err)
	}
	return &res, nil
}

type resultPack struct {
	*JobResult
	Deadline time.Time `json:"deadline"`
}

func (reg *webDriver) AddResult(jobId string, res *JobResult, deadline time.Time) error {
	buff, err := json.Marshal(&resultPack{res, deadline})
	if err != nil {
		return erro.Wrap(err)
	}

	req, err := http.NewRequest("PUT", reg.prefix+"/"+jobId, bytes.NewReader(buff))
	if err != nil {
		return erro.Wrap(err)
	}
	req.Header.Set("Content-Type", util.ContentTypeJson)
	resp, err := reg.Do(req)
	if err != nil {
		return erro.Wrap(err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated {
		return erro.New("invalid status ", resp.StatusCode, " "+http.StatusText(resp.StatusCode)+".")
	}
	return nil
}

// 住所。
func NewWebNameRegistry(addr string, ssl bool) (NameRegistry, error) {
	return newWebDriver(addr, ssl)
}

func (reg *webDriver) Address(name string) (addr string, err error) {
	resp, err := reg.Get(reg.prefix + "/node/" + name)
	if err != nil {
		return "", erro.Wrap(err)
	}
	defer resp.Body.Close()
	if resp.StatusCode == http.StatusNotFound {
		return "", nil
	} else if resp.StatusCode != http.StatusOK {
		return "", erro.New("invalid status ", resp.StatusCode, " "+http.StatusText(resp.StatusCode)+".")
	}
	if err := json.NewDecoder(resp.Body).Decode(&addr); err != nil {
		return "", erro.Wrap(err)
	}
	return addr, nil
}
func (reg *webDriver) Addresses(name string) (addrs []string, err error) {
	resp, err := reg.Get(reg.prefix + "/tree/" + name)
	if err != nil {
		return nil, erro.Wrap(err)
	}
	defer resp.Body.Close()
	if resp.StatusCode == http.StatusNotFound {
		return nil, nil
	} else if resp.StatusCode != http.StatusOK {
		return nil, erro.New("invalid status ", resp.StatusCode, " "+http.StatusText(resp.StatusCode)+".")
	}
	if err := json.NewDecoder(resp.Body).Decode(&addrs); err != nil {
		return nil, erro.Wrap(err)
	}
	return addrs, nil
}

// イベント。
func NewWebEventRegistry(addr string, ssl bool) (EventRegistry, error) {
	return newWebDriver(addr, ssl)
}

func (reg *webDriver) Handler(usrUuid, event string) (Handler, error) {
	resp, err := reg.Get(reg.prefix + "/" + usrUuid + event)
	if err != nil {
		return nil, erro.Wrap(err)
	}
	defer resp.Body.Close()
	if resp.StatusCode == http.StatusNotFound {
		return nil, nil
	} else if resp.StatusCode != http.StatusOK {
		return nil, erro.New("invalid status ", resp.StatusCode, " "+http.StatusText(resp.StatusCode)+".")
	}
	var hndl Handler
	if err := json.NewDecoder(resp.Body).Decode(&hndl); err != nil {
		return nil, erro.Wrap(err)
	}
	return hndl, nil
}
func (reg *webDriver) AddHandler(usrUuid, event string, hndl Handler) error {
	buff, err := json.Marshal(hndl)
	if err != nil {
		return erro.Wrap(err)
	}

	req, err := http.NewRequest("PUT", reg.prefix+"/"+usrUuid+event, bytes.NewReader(buff))
	if err != nil {
		return erro.Wrap(err)
	}
	req.Header.Set("Content-Type", util.ContentTypeJson)

	//util.LogRequest(req, true)
	resp, err := reg.Do(req)
	if err != nil {
		return erro.Wrap(err)
	}
	defer resp.Body.Close()
	//util.LogResponse(resp, true)

	if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated {
		return erro.New("invalid status ", resp.StatusCode, " "+http.StatusText(resp.StatusCode)+".")
	}
	return nil
}
func (reg *webDriver) RemoveHandler(usrUuid, event string) error {
	req, err := http.NewRequest("DELETE", reg.prefix+"/"+usrUuid+event, nil)
	if err != nil {
		return erro.Wrap(err)
	}
	resp, err := reg.Do(req)
	if err != nil {
		return erro.Wrap(err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return erro.New("invalid status ", resp.StatusCode, " "+http.StatusText(resp.StatusCode)+".")
	}
	return nil
}

// サービス。
func NewWebServiceRegistry(addr string, ssl bool) (ServiceRegistry, error) {
	return newWebDriver(addr, ssl)
}

func (reg *webDriver) Service(addr string) (servUuid string, err error) {
	resp, err := reg.Get(reg.prefix + "?end_point=" + url.QueryEscape(addr))
	if err != nil {
		return "", erro.Wrap(err)
	}
	defer resp.Body.Close()
	if resp.StatusCode == http.StatusNotFound {
		return "", nil
	} else if resp.StatusCode != http.StatusOK {
		return "", erro.New("invalid status ", resp.StatusCode, " "+http.StatusText(resp.StatusCode)+".")
	}
	if err := json.NewDecoder(resp.Body).Decode(&servUuid); err != nil {
		return "", erro.Wrap(err)
	}
	return servUuid, nil
}
<|endoftext|>


<commit_before>// Package s3cache provides an implementation of httpcache.Cache that stores and
// retrieves data using Amazon S3.
package s3cache

import (
	"compress/gzip"
	"crypto/md5"
	"encoding/hex"
	"io"
	"io/ioutil"
	"log"
	"os"
	"strconv"
	"strings"

	"github.com/sqs/s3"
	"github.com/sqs/s3/s3util"
)

// Cache objects store and retrieve data using Amazon S3.
type Cache struct {
	// Config is the Amazon S3 configuration.
	Config s3util.Config

	// BucketURL is the URL to the bucket on Amazon S3, which includes the
	// bucket name and the AWS region. Example:
	// "https://s3-us-west-2.amazonaws.com/mybucket".
	BucketURL string

	// Gzip indicates whether cache entries should be gzipped in Set and
	// gunzipped in Get. If true, cache entry keys will have the suffix ".gz"
	// appended.
	Gzip bool
}

var noLogErrors, _ = strconv.ParseBool(os.Getenv("NO_LOG_S3CACHE_ERRORS"))

func (c *Cache) Get(key string) (resp []byte, ok bool) {
	rdr, err := s3util.Open(c.url(key), &c.Config)
	if err != nil {
		return []byte{}, false
	}
	defer rdr.Close()
	if c.Gzip {
		rdr, err = gzip.NewReader(rdr)
		if err != nil {
			return nil, false
		}
		defer rdr.Close()
	}
	resp, err = ioutil.ReadAll(rdr)
	if err != nil {
		if !noLogErrors {
			log.Printf("s3cache.Get failed: %s", err)
		}
	}
	return resp, err == nil
}

func (c *Cache) Set(key string, resp []byte) {
	w, err := s3util.Create(c.url(key), nil, &c.Config)
	if err != nil {
		if !noLogErrors {
			log.Printf("s3util.Create failed: %s", err)
		}
		return
	}
	defer w.Close()
	if c.Gzip {
		w = gzip.NewWriter(w)
		defer w.Close()
	}
	_, err = w.Write(resp)
	if err != nil {
		if !noLogErrors {
			log.Printf("s3cache.Set failed: %s", err)
		}
	}
}

func (c *Cache) Delete(key string) {
	rdr, err := s3util.Delete(c.url(key), &c.Config)
	if err != nil {
		if !noLogErrors {
			log.Printf("s3cache.Delete failed: %s", err)
		}
		return
	}
	defer rdr.Close()
}

func (c *Cache) url(key string) string {
	key = cacheKeyToObjectKey(key)
	if c.Gzip {
		key += ".gz"
	}
	if strings.HasSuffix(c.BucketURL, "/") {
		return c.BucketURL + key
	}
	return c.BucketURL + "/" + key
}

func cacheKeyToObjectKey(key string) string {
	h := md5.New()
	io.WriteString(h, key)
	return hex.EncodeToString(h.Sum(nil))
}

// New returns a new Cache with underlying storage in Amazon S3. The bucketURL
// is the full URL to the bucket on Amazon S3, including the bucket name and AWS
// region (e.g., "https://s3-us-west-2.amazonaws.com/mybucket").
//
// The environment variables AWS_ACCESS_KEY_ID and AWS_SECRET_KEY are used as the AWS
// credentials. To use different credentials, modify the returned Cache object
// or construct a Cache object manually.
func New(bucketURL string) *Cache {
	return &Cache{
		Config: s3util.Config{
			Keys: &s3.Keys{
				AccessKey: os.Getenv("AWS_ACCESS_KEY_ID"),
				SecretKey: os.Getenv("AWS_SECRET_KEY"),
			},
			Service: s3.DefaultService,
		},
		BucketURL: bucketURL,
	}
}
<commit_msg>use sourcegraph.com/sourcegraph/... import path comment<commit_after>// Package s3cache provides an implementation of httpcache.Cache that stores and
// retrieves data using Amazon S3.
package s3cache // import "sourcegraph.com/sourcegraph/s3cache"

import (
	"compress/gzip"
	"crypto/md5"
	"encoding/hex"
	"io"
	"io/ioutil"
	"log"
	"os"
	"strconv"
	"strings"

	"github.com/sqs/s3"
	"github.com/sqs/s3/s3util"
)

// Cache objects store and retrieve data using Amazon S3.
type Cache struct {
	// Config is the Amazon S3 configuration.
	Config s3util.Config

	// BucketURL is the URL to the bucket on Amazon S3, which includes the
	// bucket name and the AWS region. Example:
	// "https://s3-us-west-2.amazonaws.com/mybucket".
	BucketURL string

	// Gzip indicates whether cache entries should be gzipped in Set and
	// gunzipped in Get. If true, cache entry keys will have the suffix ".gz"
	// appended.
	Gzip bool
}

var noLogErrors, _ = strconv.ParseBool(os.Getenv("NO_LOG_S3CACHE_ERRORS"))

func (c *Cache) Get(key string) (resp []byte, ok bool) {
	rdr, err := s3util.Open(c.url(key), &c.Config)
	if err != nil {
		return []byte{}, false
	}
	defer rdr.Close()
	if c.Gzip {
		rdr, err = gzip.NewReader(rdr)
		if err != nil {
			return nil, false
		}
		defer rdr.Close()
	}
	resp, err = ioutil.ReadAll(rdr)
	if err != nil {
		if !noLogErrors {
			log.Printf("s3cache.Get failed: %s", err)
		}
	}
	return resp, err == nil
}

func (c *Cache) Set(key string, resp []byte) {
	w, err := s3util.Create(c.url(key), nil, &c.Config)
	if err != nil {
		if !noLogErrors {
			log.Printf("s3util.Create failed: %s", err)
		}
		return
	}
	defer w.Close()
	if c.Gzip {
		w = gzip.NewWriter(w)
		defer w.Close()
	}
	_, err = w.Write(resp)
	if err != nil {
		if !noLogErrors {
			log.Printf("s3cache.Set failed: %s", err)
		}
	}
}

func (c *Cache) Delete(key string) {
	rdr, err := s3util.Delete(c.url(key), &c.Config)
	if err != nil {
		if !noLogErrors {
			log.Printf("s3cache.Delete failed: %s", err)
		}
		return
	}
	defer rdr.Close()
}

func (c *Cache) url(key string) string {
	key = cacheKeyToObjectKey(key)
	if c.Gzip {
		key += ".gz"
	}
	if strings.HasSuffix(c.BucketURL, "/") {
		return c.BucketURL + key
	}
	return c.BucketURL + "/" + key
}

func cacheKeyToObjectKey(key string) string {
	h := md5.New()
	io.WriteString(h, key)
	return hex.EncodeToString(h.Sum(nil))
}

// New returns a new Cache with underlying storage in Amazon S3. The bucketURL
// is the full URL to the bucket on Amazon S3, including the bucket name and AWS
// region (e.g., "https://s3-us-west-2.amazonaws.com/mybucket").
//
// The environment variables AWS_ACCESS_KEY_ID and AWS_SECRET_KEY are used as the AWS
// credentials. To use different credentials, modify the returned Cache object
// or construct a Cache object manually.
func New(bucketURL string) *Cache {
	return &Cache{
		Config: s3util.Config{
			Keys: &s3.Keys{
				AccessKey: os.Getenv("AWS_ACCESS_KEY_ID"),
				SecretKey: os.Getenv("AWS_SECRET_KEY"),
			},
			Service: s3.DefaultService,
		},
		BucketURL: bucketURL,
	}
}
<|endoftext|>