<commit_before>package main

import (
	"github.com/buildkite/agent/buildkite"
	"github.com/buildkite/agent/command"
	"github.com/codegangsta/cli"
)

var Commands []cli.Command

var AgentDescription = `Usage:

   buildkite-agent start [arguments...]

Description:

   When a job is ready to run it will call the "bootstrap-script"
   and pass it all the environment variables required for the job to run.
   This script is responsible for checking out the code, and running the
   actual build script defined in the project.

   The agent will run any jobs within a PTY (pseudo terminal) if available.

Example:

   $ buildkite-agent start --token xxx`

var DownloadHelpDescription = `Usage:

   buildkite-agent artifact download [arguments...]

Description:

   Downloads artifacts from Buildkite to the local machine.

   You need to ensure that your search query is surrounded by quotes if
   using a wild card as the built-in shell path globbing will provide files,
   which will break the download.

Example:

   $ buildkite-agent artifact download "pkg/*.tar.gz" . --build xxx

   This will search across all the artifacts for the build with files that match that part.
   The first argument is the search query, and the second argument is the download destination.

   If you're trying to download a specific file, and there are multiple artifacts from different
   jobs, you can target the paticular job you want to download the artifact from:

   $ buildkite-agent artifact download "pkg/*.tar.gz" . --job "tests" --build xxx

   You can also use the job's id (provided by the environment variable $BUILDKITE_JOB_ID)`

var UploadHelpDescription = `Usage:

   buildkite-agent artifact upload <pattern> <destination> [arguments...]

Description:

   Uploads files to a job as artifacts.

   You need to ensure that the paths are surrounded by quotes otherwise the
   built-in shell path globbing will provide the files, which is currently not
   supported.

Example:

   $ buildkite-agent artifact upload "log/**/*.log"

   You can also upload directy to Amazon S3 if you'd like to host your own artifacts:

   $ export AWS_SECRET_ACCESS_KEY=yyy
   $ export AWS_ACCESS_KEY_ID=xxx
   $ buildkite-agent artifact upload "log/**/*.log" s3://name-of-your-s3-bucket/$BUILDKITE_JOB_ID`

var SetHelpDescription = `Usage:

   buildkite-agent meta-data set <key> <value> [arguments...]

Description:

   Set arbitrary data on a build using a basic key/value store.

Example:

   $ buildkite-agent meta-data set "foo" "bar"`

var GetHelpDescription = `Usage:

   buildkite-agent meta-data get <key> [arguments...]

Description:

   Get data from a builds key/value store.

Example:

   $ buildkite-agent meta-data get "foo"`

func init() {
	// This is default locations of stuff (*nix systems)
	bootstrapScriptLocation := "$HOME/.buildkite/bootstrap.sh"
	buildPathLocation := "$HOME/.buildkite/builds"
	hookPathLocation := "$HOME/.buildkite/hooks"

	// Windows has a slightly modified locations
	if buildkite.MachineIsWindows() {
		bootstrapScriptLocation = "$USERPROFILE\\AppData\\Local\\BuildkiteAgent\\bootstrap.bat"
		buildPathLocation = "$USERPROFILE\\AppData\\Local\\BuildkiteAgent\\builds"
		hookPathLocation = "$USERPROFILE\\AppData\\Local\\BuildkiteAgent\\hooks"
	}

	Commands = []cli.Command{
		{
			Name:        "start",
			Usage:       "Starts a Buildkite agent",
			Description: AgentDescription,
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:   "token",
					Value:  "",
					Usage:  "Your account agent token",
					EnvVar: "BUILDKITE_AGENT_TOKEN",
				},
				cli.StringFlag{
					Name:   "name",
					Value:  "",
					Usage:  "The name of the agent",
					EnvVar: "BUILDKITE_AGENT_NAME",
				},
				cli.StringFlag{
					Name:   "priority",
					Value:  "",
					Usage:  "The priority of the agent",
					EnvVar: "BUILDKITE_AGENT_PRIORITY",
				},
				cli.StringSliceFlag{
					Name:   "meta-data",
					Value:  &cli.StringSlice{},
					Usage:  "Meta data for the agent",
					EnvVar: "BUILDKITE_AGENT_META_DATA",
				},
				cli.BoolFlag{
					Name:  "meta-data-ec2-tags",
					Usage: "Populate the meta data from the current instances EC2 Tags",
				},
				cli.StringFlag{
					Name:   "bootstrap-script",
					Value:  bootstrapScriptLocation,
					Usage:  "Path to the bootstrap script",
					EnvVar: "BUILDKITE_BOOTSTRAP_SCRIPT_PATH",
				},
				cli.StringFlag{
					Name:   "build-path",
					Value:  buildPathLocation,
					Usage:  "Path to where the builds will run from",
					EnvVar: "BUILDKITE_BUILD_PATH",
				},
				cli.StringFlag{
					Name:   "hooks-path",
					Value:  hookPathLocation,
					Usage:  "Directory where the hook scripts are found",
					EnvVar: "BUILDKITE_HOOKS_PATH",
				},
				cli.BoolFlag{
					Name:  "no-pty",
					Usage: "Do not run jobs within a pseudo terminal",
				},
				cli.BoolFlag{
					Name:  "no-automatic-ssh-fingerprint-verification",
					Usage: "Don't automatically verify SSH fingerprints",
				},
				cli.BoolFlag{
					Name:  "no-script-eval",
					Usage: "Don't allow this agent to evaluate scripts from Buildkite. Only scripts that exist on the file system will be allowed to run",
				},
				cli.StringFlag{
					Name:   "endpoint",
					Value:  "https://agent.buildkite.com/v2",
					Usage:  "The agent API endpoint",
					EnvVar: "BUILDKITE_AGENT_ENDPOINT",
				},
				cli.BoolFlag{
					Name:   "debug",
					Usage:  "Enable debug mode.",
					EnvVar: "BUILDKITE_AGENT_DEBUG",
				},
				cli.BoolFlag{
					Name:   "no-color",
					Usage:  "Don't show colors in logging",
					EnvVar: "BUILDKITE_AGENT_NO_COLOR",
				},
			},
			Action: command.AgentStartCommandAction,
		},
		{
			Name:  "artifact",
			Usage: "Upload/download artifacts from Buildkite jobs",
			Subcommands: []cli.Command{
				{
					Name:        "download",
					Usage:       "Downloads artifacts from Buildkite to the local machine.",
					Description: DownloadHelpDescription,
					Flags: []cli.Flag{
						// We don't default to $BUILDKITE_JOB_ID with --job because downloading artifacts should
						// default to all the jobs on the build, not just the current one. --job is used
						// to scope to a paticular job if you
						cli.StringFlag{
							Name:  "job",
							Value: "",
							Usage: "Used to target a specific job to download artifacts from",
						},
						cli.StringFlag{
							Name:   "build",
							Value:  "",
							Usage:  "Which build should the artifacts be downloaded from",
							EnvVar: "BUILDKITE_BUILD_ID",
						},
						cli.StringFlag{
							Name:   "agent-access-token",
							Value:  "",
							Usage:  "The access token used to identify the agent",
							EnvVar: "BUILDKITE_AGENT_ACCESS_TOKEN",
						},
						cli.StringFlag{
							Name:   "endpoint",
							Value:  "https://agent.buildkite.com/v2",
							Usage:  "The agent API endpoint",
							EnvVar: "BUILDKITE_AGENT_ENDPOINT",
						},
						cli.BoolFlag{
							Name:   "debug",
							Usage:  "Enable debug mode",
							EnvVar: "BUILDKITE_AGENT_DEBUG",
						},
						cli.BoolFlag{
							Name:   "no-color",
							Usage:  "Don't show colors in logging",
							EnvVar: "BUILDKITE_AGENT_NO_COLOR",
						},
					},
					Action: command.ArtifactDownloadCommandAction,
				},
				{
					Name:        "upload",
					Usage:       "Uploads files to a job as artifacts.",
					Description: UploadHelpDescription,
					Flags: []cli.Flag{
						cli.StringFlag{
							Name:   "job",
							Value:  "",
							Usage:  "Which job should the artifacts be downloaded from",
							EnvVar: "BUILDKITE_JOB_ID",
						},
						cli.StringFlag{
							Name:   "agent-access-token",
							Value:  "",
							Usage:  "The access token used to identify the agent",
							EnvVar: "BUILDKITE_AGENT_ACCESS_TOKEN",
						},
						cli.StringFlag{
							Name:   "endpoint",
							Value:  "https://agent.buildkite.com/v2",
							Usage:  "The agent API endpoint",
							EnvVar: "BUILDKITE_AGENT_ENDPOINT",
						},
						cli.BoolFlag{
							Name:   "debug",
							Usage:  "Enable debug mode",
							EnvVar: "BUILDKITE_AGENT_DEBUG",
						},
						cli.BoolFlag{
							Name:   "no-color",
							Usage:  "Don't show colors in logging",
							EnvVar: "BUILDKITE_AGENT_NO_COLOR",
						},
					},
					Action: command.ArtifactUploadCommandAction,
				},
			},
		},
		{
			Name:  "meta-data",
			Usage: "Get/set data from Buildkite jobs",
			Subcommands: []cli.Command{
				{
					Name:        "set",
					Usage:       "Set data on a build",
					Description: SetHelpDescription,
					Flags: []cli.Flag{
						cli.StringFlag{
							Name:   "job",
							Value:  "",
							Usage:  "Which job should the artifacts be downloaded from",
							EnvVar: "BUILDKITE_JOB_ID",
						},
						cli.StringFlag{
							Name:   "agent-access-token",
							Value:  "",
							Usage:  "The access token used to identify the agent",
							EnvVar: "BUILDKITE_AGENT_ACCESS_TOKEN",
						},
						cli.StringFlag{
							Name:   "endpoint",
							Value:  "https://agent.buildkite.com/v2",
							Usage:  "The agent API endpoint",
							EnvVar: "BUILDKITE_AGENT_ENDPOINT",
						},
						cli.BoolFlag{
							Name:   "debug",
							Usage:  "Enable debug mode",
							EnvVar: "BUILDKITE_AGENT_DEBUG",
						},
						cli.BoolFlag{
							Name:   "no-color",
							Usage:  "Don't show colors in logging",
							EnvVar: "BUILDKITE_AGENT_NO_COLOR",
						},
					},
					Action: command.DataSetCommandAction,
				},
				{
					Name:        "get",
					Usage:       "Get data from a build",
					Description: GetHelpDescription,
					Flags: []cli.Flag{
						cli.StringFlag{
							Name:   "job",
							Value:  "",
							Usage:  "Which job should the data be retrieved from",
							EnvVar: "BUILDKITE_JOB_ID",
						},
						cli.StringFlag{
							Name:   "agent-access-token",
							Value:  "",
							Usage:  "The access token used to identify the agent",
							EnvVar: "BUILDKITE_AGENT_ACCESS_TOKEN",
						},
						cli.StringFlag{
							Name:   "endpoint",
							Value:  "https://agent.buildkite.com/v2",
							Usage:  "The agent API endpoint",
							EnvVar: "BUILDKITE_AGENT_ENDPOINT",
						},
						cli.BoolFlag{
							Name:   "debug",
							Usage:  "Enable debug mode",
							EnvVar: "BUILDKITE_AGENT_DEBUG",
						},
						cli.BoolFlag{
							Name:   "no-color",
							Usage:  "Don't show colors in logging",
							EnvVar: "BUILDKITE_AGENT_NO_COLOR",
						},
					},
					Action: command.DataGetCommandAction,
				},
			},
		},
	}
}
<commit_msg>Fixed typo.<commit_after>package main

import (
	"github.com/buildkite/agent/buildkite"
	"github.com/buildkite/agent/command"
	"github.com/codegangsta/cli"
)

var Commands []cli.Command

var AgentDescription = `Usage:

   buildkite-agent start [arguments...]

Description:

   When a job is ready to run it will call the "bootstrap-script"
   and pass it all the environment variables required for the job to run.
   This script is responsible for checking out the code, and running the
   actual build script defined in the project.

   The agent will run any jobs within a PTY (pseudo terminal) if available.

Example:

   $ buildkite-agent start --token xxx`

var DownloadHelpDescription = `Usage:

   buildkite-agent artifact download [arguments...]

Description:

   Downloads artifacts from Buildkite to the local machine.

   You need to ensure that your search query is surrounded by quotes if
   using a wild card as the built-in shell path globbing will provide files,
   which will break the download.

Example:

   $ buildkite-agent artifact download "pkg/*.tar.gz" . --build xxx

   This will search across all the artifacts for the build with files that match that part.
   The first argument is the search query, and the second argument is the download destination.

   If you're trying to download a specific file, and there are multiple artifacts from different
   jobs, you can target the paticular job you want to download the artifact from:

   $ buildkite-agent artifact download "pkg/*.tar.gz" . --job "tests" --build xxx

   You can also use the job's id (provided by the environment variable $BUILDKITE_JOB_ID)`

var UploadHelpDescription = `Usage:

   buildkite-agent artifact upload <pattern> <destination> [arguments...]

Description:

   Uploads files to a job as artifacts.

   You need to ensure that the paths are surrounded by quotes otherwise the
   built-in shell path globbing will provide the files, which is currently not
   supported.

Example:

   $ buildkite-agent artifact upload "log/**/*.log"

   You can also upload directy to Amazon S3 if you'd like to host your own artifacts:

   $ export AWS_SECRET_ACCESS_KEY=yyy
   $ export AWS_ACCESS_KEY_ID=xxx
   $ buildkite-agent artifact upload "log/**/*.log" s3://name-of-your-s3-bucket/$BUILDKITE_JOB_ID`

var SetHelpDescription = `Usage:

   buildkite-agent meta-data set <key> <value> [arguments...]

Description:

   Set arbitrary data on a build using a basic key/value store.

Example:

   $ buildkite-agent meta-data set "foo" "bar"`

var GetHelpDescription = `Usage:

   buildkite-agent meta-data get <key> [arguments...]

Description:

   Get data from a builds key/value store.

Example:

   $ buildkite-agent meta-data get "foo"`

func init() {
	// This is default locations of stuff (*nix systems)
	bootstrapScriptLocation := "$HOME/.buildkite/bootstrap.sh"
	buildPathLocation := "$HOME/.buildkite/builds"
	hookPathLocation := "$HOME/.buildkite/hooks"

	// Windows has a slightly modified locations
	if buildkite.MachineIsWindows() {
		bootstrapScriptLocation = "$USERPROFILE\\AppData\\Local\\BuildkiteAgent\\bootstrap.bat"
		buildPathLocation = "$USERPROFILE\\AppData\\Local\\BuildkiteAgent\\builds"
		hookPathLocation = "$USERPROFILE\\AppData\\Local\\BuildkiteAgent\\hooks"
	}

	Commands = []cli.Command{
		{
			Name:        "start",
			Usage:       "Starts a Buildkite agent",
			Description: AgentDescription,
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:   "token",
					Value:  "",
					Usage:  "Your account agent token",
					EnvVar: "BUILDKITE_AGENT_TOKEN",
				},
				cli.StringFlag{
					Name:   "name",
					Value:  "",
					Usage:  "The name of the agent",
					EnvVar: "BUILDKITE_AGENT_NAME",
				},
				cli.StringFlag{
					Name:   "priority",
					Value:  "",
					Usage:  "The priority of the agent",
					EnvVar: "BUILDKITE_AGENT_PRIORITY",
				},
				cli.StringSliceFlag{
					Name:   "meta-data",
					Value:  &cli.StringSlice{},
					Usage:  "Meta data for the agent",
					EnvVar: "BUILDKITE_AGENT_META_DATA",
				},
				cli.BoolFlag{
					Name:  "meta-data-ec2-tags",
					Usage: "Populate the meta data from the current instances EC2 Tags",
				},
				cli.StringFlag{
					Name:   "bootstrap-script",
					Value:  bootstrapScriptLocation,
					Usage:  "Path to the bootstrap script",
					EnvVar: "BUILDKITE_BOOTSTRAP_SCRIPT_PATH",
				},
				cli.StringFlag{
					Name:   "build-path",
					Value:  buildPathLocation,
					Usage:  "Path to where the builds will run from",
					EnvVar: "BUILDKITE_BUILD_PATH",
				},
				cli.StringFlag{
					Name:   "hooks-path",
					Value:  hookPathLocation,
					Usage:  "Directory where the hook scripts are found",
					EnvVar: "BUILDKITE_HOOKS_PATH",
				},
				cli.BoolFlag{
					Name:  "no-pty",
					Usage: "Do not run jobs within a pseudo terminal",
				},
				cli.BoolFlag{
					Name:  "no-automatic-ssh-fingerprint-verification",
					Usage: "Don't automatically verify SSH fingerprints",
				},
				cli.BoolFlag{
					Name:  "no-script-eval",
					Usage: "Don't allow this agent to evaluate scripts from Buildkite. Only scripts that exist on the file system will be allowed to run",
				},
				cli.StringFlag{
					Name:   "endpoint",
					Value:  "https://agent.buildkite.com/v2",
					Usage:  "The agent API endpoint",
					EnvVar: "BUILDKITE_AGENT_ENDPOINT",
				},
				cli.BoolFlag{
					Name:   "debug",
					Usage:  "Enable debug mode.",
					EnvVar: "BUILDKITE_AGENT_DEBUG",
				},
				cli.BoolFlag{
					Name:   "no-color",
					Usage:  "Don't show colors in logging",
					EnvVar: "BUILDKITE_AGENT_NO_COLOR",
				},
			},
			Action: command.AgentStartCommandAction,
		},
		{
			Name:  "artifact",
			Usage: "Upload/download artifacts from Buildkite jobs",
			Subcommands: []cli.Command{
				{
					Name:        "download",
					Usage:       "Downloads artifacts from Buildkite to the local machine.",
					Description: DownloadHelpDescription,
					Flags: []cli.Flag{
						// We don't default to $BUILDKITE_JOB_ID with --job because downloading artifacts should
						// default to all the jobs on the build, not just the current one. --job is used
						// to scope to a paticular job if you
						cli.StringFlag{
							Name:  "job",
							Value: "",
							Usage: "Used to target a specific job to download artifacts from",
						},
						cli.StringFlag{
							Name:   "build",
							Value:  "",
							Usage:  "Which build should the artifacts be downloaded from",
							EnvVar: "BUILDKITE_BUILD_ID",
						},
						cli.StringFlag{
							Name:   "agent-access-token",
							Value:  "",
							Usage:  "The access token used to identify the agent",
							EnvVar: "BUILDKITE_AGENT_ACCESS_TOKEN",
						},
						cli.StringFlag{
							Name:   "endpoint",
							Value:  "https://agent.buildkite.com/v2",
							Usage:  "The agent API endpoint",
							EnvVar: "BUILDKITE_AGENT_ENDPOINT",
						},
						cli.BoolFlag{
							Name:   "debug",
							Usage:  "Enable debug mode",
							EnvVar: "BUILDKITE_AGENT_DEBUG",
						},
						cli.BoolFlag{
							Name:   "no-color",
							Usage:  "Don't show colors in logging",
							EnvVar: "BUILDKITE_AGENT_NO_COLOR",
						},
					},
					Action: command.ArtifactDownloadCommandAction,
				},
				{
					Name:        "upload",
					Usage:       "Uploads files to a job as artifacts.",
					Description: UploadHelpDescription,
					Flags: []cli.Flag{
						cli.StringFlag{
							Name:   "job",
							Value:  "",
							Usage:  "Which job should the artifacts be uploaded to",
							EnvVar: "BUILDKITE_JOB_ID",
						},
						cli.StringFlag{
							Name:   "agent-access-token",
							Value:  "",
							Usage:  "The access token used to identify the agent",
							EnvVar: "BUILDKITE_AGENT_ACCESS_TOKEN",
						},
						cli.StringFlag{
							Name:   "endpoint",
							Value:  "https://agent.buildkite.com/v2",
							Usage:  "The agent API endpoint",
							EnvVar: "BUILDKITE_AGENT_ENDPOINT",
						},
						cli.BoolFlag{
							Name:   "debug",
							Usage:  "Enable debug mode",
							EnvVar: "BUILDKITE_AGENT_DEBUG",
						},
						cli.BoolFlag{
							Name:   "no-color",
							Usage:  "Don't show colors in logging",
							EnvVar: "BUILDKITE_AGENT_NO_COLOR",
						},
					},
					Action: command.ArtifactUploadCommandAction,
				},
			},
		},
		{
			Name:  "meta-data",
			Usage: "Get/set data from Buildkite jobs",
			Subcommands: []cli.Command{
				{
					Name:        "set",
					Usage:       "Set data on a build",
					Description: SetHelpDescription,
					Flags: []cli.Flag{
						cli.StringFlag{
							Name:   "job",
							Value:  "",
							Usage:  "Which job should the artifacts be downloaded from",
							EnvVar: "BUILDKITE_JOB_ID",
						},
						cli.StringFlag{
							Name:   "agent-access-token",
							Value:  "",
							Usage:  "The access token used to identify the agent",
							EnvVar: "BUILDKITE_AGENT_ACCESS_TOKEN",
						},
						cli.StringFlag{
							Name:   "endpoint",
							Value:  "https://agent.buildkite.com/v2",
							Usage:  "The agent API endpoint",
							EnvVar: "BUILDKITE_AGENT_ENDPOINT",
						},
						cli.BoolFlag{
							Name:   "debug",
							Usage:  "Enable debug mode",
							EnvVar: "BUILDKITE_AGENT_DEBUG",
						},
						cli.BoolFlag{
							Name:   "no-color",
							Usage:  "Don't show colors in logging",
							EnvVar: "BUILDKITE_AGENT_NO_COLOR",
						},
					},
					Action: command.DataSetCommandAction,
				},
				{
					Name:        "get",
					Usage:       "Get data from a build",
					Description: GetHelpDescription,
					Flags: []cli.Flag{
						cli.StringFlag{
							Name:   "job",
							Value:  "",
							Usage:  "Which job should the data be retrieved from",
							EnvVar: "BUILDKITE_JOB_ID",
						},
						cli.StringFlag{
							Name:   "agent-access-token",
							Value:  "",
							Usage:  "The access token used to identify the agent",
							EnvVar: "BUILDKITE_AGENT_ACCESS_TOKEN",
						},
						cli.StringFlag{
							Name:   "endpoint",
							Value:  "https://agent.buildkite.com/v2",
							Usage:  "The agent API endpoint",
							EnvVar: "BUILDKITE_AGENT_ENDPOINT",
						},
						cli.BoolFlag{
							Name:   "debug",
							Usage:  "Enable debug mode",
							EnvVar: "BUILDKITE_AGENT_DEBUG",
						},
						cli.BoolFlag{
							Name:   "no-color",
							Usage:  "Don't show colors in logging",
							EnvVar: "BUILDKITE_AGENT_NO_COLOR",
						},
					},
					Action: command.DataGetCommandAction,
				},
			},
		},
	}
}
<|endoftext|>


<commit_before>package tusd

import (
	"io"
)

type MetaData map[string]string

type FileInfo struct {
	ID string
	// Total file size in bytes specified in the NewUpload call
	Size int64
	// Offset in bytes (zero-based)
	Offset   int64
	MetaData MetaData
	// Indicates that this is a partial upload which will later be used to form
	// a final upload by concatenation. Partial uploads should not be processed
	// when they are finished since they are only incomplete chunks of files.
	IsPartial bool
	// Indicates that this is a final upload
	IsFinal bool
	// If the upload is a final one (see IsFinal) this will be a non-empty
	// ordered slice containing the ids of the uploads of which the final upload
	// will consist after concatenation.
	PartialUploads []string
}

type DataStore interface {
	// Create a new upload using the size as the file's length. The method must
	// return an unique id which is used to identify the upload. If no backend
	// (e.g. Riak) specifes the id you may want to use the uid package to
	// generate one. The properties Size and MetaData will be filled.
	NewUpload(info FileInfo) (id string, err error)
	// Write the chunk read from src into the file specified by the id at the
	// given offset. The handler will take care of validating the offset and
	// limiting the size of the src to not overflow the file's size. It may
	// return an os.ErrNotExist which will be interpreted as a 404 Not Found.
	// It will also lock resources while they are written to ensure only one
	// write happens per time.
	// The function call must return the number of bytes written.
	WriteChunk(id string, offset int64, src io.Reader) (int64, error)
	// Read the fileinformation used to validate the offset and respond to HEAD
	// requests. It may return an os.ErrNotExist which will be interpreted as a
	// 404 Not Found.
	GetInfo(id string) (FileInfo, error)
	// Get an io.Reader to allow downloading the file. This feature is not
	// part of the official tus specification. If this additional function
	// should not be enabled any call to GetReader should return
	// tusd.ErrNotImplemented. The length of the resource is determined by
	// retrieving the offset using GetInfo.
	// If the returned reader also implements the io.Closer interface, the
	// Close() method will be invoked once everything has been read.
	GetReader(id string) (io.Reader, error)
}

// TerminaterDataStore is the interface which must be implemented by DataStores
// if they want to receive DELETE requests using the Handler. If this interface
// is not implemented, no request handler for this method is attached.
type TerminaterDataStore interface {
	DataStore

	// Terminate an upload so any further requests to the resource, both reading
	// and writing, must return os.ErrNotExist or similar.
	Terminate(id string) error
}

type FinisherDataStore interface {
	DataStore

	FinishUpload(id string) error
}

// LockerDataStore is the interface required for custom lock persisting mechanisms.
// Common ways to store this information is in memory, on disk or using an
// external service, such as ZooKeeper.
// When multiple processes are attempting to access an upload, whether it be
// by reading or writing, a syncronization mechanism is required to prevent
// data corruption, especially to ensure correct offset values and the proper
// order of chunks inside a single upload.
type LockerDataStore interface {
	DataStore

	// LockUpload attempts to obtain an exclusive lock for the upload specified
	// by its id.
	// If this operation fails because the resource is already locked, the
	// tusd.ErrFileLocked must be returned. If no error is returned, the attempt
	// is consider to be successful and the upload to be locked until UnlockUpload
	// is invoked for the same upload.
	LockUpload(id string) error
	// UnlockUpload releases an existing lock for the given upload.
	UnlockUpload(id string) error
}
<commit_msg>Add documentation for FinisherDataStore<commit_after>package tusd

import (
	"io"
)

type MetaData map[string]string

type FileInfo struct {
	ID string
	// Total file size in bytes specified in the NewUpload call
	Size int64
	// Offset in bytes (zero-based)
	Offset   int64
	MetaData MetaData
	// Indicates that this is a partial upload which will later be used to form
	// a final upload by concatenation. Partial uploads should not be processed
	// when they are finished since they are only incomplete chunks of files.
	IsPartial bool
	// Indicates that this is a final upload
	IsFinal bool
	// If the upload is a final one (see IsFinal) this will be a non-empty
	// ordered slice containing the ids of the uploads of which the final upload
	// will consist after concatenation.
	PartialUploads []string
}

type DataStore interface {
	// Create a new upload using the size as the file's length. The method must
	// return an unique id which is used to identify the upload. If no backend
	// (e.g. Riak) specifes the id you may want to use the uid package to
	// generate one. The properties Size and MetaData will be filled.
	NewUpload(info FileInfo) (id string, err error)
	// Write the chunk read from src into the file specified by the id at the
	// given offset. The handler will take care of validating the offset and
	// limiting the size of the src to not overflow the file's size. It may
	// return an os.ErrNotExist which will be interpreted as a 404 Not Found.
	// It will also lock resources while they are written to ensure only one
	// write happens per time.
	// The function call must return the number of bytes written.
	WriteChunk(id string, offset int64, src io.Reader) (int64, error)
	// Read the fileinformation used to validate the offset and respond to HEAD
	// requests. It may return an os.ErrNotExist which will be interpreted as a
	// 404 Not Found.
	GetInfo(id string) (FileInfo, error)
	// Get an io.Reader to allow downloading the file. This feature is not
	// part of the official tus specification. If this additional function
	// should not be enabled any call to GetReader should return
	// tusd.ErrNotImplemented. The length of the resource is determined by
	// retrieving the offset using GetInfo.
	// If the returned reader also implements the io.Closer interface, the
	// Close() method will be invoked once everything has been read.
	GetReader(id string) (io.Reader, error)
}

// TerminaterDataStore is the interface which must be implemented by DataStores
// if they want to receive DELETE requests using the Handler. If this interface
// is not implemented, no request handler for this method is attached.
type TerminaterDataStore interface {
	DataStore

	// Terminate an upload so any further requests to the resource, both reading
	// and writing, must return os.ErrNotExist or similar.
	Terminate(id string) error
}

// FinisherDataStore is the interface which can be implemented by DataStores
// which need to do additional operations once an entire upload has been
// completed. These tasks may include but are not limited to freeing unused
// resources or notifying other services. For example, S3Store uses this
// interface for removing a temporary object.
type FinisherDataStore interface {
	DataStore

	// FinishUpload executes additional operations for the finished upload which
	// is specified by its ID.
	FinishUpload(id string) error
}

// LockerDataStore is the interface required for custom lock persisting mechanisms.
// Common ways to store this information is in memory, on disk or using an
// external service, such as ZooKeeper.
// When multiple processes are attempting to access an upload, whether it be
// by reading or writing, a syncronization mechanism is required to prevent
// data corruption, especially to ensure correct offset values and the proper
// order of chunks inside a single upload.
type LockerDataStore interface {
	DataStore

	// LockUpload attempts to obtain an exclusive lock for the upload specified
	// by its id.
	// If this operation fails because the resource is already locked, the
	// tusd.ErrFileLocked must be returned. If no error is returned, the attempt
	// is consider to be successful and the upload to be locked until UnlockUpload
	// is invoked for the same upload.
	LockUpload(id string) error
	// UnlockUpload releases an existing lock for the given upload.
	UnlockUpload(id string) error
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"
	"net/url"
	"os"
	"path"
	"path/filepath"
)

type Mount struct {
	baseDir string
}

func (m *Mount) realPath(u *url.URL) string {
	return filepath.Join(m.baseDir, filepath.FromSlash(u.Path))
}

func (m *Mount) InfoFromURL(u *url.URL) (os.FileInfo, error) {
	return os.Stat(m.realPath(u))
}

func (m *Mount) OpenReadFile(u *url.URL) (*os.File, error) {
	return os.Open(m.realPath(u))
}

func (m *Mount) ReadDir(u *url.URL) ([]os.FileInfo, error) {
	f, err := os.Open(m.realPath(u))
	if err != nil {
		return nil, err
	}
	defer f.Close()
	return f.Readdir(-1)
}

type RawFS struct {
	mount    *Mount
	metaBase string
}

func (r *RawFS) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	info, err := r.mount.InfoFromURL(req.URL)
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}
	if info.IsDir() {
		r.serveDir(w, req, info)
	} else {
		r.serveFile(w, req, info)
	}
}

func (r *RawFS) serveDir(w http.ResponseWriter, req *http.Request, info os.FileInfo) {
	childs, err := r.mount.ReadDir(req.URL)
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}
	fmt.Fprintf(w,
		`<!doctype html>

	<title>Listing directory: %v</title>

Listing directory: %v

`,
		info.Name(),
		info.Name())

	for _, child := range childs {
		fmt.Fprintf(w, `<li><a href="%v">%v</a> <a href="%v">Stat</a></li>`,
			"./"+child.Name(), child.Name(), r.metaForChild(child.Name(), req.URL))
	}

	fmt.Fprintf(w,
		`

`)
}

func (r *RawFS) metaForChild(name string, parent *url.URL) *url.URL {
	u := parent.ResolveReference(&url.URL{})
	u.Path = path.Join(r.metaBase, u.Path, name)
	return u
}

func (r *RawFS) serveFile(w http.ResponseWriter, req *http.Request, info os.FileInfo) {
	if req.Method != "GET" {
		http.Error(w, "Only GET at this moment", http.StatusMethodNotAllowed)
		return
	}
	rw, err := r.mount.OpenReadFile(req.URL)
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}
	defer rw.Close()

	http.ServeContent(w, req, info.Name(), info.ModTime(), rw)
}

type MetaFS struct {
	mount   *Mount
	rawBase string
}

func (m *MetaFS) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	info, err := m.mount.InfoFromURL(req.URL)
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}

	m.printAsHtml(w, req, info)
}

// Return the raw url representing this file
func (m *MetaFS) rawURLFor(meta *url.URL) *url.URL {
	u := meta.ResolveReference(&url.URL{})
	u.Path = path.Join(m.rawBase, meta.Path)
	return u
}

func (m *MetaFS) printAsHtml(w http.ResponseWriter, req *http.Request, info os.FileInfo) {
	rawUrl := m.rawURLFor(req.URL)

	fmt.Fprintf(w,
		`<!doctype html>

	<title>Info about: %v</title>

Name

%v

Directory?

%v

Size

%d

Mod time

%v

Raw url
%v</href>

`,
		req.URL.Path,
		info.Name(),
		info.IsDir(),
		info.Size(),
		info.ModTime(),
		rawUrl,
		info.Name())
}

var (
	addr    = flag.String("addr", "0.0.0.0:9091", "Address to listen for clients")
	baseDir = flag.String("baseDir", ".", "Base dir to serve the content")
)

func index(w http.ResponseWriter, req *http.Request) {
	fmt.Fprintf(w,
		`<!doctype html>

	<title>Root dir</title>

Meta

./meta/

Raw

./raw/

`)
}

func main() {

	m := &Mount{baseDir: *baseDir}
	metafs := &MetaFS{mount: m, rawBase: "/raw"}
	rawfs := &RawFS{mount: m, metaBase: "/meta"}

	http.HandleFunc("/", index)
	http.Handle("/meta/", http.StripPrefix("/meta/", metafs))
	http.Handle("/raw/", http.StripPrefix("/raw/", rawfs))

	log.Printf("Starting davd server at %v", *addr)
	err := http.ListenAndServe(*addr, nil)
	http.ListenAndServe(*addr, nil)
	if err != nil {
		log.Printf("Error opening server: %v", err)
	}
}
<commit_msg>initial work on POST/PUT<commit_after>package main

import (
	"flag"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/url"
	"os"
	"path"
	"path/filepath"
)

type Mount struct {
	baseDir string
}

func (m *Mount) realPath(u *url.URL) string {
	return filepath.Join(m.baseDir, filepath.FromSlash(u.Path))
}

func (m *Mount) InfoFromURL(u *url.URL) (os.FileInfo, error) {
	return os.Stat(m.realPath(u))
}

func (m *Mount) OpenReadFile(u *url.URL) (*os.File, error) {
	return os.Open(m.realPath(u))
}

func (m *Mount) ReadDir(u *url.URL) ([]os.FileInfo, error) {
	f, err := os.Open(m.realPath(u))
	if err != nil {
		return nil, err
	}
	defer f.Close()
	return f.Readdir(-1)
}

func (m *Mount) CreateOrOpenFileForWrite(u *url.URL) (*os.File, error) {
	rp := m.realPath(u)
	stat, err := os.Stat(rp)
	if os.IsNotExist(err) {
		// new file
		d := filepath.Dir(rp)
		err = os.MkdirAll(d, 0644)
		if err != nil {
			return nil, err
		}

		return os.OpenFile(rp, os.O_CREATE, 0644)
	}
	if err != nil {
		return nil, err
	}
	if stat.IsDir() {
		return nil, fmt.Errorf("%v is a directory", u.Path)
	}
	return os.OpenFile(rp, os.O_RDWR, 0644)
}

type RawFS struct {
	mount    *Mount
	metaBase string
}

func (r *RawFS) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	info, err := r.mount.InfoFromURL(req.URL)
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}
	if info.IsDir() {
		r.serveDir(w, req, info)
	} else {
		r.serveFile(w, req, info)
	}
}

func (r *RawFS) serveDir(w http.ResponseWriter, req *http.Request, info os.FileInfo) {
	childs, err := r.mount.ReadDir(req.URL)
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}
	fmt.Fprintf(w,
		`<!doctype html>

	<title>Listing directory: %v</title>

Listing directory: %v

`,
		info.Name(),
		info.Name())

	for _, child := range childs {
		fmt.Fprintf(w, `<li><a href="%v">%v</a> <a href="%v">Stat</a></li>`,
			"./"+child.Name(), child.Name(), r.metaForChild(child.Name(), req.URL))
	}

	fmt.Fprintf(w,
		`

`)
}

func (r *RawFS) metaForChild(name string, parent *url.URL) *url.URL {
	u := parent.ResolveReference(&url.URL{})
	u.Path = path.Join(r.metaBase, u.Path, name)
	return u
}

func (r *RawFS) serveFile(w http.ResponseWriter, req *http.Request, info os.FileInfo) {
	switch req.Method {
	case "GET":
		r.serveGetFile(w, req, info)
	case "POST", "PUT":
		r.servePostFile(w, req, info)
	default:
		if req.Method != "GET" {
			http.Error(w, "Only GET/POST/PUT at this moment", http.StatusMethodNotAllowed)
			return
		}
	}
}

func (r *RawFS) servePostFile(w http.ResponseWriter, req *http.Request, info os.FileInfo) {
	http.Error(w, "Not implemented yet!", 500)
	return
	file, err := r.mount.CreateOrOpenFileForWrite(req.URL)
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}
	defer file.Close()
	_, err = io.Copy(file, req.Body)
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}
}

func (r *RawFS) serveGetFile(w http.ResponseWriter, req *http.Request, info os.FileInfo) {
	rw, err := r.mount.OpenReadFile(req.URL)
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}
	defer rw.Close()

	http.ServeContent(w, req, info.Name(), info.ModTime(), rw)
}

type MetaFS struct {
	mount   *Mount
	rawBase string
}

func (m *MetaFS) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	info, err := m.mount.InfoFromURL(req.URL)
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}

	m.printAsHtml(w, req, info)
}

// Return the raw url representing this file
func (m *MetaFS) rawURLFor(meta *url.URL) *url.URL {
	u := meta.ResolveReference(&url.URL{})
	u.Path = path.Join(m.rawBase, meta.Path)
	return u
}

func (m *MetaFS) printAsHtml(w http.ResponseWriter, req *http.Request, info os.FileInfo) {
	rawUrl := m.rawURLFor(req.URL)

	fmt.Fprintf(w,
		`<!doctype html>

	<title>Info about: %v</title>

Name

%v

Directory?

%v

Size

%d

Mod time

%v

Raw url
%v</href>

`,
		req.URL.Path,
		info.Name(),
		info.IsDir(),
		info.Size(),
		info.ModTime(),
		rawUrl,
		info.Name())
}

var (
	addr    = flag.String("addr", "0.0.0.0:9091", "Address to listen for clients")
	baseDir = flag.String("baseDir", ".", "Base dir to serve the content")
)

func index(w http.ResponseWriter, req *http.Request) {
	fmt.Fprintf(w,
		`<!doctype html>

	<title>Root dir</title>

Meta

./meta/

Raw

./raw/

`)
}

func main() {

	m := &Mount{baseDir: *baseDir}
	metafs := &MetaFS{mount: m, rawBase: "/raw"}
	rawfs := &RawFS{mount: m, metaBase: "/meta"}

	http.HandleFunc("/", index)
	http.Handle("/meta/", http.StripPrefix("/meta/", metafs))
	http.Handle("/raw/", http.StripPrefix("/raw/", rawfs))

	log.Printf("Starting davd server at %v", *addr)
	err := http.ListenAndServe(*addr, nil)
	http.ListenAndServe(*addr, nil)
	if err != nil {
		log.Printf("Error opening server: %v", err)
	}
}
<|endoftext|>


<commit_before>package smtpd

import (
	"crypto/tls"
	"fmt"
	"strings"
	"time"
)

// Envelope holds a message
type Envelope struct {
	Sender     string
	Recipients []string
	Data       []byte
}

// AddReceivedLine prepends a Received header to the Data
func (env *Envelope) AddReceivedLine(peer Peer) {

	tlsDetails := ""

	tlsVersions := map[uint16]string{
		tls.VersionSSL30: "SSL3.0",
		tls.VersionTLS10: "TLS1.0",
		tls.VersionTLS11: "TLS1.1",
		tls.VersionTLS12: "TLS1.2",
	}

	if peer.TLS != nil {
		tlsDetails = fmt.Sprintf(
			"\r\n\t(version=%s cipher=0x%x);",
			tlsVersions[peer.TLS.Version],
			peer.TLS.CipherSuite,
		)
	}

	line := wrap([]byte(fmt.Sprintf(
		"Received: from %s [%s] by %s with %s;%s\r\n\t%s\r\n",
		peer.HeloName,
		strings.Split(peer.Addr.String(), ":")[0],
		peer.ServerName,
		peer.Protocol,
		tlsDetails,
		time.Now().Format("Mon Jan 2 15:04:05 -0700 2006"),
	)))

	env.Data = append(env.Data, line...)

	// Move the new Received line up front

	copy(env.Data[len(line):], env.Data[0:len(env.Data)-len(line)])
	copy(env.Data, line)

}
<commit_msg>Fix client IP in Received line for IPv6 IP addresses<commit_after>package smtpd

import (
	"crypto/tls"
	"fmt"
	"net"
	"time"
)

// Envelope holds a message
type Envelope struct {
	Sender     string
	Recipients []string
	Data       []byte
}

// AddReceivedLine prepends a Received header to the Data
func (env *Envelope) AddReceivedLine(peer Peer) {

	tlsDetails := ""

	tlsVersions := map[uint16]string{
		tls.VersionSSL30: "SSL3.0",
		tls.VersionTLS10: "TLS1.0",
		tls.VersionTLS11: "TLS1.1",
		tls.VersionTLS12: "TLS1.2",
	}

	if peer.TLS != nil {
		tlsDetails = fmt.Sprintf(
			"\r\n\t(version=%s cipher=0x%x);",
			tlsVersions[peer.TLS.Version],
			peer.TLS.CipherSuite,
		)
	}

	peerIP := ""
	if addr, ok := peer.Addr.(*net.TCPAddr); ok {
		peerIP = addr.IP.String()
	}

	line := wrap([]byte(fmt.Sprintf(
		"Received: from %s [%s] by %s with %s;%s\r\n\t%s\r\n",
		peer.HeloName,
		peerIP,
		peer.ServerName,
		peer.Protocol,
		tlsDetails,
		time.Now().Format("Mon Jan 2 15:04:05 -0700 2006"),
	)))

	env.Data = append(env.Data, line...)

	// Move the new Received line up front

	copy(env.Data[len(line):], env.Data[0:len(env.Data)-len(line)])
	copy(env.Data, line)

}
<|endoftext|>


<commit_before>package cmd

import (
	"errors"
	"fmt"
	"net/http"
	"os"
	"path/filepath"

	"github.com/cashshuffle/cashshuffle/server"
	"golang.org/x/crypto/acme/autocert"

	"github.com/spf13/cobra"
)

const (
	appName         = "cashshuffle"
	version         = "0.3.1"
	defaultPort     = 8080
	defaultPoolSize = 5
)

// Stores configuration data.
var config Config

// MainCmd is the main command for Cobra.
var MainCmd = &cobra.Command{
	Use:   "cashshuffle",
	Short: "CashShuffle server.",
	Long:  `CashShuffle server.`,
	Run: func(cmd *cobra.Command, args []string) {
		err := performCommand(cmd, args)
		if err != nil {
			bail(err)
		}
	},
}

func init() {
	err := config.Load()
	if err != nil {
		bail(fmt.Errorf("Failed to load configuration: %s", err))
	}

	prepareFlags()
}

func bail(err error) {
	fmt.Fprintf(os.Stderr, "[Error] %s\n", err)
	os.Exit(1)
}

func prepareFlags() {
	if config.Port == 0 {
		config.Port = defaultPort
	}

	if config.PoolSize == 0 {
		config.PoolSize = defaultPoolSize
	}

	MainCmd.PersistentFlags().StringVarP(
		&config.Cert, "cert", "c", config.Cert, "path to server.crt for TLS")
	MainCmd.PersistentFlags().StringVarP(
		&config.Key, "key", "k", config.Key, "path to server.key for TLS")
	MainCmd.PersistentFlags().BoolVarP(
		&config.DisplayVersion, "version", "v", false, "display version")
	MainCmd.PersistentFlags().IntVarP(
		&config.Port, "port", "p", config.Port, "server port")
	MainCmd.PersistentFlags().IntVarP(
		&config.StatsPort, "stats-port", "z", config.StatsPort, "stats server port (default disabled)")
	MainCmd.PersistentFlags().IntVarP(
		&config.PoolSize, "pool-size", "s", config.PoolSize, "pool size")
	MainCmd.PersistentFlags().BoolVarP(
		&config.Debug, "debug", "d", config.Debug, "debug mode")
	MainCmd.PersistentFlags().StringVarP(
		&config.AutoCert, "auto-cert", "a", config.AutoCert, "register hostname with LetsEncrypt")
}

// Where all the work happens.
func performCommand(cmd *cobra.Command, args []string) error {
	if config.DisplayVersion {
		fmt.Printf("%s %s\n", appName, version)
		return nil
	}

	if config.AutoCert != "" && (config.Cert != "" || config.Key != "") {
		return errors.New("can't specify auto-cert and key/cert")
	}

	t := server.NewTracker(config.PoolSize, config.Port)

	m, err := getLetsEncryptManager()
	if err != nil {
		return err
	}

	// enable stats if port specified
	if config.StatsPort > 0 {
		go server.StartStatsServer(config.StatsPort, config.Cert, config.Key, t, m)
	}

	return server.Start(config.Port, config.Cert, config.Key, config.Debug, t, m)
}

func getLetsEncryptManager() (*autocert.Manager, error) {
	configDir, err := config.configDir()
	if err != nil {
		return nil, err
	}

	certDir := filepath.Join(configDir, "certs")
	if _, err := os.Stat(certDir); os.IsNotExist(err) {
		err = os.MkdirAll(certDir, 0755)
		if err != nil {
			return nil, err
		}
	}

	if config.AutoCert == "" {
		return nil, nil
	}

	m := &autocert.Manager{
		Cache:      autocert.DirCache(certDir),
		Prompt:     autocert.AcceptTOS,
		HostPolicy: autocert.HostWhitelist(config.AutoCert),
	}

	go http.ListenAndServe(":http", m.HTTPHandler(nil))

	return m, nil
}
<commit_msg>Bump version to 0.3.2<commit_after>package cmd

import (
	"errors"
	"fmt"
	"net/http"
	"os"
	"path/filepath"

	"github.com/cashshuffle/cashshuffle/server"
	"golang.org/x/crypto/acme/autocert"

	"github.com/spf13/cobra"
)

const (
	appName         = "cashshuffle"
	version         = "0.3.2"
	defaultPort     = 8080
	defaultPoolSize = 5
)

// Stores configuration data.
var config Config

// MainCmd is the main command for Cobra.
var MainCmd = &cobra.Command{
	Use:   "cashshuffle",
	Short: "CashShuffle server.",
	Long:  `CashShuffle server.`,
	Run: func(cmd *cobra.Command, args []string) {
		err := performCommand(cmd, args)
		if err != nil {
			bail(err)
		}
	},
}

func init() {
	err := config.Load()
	if err != nil {
		bail(fmt.Errorf("Failed to load configuration: %s", err))
	}

	prepareFlags()
}

func bail(err error) {
	fmt.Fprintf(os.Stderr, "[Error] %s\n", err)
	os.Exit(1)
}

func prepareFlags() {
	if config.Port == 0 {
		config.Port = defaultPort
	}

	if config.PoolSize == 0 {
		config.PoolSize = defaultPoolSize
	}

	MainCmd.PersistentFlags().StringVarP(
		&config.Cert, "cert", "c", config.Cert, "path to server.crt for TLS")
	MainCmd.PersistentFlags().StringVarP(
		&config.Key, "key", "k", config.Key, "path to server.key for TLS")
	MainCmd.PersistentFlags().BoolVarP(
		&config.DisplayVersion, "version", "v", false, "display version")
	MainCmd.PersistentFlags().IntVarP(
		&config.Port, "port", "p", config.Port, "server port")
	MainCmd.PersistentFlags().IntVarP(
		&config.StatsPort, "stats-port", "z", config.StatsPort, "stats server port (default disabled)")
	MainCmd.PersistentFlags().IntVarP(
		&config.PoolSize, "pool-size", "s", config.PoolSize, "pool size")
	MainCmd.PersistentFlags().BoolVarP(
		&config.Debug, "debug", "d", config.Debug, "debug mode")
	MainCmd.PersistentFlags().StringVarP(
		&config.AutoCert, "auto-cert", "a", config.AutoCert, "register hostname with LetsEncrypt")
}

// Where all the work happens.
func performCommand(cmd *cobra.Command, args []string) error {
	if config.DisplayVersion {
		fmt.Printf("%s %s\n", appName, version)
		return nil
	}

	if config.AutoCert != "" && (config.Cert != "" || config.Key != "") {
		return errors.New("can't specify auto-cert and key/cert")
	}

	t := server.NewTracker(config.PoolSize, config.Port)

	m, err := getLetsEncryptManager()
	if err != nil {
		return err
	}

	// enable stats if port specified
	if config.StatsPort > 0 {
		go server.StartStatsServer(config.StatsPort, config.Cert, config.Key, t, m)
	}

	return server.Start(config.Port, config.Cert, config.Key, config.Debug, t, m)
}

func getLetsEncryptManager() (*autocert.Manager, error) {
	configDir, err := config.configDir()
	if err != nil {
		return nil, err
	}

	certDir := filepath.Join(configDir, "certs")
	if _, err := os.Stat(certDir); os.IsNotExist(err) {
		err = os.MkdirAll(certDir, 0755)
		if err != nil {
			return nil, err
		}
	}

	if config.AutoCert == "" {
		return nil, nil
	}

	m := &autocert.Manager{
		Cache:      autocert.DirCache(certDir),
		Prompt:     autocert.AcceptTOS,
		HostPolicy: autocert.HostWhitelist(config.AutoCert),
	}

	go http.ListenAndServe(":http", m.HTTPHandler(nil))

	return m, nil
}
<|endoftext|>


<commit_before>package cmd

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"strings"

	"github.com/driusan/dgit/git"
)

func Push(c *git.Client, args []string) error {
	flags := flag.NewFlagSet("branch", flag.ExitOnError)
	flags.SetOutput(flag.CommandLine.Output())
	flags.Usage = func() {
		flag.Usage()
		fmt.Fprintf(flag.CommandLine.Output(), "\n\nOptions:\n")
		flags.PrintDefaults()
	}

	// These flags can be moved out of these lists and below as proper flags as they are implemented
	for _, bf := range []string{"all", "mirror", "tags", "follow-tags", "atomic", "n", "dry-run", "f", "force", "delete", "prune", "v", "verbose", "u", "no-signed", "no-verify"} {
		flags.Var(newNotimplBoolValue(), bf, "Not implemented")
	}
	for _, sf := range []string{"receive-pack", "repo", "o", "push-option", "signed", "force-with-lease"} {
		flags.Var(newNotimplStringValue(), sf, "Not implemented")
	}

	setupstream := flags.String("set-upstream", "", "Sets the upstream remote for the branch")

	flags.Parse(args)

	if flags.NArg() < 1 {
		fmt.Fprintf(flag.CommandLine.Output(), "Missing repository to push")
		flag.Usage()
		os.Exit(2)
	} else if flags.NArg() > 1 {
		fmt.Fprintf(flag.CommandLine.Output(), "Providing a refspec is not currently implemented")
		flag.Usage()
		os.Exit(2)
	}

	bname := flags.Arg(0)
	config, err := git.LoadLocalConfig(c)
	if err != nil {
		return err
	}
	if *setupstream != "" {
		config.SetConfig(fmt.Sprintf("branch.%v.remote", bname), *setupstream)
		config.SetConfig(fmt.Sprintf("branch.%v.merge", bname), fmt.Sprintf("refs/heads/%v", bname))
		if err := config.WriteConfig(); err != nil {
			return err
		}
	}
	remote, _ := config.GetConfig("branch." + bname + ".remote")
	if remote == "" {
		return fmt.Errorf(`The branch %v has no upstream set.
To push and set the upstream to the remote named "origin" use:

	%v push --set-upstream origin %v

`, bname, os.Args[0], bname)

	}
	mergebranch, _ := config.GetConfig("branch." + bname + ".merge")
	mergebranch = strings.TrimSpace(mergebranch)
	repoid, _ := config.GetConfig("remote." + remote + ".url")
	println(remote, " on ", repoid)
	var ups git.Uploadpack
	if repoid[0:7] == "http://" || repoid[0:8] == "https://" {
		ups = &git.SmartHTTPServerRetriever{Location: repoid,
			C: c,
		}
	} else {
		return fmt.Errorf("Unknown protocol.")
	}

	refs, err := ups.NegotiateSendPack()
	if err != nil {
		return err
	}

	localSha, _, err := RevParse(c, []string{flags.Arg(0)})
	if err != nil {
		return err
	}
	var remoteCommits []git.Commitish
	var remoteHead git.CommitID
	for _, ref := range refs {
		trimmed := ref.Refname.String()
		refsha, err := git.Sha1FromString(ref.Sha1)
		if err != nil {
			return err
		}
		if trimmed == mergebranch {
			remoteHead = git.CommitID(refsha)
		}
		if have, _, err := c.HaveObject(refsha); have && err == nil {
			remoteCommits = append(remoteCommits, git.CommitID(refsha))
		}
	}
	var objects strings.Builder
	if _, err := git.RevList(c, git.RevListOptions{Objects: true}, &objects, []git.Commitish{localSha[0]}, remoteCommits); err != nil {
		return err
	}

	f, err := ioutil.TempFile("", "sendpack")
	if err != nil {
		panic(err)
	}
	os.Remove(f.Name())
	fmt.Fprintf(f, objects.String())

	PackObjects(c, strings.NewReader(objects.String()), []string{f.Name()})
	f, err = os.Open(f.Name() + ".pack")
	if err != nil {
		return err
	}
	defer os.Remove(f.Name())
	stat, err := f.Stat()
	if err != nil {
		return err
	}
	ups.SendPack(git.UpdateReference{
		LocalSha1:  localSha[0].Id.String(),
		RemoteSha1: remoteHead.String(),
		Refname:    git.RefSpec(mergebranch),
	}, f, stat.Size())

	// We don't do anything special for setupstream here, because it was saved above
	if rmtname := c.GetConfig(fmt.Sprintf("branch.%v.remote", bname)); rmtname != "" {
		rmtref := git.RefSpec(fmt.Sprintf("refs/remotes/%v/%v", rmtname, bname))
		if git.UpdateRefSpec(c, git.UpdateRefOptions{}, rmtref, git.CommitID(localSha[0].Id), "update by push"); err != nil {
			return err
		}
	}
	return nil
}
<commit_msg>Fix push (#270)<commit_after>package cmd

import (
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"strings"

	"github.com/driusan/dgit/git"
)

func Push(c *git.Client, args []string) error {
	flags := flag.NewFlagSet("branch", flag.ExitOnError)
	flags.SetOutput(flag.CommandLine.Output())
	flags.Usage = func() {
		flag.Usage()
		fmt.Fprintf(flag.CommandLine.Output(), "\n\nOptions:\n")
		flags.PrintDefaults()
	}

	// These flags can be moved out of these lists and below as proper flags as they are implemented
	for _, bf := range []string{"all", "mirror", "tags", "follow-tags", "atomic", "n", "dry-run", "f", "force", "delete", "prune", "v", "verbose", "u", "no-signed", "no-verify"} {
		flags.Var(newNotimplBoolValue(), bf, "Not implemented")
	}
	for _, sf := range []string{"receive-pack", "repo", "o", "push-option", "signed", "force-with-lease"} {
		flags.Var(newNotimplStringValue(), sf, "Not implemented")
	}

	setupstream := flags.String("set-upstream", "", "Sets the upstream remote for the branch")

	flags.Parse(args)

	if flags.NArg() < 1 {
		fmt.Fprintf(flag.CommandLine.Output(), "Missing repository to push")
		flag.Usage()
		os.Exit(2)
	} else if flags.NArg() > 1 {
		fmt.Fprintf(flag.CommandLine.Output(), "Providing a refspec is not currently implemented")
		flag.Usage()
		os.Exit(2)
	}

	bname := flags.Arg(0)
	config, err := git.LoadLocalConfig(c)
	if err != nil {
		return err
	}
	if *setupstream != "" {
		config.SetConfig(fmt.Sprintf("branch.%v.remote", bname), *setupstream)
		config.SetConfig(fmt.Sprintf("branch.%v.merge", bname), fmt.Sprintf("refs/heads/%v", bname))
		if err := config.WriteConfig(); err != nil {
			return err
		}
	}
	remote, _ := config.GetConfig("branch." + bname + ".remote")
	if remote == "" {
		return fmt.Errorf(`The branch %v has no upstream set.
To push and set the upstream to the remote named "origin" use:

	%v push --set-upstream origin %v

`, bname, os.Args[0], bname)

	}
	mergebranch, _ := config.GetConfig("branch." + bname + ".merge")
	mergebranch = strings.TrimSpace(mergebranch)
	repoid, _ := config.GetConfig("remote." + remote + ".url")
	println(remote, " on ", repoid)
	var ups git.Uploadpack
	if repoid[0:7] == "http://" || repoid[0:8] == "https://" {
		ups = &git.SmartHTTPServerRetriever{Location: repoid,
			C: c,
		}
	} else {
		return fmt.Errorf("Unknown protocol.")
	}

	refs, err := ups.NegotiateSendPack()
	if err != nil {
		return err
	}

	localSha, _, err := RevParse(c, []string{flags.Arg(0)})
	if err != nil {
		return err
	}
	var remoteCommits []git.Commitish
	var remoteHead git.CommitID
	for _, ref := range refs {
		trimmed := ref.Refname.String()
		refsha, err := git.Sha1FromString(ref.Sha1)
		if err != nil {
			return err
		}
		if trimmed == mergebranch {
			remoteHead = git.CommitID(refsha)
		}
		if have, _, err := c.HaveObject(refsha); have && err == nil {
			remoteCommits = append(remoteCommits, git.CommitID(refsha))
		}
	}
	objs, err := git.RevList(c, git.RevListOptions{Objects: true, Quiet: true}, nil, []git.Commitish{localSha[0]}, remoteCommits)
	if err != nil {
		return err
	}

	f, err := ioutil.TempFile("", "dgitpush")
	if err != nil {
		return err
	}
	defer os.Remove(f.Name())
	if _, err := git.PackObjects(c, git.PackObjectsOptions{}, f, objs); err != nil {
		return err
	}
	f.Seek(0, io.SeekStart)
	stat, err := f.Stat()
	if err != nil {
		return err
	}
	ups.SendPack(git.UpdateReference{
		LocalSha1:  localSha[0].Id.String(),
		RemoteSha1: remoteHead.String(),
		Refname:    git.RefSpec(mergebranch),
	}, f, stat.Size())

	// We don't do anything special for setupstream here, because it was saved above
	if rmtname := c.GetConfig(fmt.Sprintf("branch.%v.remote", bname)); rmtname != "" {
		rmtref := git.RefSpec(fmt.Sprintf("refs/remotes/%v/%v", rmtname, bname))
		if git.UpdateRefSpec(c, git.UpdateRefOptions{}, rmtref, git.CommitID(localSha[0].Id), "update by push"); err != nil {
			return err
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package models

import (
	"encoding/json"
	"net/url"
	"regexp"
)

const maximumRouteLength = 4 * 1024

type DomainSet map[string]struct{}

func (set DomainSet) Add(domain string) {
	set[domain] = struct{}{}
}

func (set DomainSet) Each(predicate func(domain string)) {
	for domain := range set {
		predicate(domain)
	}
}

func (set DomainSet) Contains(domain string) bool {
	_, found := set[domain]
	return found
}

type DesiredLRPsByProcessGuid map[string]DesiredLRP

func (set DesiredLRPsByProcessGuid) Add(desired DesiredLRP) {
	set[desired.ProcessGuid] = desired
}

func (set DesiredLRPsByProcessGuid) Each(predicate func(desired DesiredLRP)) {
	for _, desired := range set {
		predicate(desired)
	}
}

type DesiredLRP struct {
	ProcessGuid          string                      `json:"process_guid"`
	Domain               string                      `json:"domain"`
	RootFS               string                      `json:"rootfs"`
	Instances            int                         `json:"instances"`
	EnvironmentVariables []EnvironmentVariable       `json:"env,omitempty"`
	Setup                Action                      `json:"-"`
	Action               Action                      `json:"-"`
	StartTimeout         uint                        `json:"start_timeout"`
	Monitor              Action                      `json:"-"`
	DiskMB               int                         `json:"disk_mb"`
	MemoryMB             int                         `json:"memory_mb"`
	CPUWeight            uint                        `json:"cpu_weight"`
	Privileged           bool                        `json:"privileged"`
	Ports                []uint16                    `json:"ports"`
	Routes               map[string]*json.RawMessage `json:"routes,omitempty"`
	LogSource            string                      `json:"log_source"`
	LogGuid              string                      `json:"log_guid"`
	MetricsGuid          string                      `json:"metrics_guid"`
	Annotation           string                      `json:"annotation,omitempty"`
	EgressRules          []SecurityGroupRule         `json:"egress_rules,omitempty"`
	ModificationTag      ModificationTag             `json:"modification_tag"`
}

type InnerDesiredLRP DesiredLRP

type mDesiredLRP struct {
	SetupRaw   *json.RawMessage `json:"setup,omitempty"`
	ActionRaw  *json.RawMessage `json:"action,omitempty"`
	MonitorRaw *json.RawMessage `json:"monitor,omitempty"`
	*InnerDesiredLRP
}

type DesiredLRPUpdate struct {
	Instances  *int                        `json:"instances,omitempty"`
	Routes     map[string]*json.RawMessage `json:"routes,omitempty"`
	Annotation *string                     `json:"annotation,omitempty"`
}

type DesiredLRPChange struct {
	Before DesiredLRP
	After  DesiredLRP
}

func (desired DesiredLRP) ApplyUpdate(update DesiredLRPUpdate) DesiredLRP {
	if update.Instances != nil {
		desired.Instances = *update.Instances
	}
	if update.Routes != nil {
		desired.Routes = update.Routes
	}
	if update.Annotation != nil {
		desired.Annotation = *update.Annotation
	}
	return desired
}

var processGuidPattern = regexp.MustCompile(`^[a-zA-Z0-9_-]+$`)

func (desired DesiredLRP) Validate() error {
	var validationError ValidationError

	if desired.Domain == "" {
		validationError = validationError.Append(ErrInvalidField{"domain"})
	}

	if !processGuidPattern.MatchString(desired.ProcessGuid) {
		validationError = validationError.Append(ErrInvalidField{"process_guid"})
	}

	if desired.RootFS == "" {
		validationError = validationError.Append(ErrInvalidField{"rootfs"})
	}

	rootFSURL, err := url.Parse(desired.RootFS)
	if err != nil || rootFSURL.Scheme == "" {
		validationError = validationError.Append(ErrInvalidField{"rootfs"})
	}

	if desired.Setup != nil {
		err := desired.Setup.Validate()
		if err != nil {
			validationError = validationError.Append(err)
		}
	}

	if desired.Action == nil {
		validationError = validationError.Append(ErrInvalidActionType)
	} else {
		err := desired.Action.Validate()
		if err != nil {
			validationError = validationError.Append(err)
		}
	}

	if desired.Monitor != nil {
		err := desired.Monitor.Validate()
		if err != nil {
			validationError = validationError.Append(err)
		}
	}

	if desired.Instances < 0 {
		validationError = validationError.Append(ErrInvalidField{"instances"})
	}

	if desired.CPUWeight > 100 {
		validationError = validationError.Append(ErrInvalidField{"cpu_weight"})
	}

	if len(desired.Annotation) > maximumAnnotationLength {
		validationError = validationError.Append(ErrInvalidField{"annotation"})
	}

	totalRoutesLength := 0
	for _, value := range desired.Routes {
		totalRoutesLength += len(*value)
		if totalRoutesLength > maximumRouteLength {
			validationError = validationError.Append(ErrInvalidField{"routes"})
			break
		}
	}

	for _, rule := range desired.EgressRules {
		err := rule.Validate()
		if err != nil {
			validationError = validationError.Append(ErrInvalidField{"egress_rules"})
			validationError = validationError.Append(err)
		}
	}

	if !validationError.Empty() {
		return validationError
	}

	return nil
}

func (desired *DesiredLRP) UnmarshalJSON(payload []byte) error {
	mLRP := &mDesiredLRP{InnerDesiredLRP: (*InnerDesiredLRP)(desired)}
	err := json.Unmarshal(payload, mLRP)
	if err != nil {
		return err
	}

	var a Action
	if mLRP.ActionRaw == nil {
		a = nil
	} else {
		a, err = UnmarshalAction(*mLRP.ActionRaw)
		if err != nil {
			return err
		}
	}
	desired.Action = a

	if mLRP.SetupRaw == nil {
		a = nil
	} else {
		a, err = UnmarshalAction(*mLRP.SetupRaw)
		if err != nil {
			return err
		}
		desired.Setup = a
	}

	if mLRP.MonitorRaw == nil {
		a = nil
	} else {
		a, err = UnmarshalAction(*mLRP.MonitorRaw)
		if err != nil {
			return err
		}
		desired.Monitor = a
	}

	return nil
}

func (desired DesiredLRP) MarshalJSON() ([]byte, error) {
	var setupRaw, actionRaw, monitorRaw *json.RawMessage

	if desired.Action != nil {
		raw, err := MarshalAction(desired.Action)
		if err != nil {
			return nil, err
		}
		rm := json.RawMessage(raw)
		actionRaw = &rm
	}

	if desired.Setup != nil {
		raw, err := MarshalAction(desired.Setup)
		if err != nil {
			return nil, err
		}
		rm := json.RawMessage(raw)
		setupRaw = &rm
	}
	if desired.Monitor != nil {
		raw, err := MarshalAction(desired.Monitor)
		if err != nil {
			return nil, err
		}
		rm := json.RawMessage(raw)
		monitorRaw = &rm
	}

	innerDesiredLRP := InnerDesiredLRP(desired)

	mLRP := &mDesiredLRP{
		SetupRaw:        setupRaw,
		ActionRaw:       actionRaw,
		MonitorRaw:      monitorRaw,
		InnerDesiredLRP: &innerDesiredLRP,
	}

	return json.Marshal(mLRP)
}
<commit_msg>Remove runtime-schema/tasks<commit_after>package models

import (
	"encoding/json"
	"net/url"
	"regexp"
)

const (
	maximumAnnotationLength = 10 * 1024
	maximumRouteLength      = 4 * 1024
)

type DomainSet map[string]struct{}

func (set DomainSet) Add(domain string) {
	set[domain] = struct{}{}
}

func (set DomainSet) Each(predicate func(domain string)) {
	for domain := range set {
		predicate(domain)
	}
}

func (set DomainSet) Contains(domain string) bool {
	_, found := set[domain]
	return found
}

type DesiredLRPsByProcessGuid map[string]DesiredLRP

func (set DesiredLRPsByProcessGuid) Add(desired DesiredLRP) {
	set[desired.ProcessGuid] = desired
}

func (set DesiredLRPsByProcessGuid) Each(predicate func(desired DesiredLRP)) {
	for _, desired := range set {
		predicate(desired)
	}
}

type DesiredLRP struct {
	ProcessGuid          string                      `json:"process_guid"`
	Domain               string                      `json:"domain"`
	RootFS               string                      `json:"rootfs"`
	Instances            int                         `json:"instances"`
	EnvironmentVariables []EnvironmentVariable       `json:"env,omitempty"`
	Setup                Action                      `json:"-"`
	Action               Action                      `json:"-"`
	StartTimeout         uint                        `json:"start_timeout"`
	Monitor              Action                      `json:"-"`
	DiskMB               int                         `json:"disk_mb"`
	MemoryMB             int                         `json:"memory_mb"`
	CPUWeight            uint                        `json:"cpu_weight"`
	Privileged           bool                        `json:"privileged"`
	Ports                []uint16                    `json:"ports"`
	Routes               map[string]*json.RawMessage `json:"routes,omitempty"`
	LogSource            string                      `json:"log_source"`
	LogGuid              string                      `json:"log_guid"`
	MetricsGuid          string                      `json:"metrics_guid"`
	Annotation           string                      `json:"annotation,omitempty"`
	EgressRules          []SecurityGroupRule         `json:"egress_rules,omitempty"`
	ModificationTag      ModificationTag             `json:"modification_tag"`
}

type InnerDesiredLRP DesiredLRP

type mDesiredLRP struct {
	SetupRaw   *json.RawMessage `json:"setup,omitempty"`
	ActionRaw  *json.RawMessage `json:"action,omitempty"`
	MonitorRaw *json.RawMessage `json:"monitor,omitempty"`
	*InnerDesiredLRP
}

type DesiredLRPUpdate struct {
	Instances  *int                        `json:"instances,omitempty"`
	Routes     map[string]*json.RawMessage `json:"routes,omitempty"`
	Annotation *string                     `json:"annotation,omitempty"`
}

type DesiredLRPChange struct {
	Before DesiredLRP
	After  DesiredLRP
}

func (desired DesiredLRP) ApplyUpdate(update DesiredLRPUpdate) DesiredLRP {
	if update.Instances != nil {
		desired.Instances = *update.Instances
	}
	if update.Routes != nil {
		desired.Routes = update.Routes
	}
	if update.Annotation != nil {
		desired.Annotation = *update.Annotation
	}
	return desired
}

var processGuidPattern = regexp.MustCompile(`^[a-zA-Z0-9_-]+$`)

func (desired DesiredLRP) Validate() error {
	var validationError ValidationError

	if desired.Domain == "" {
		validationError = validationError.Append(ErrInvalidField{"domain"})
	}

	if !processGuidPattern.MatchString(desired.ProcessGuid) {
		validationError = validationError.Append(ErrInvalidField{"process_guid"})
	}

	if desired.RootFS == "" {
		validationError = validationError.Append(ErrInvalidField{"rootfs"})
	}

	rootFSURL, err := url.Parse(desired.RootFS)
	if err != nil || rootFSURL.Scheme == "" {
		validationError = validationError.Append(ErrInvalidField{"rootfs"})
	}

	if desired.Setup != nil {
		err := desired.Setup.Validate()
		if err != nil {
			validationError = validationError.Append(err)
		}
	}

	if desired.Action == nil {
		validationError = validationError.Append(ErrInvalidActionType)
	} else {
		err := desired.Action.Validate()
		if err != nil {
			validationError = validationError.Append(err)
		}
	}

	if desired.Monitor != nil {
		err := desired.Monitor.Validate()
		if err != nil {
			validationError = validationError.Append(err)
		}
	}

	if desired.Instances < 0 {
		validationError = validationError.Append(ErrInvalidField{"instances"})
	}

	if desired.CPUWeight > 100 {
		validationError = validationError.Append(ErrInvalidField{"cpu_weight"})
	}

	if len(desired.Annotation) > maximumAnnotationLength {
		validationError = validationError.Append(ErrInvalidField{"annotation"})
	}

	totalRoutesLength := 0
	for _, value := range desired.Routes {
		totalRoutesLength += len(*value)
		if totalRoutesLength > maximumRouteLength {
			validationError = validationError.Append(ErrInvalidField{"routes"})
			break
		}
	}

	for _, rule := range desired.EgressRules {
		err := rule.Validate()
		if err != nil {
			validationError = validationError.Append(ErrInvalidField{"egress_rules"})
			validationError = validationError.Append(err)
		}
	}

	if !validationError.Empty() {
		return validationError
	}

	return nil
}

func (desired *DesiredLRP) UnmarshalJSON(payload []byte) error {
	mLRP := &mDesiredLRP{InnerDesiredLRP: (*InnerDesiredLRP)(desired)}
	err := json.Unmarshal(payload, mLRP)
	if err != nil {
		return err
	}

	var a Action
	if mLRP.ActionRaw == nil {
		a = nil
	} else {
		a, err = UnmarshalAction(*mLRP.ActionRaw)
		if err != nil {
			return err
		}
	}
	desired.Action = a

	if mLRP.SetupRaw == nil {
		a = nil
	} else {
		a, err = UnmarshalAction(*mLRP.SetupRaw)
		if err != nil {
			return err
		}
		desired.Setup = a
	}

	if mLRP.MonitorRaw == nil {
		a = nil
	} else {
		a, err = UnmarshalAction(*mLRP.MonitorRaw)
		if err != nil {
			return err
		}
		desired.Monitor = a
	}

	return nil
}

func (desired DesiredLRP) MarshalJSON() ([]byte, error) {
	var setupRaw, actionRaw, monitorRaw *json.RawMessage

	if desired.Action != nil {
		raw, err := MarshalAction(desired.Action)
		if err != nil {
			return nil, err
		}
		rm := json.RawMessage(raw)
		actionRaw = &rm
	}

	if desired.Setup != nil {
		raw, err := MarshalAction(desired.Setup)
		if err != nil {
			return nil, err
		}
		rm := json.RawMessage(raw)
		setupRaw = &rm
	}
	if desired.Monitor != nil {
		raw, err := MarshalAction(desired.Monitor)
		if err != nil {
			return nil, err
		}
		rm := json.RawMessage(raw)
		monitorRaw = &rm
	}

	innerDesiredLRP := InnerDesiredLRP(desired)

	mLRP := &mDesiredLRP{
		SetupRaw:        setupRaw,
		ActionRaw:       actionRaw,
		MonitorRaw:      monitorRaw,
		InnerDesiredLRP: &innerDesiredLRP,
	}

	return json.Marshal(mLRP)
}
<|endoftext|>


<commit_before>package internal

// VERSION of sail
const VERSION = "0.6.0"
<commit_msg>[auto] bump version to v0.6.5<commit_after>package internal

// VERSION of sail
const VERSION = "0.6.5"
<|endoftext|>


<commit_before>// Copyright © 2017 Mladen Popadic <mladen.popadic.4@gmail.com>

package cmd

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path"
	"path/filepath"
	"regexp"
	"strings"

	"github.com/mpopadic/go_n_find/colors"
	"github.com/spf13/cobra"
)

var (
	pathFlag              string
	nameFlag              string
	replaceFlag           string
	ignoreCaseFlag        bool
	showAbsolutePathsFlag bool
	forceReplaceFlag      bool
	contentFlag           string
)

var (
	_numberOfResults int
	_renameMap       map[string]string
)

// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
	Use:   "go_n_find",
	Short: "CLI for finding files and folders",
	Long:  `CLI tool for finding files and folders by name or content`,
	PreRunE: func(cmd *cobra.Command, args []string) error {
		if pathFlag == "" {
			return fmt.Errorf("path flag is required")
		}
		if nameFlag == "" && contentFlag == "" {
			return fmt.Errorf("name flag or content flag are required")
		}
		return nil
	},
	// Uncomment the following line if your bare application
	// has an action associated with it:
	RunE: func(cmd *cobra.Command, args []string) error {

		// Set findOptions
		options := &findOptions{
			Path:              pathFlag,
			Name:              nameFlag,
			Content:           contentFlag,
			ReplaceWith:       replaceFlag,
			IgnoreCase:        ignoreCaseFlag,
			ShowAbsolutePaths: showAbsolutePathsFlag,
			ForceReplace:      forceReplaceFlag,
		}

		_numberOfResults = 0

		if options.ReplaceWith != "" && !options.ForceReplace {
			_renameMap = make(map[string]string)
		}

		if err := findInTree(options); err != nil {
			return err
		}

		colors.CYAN.Printf("Number of results: %d\n", _numberOfResults)
		if options.ReplaceWith != "" && !options.ForceReplace {
			response := waitResponse("Are you sure? [Yes/No] ", map[string][]string{
				"Yes": []string{"Yes", "Y", "y"},
				"No":  []string{"No", "N", "n"},
			})
			switch response {
			case "Yes":
				renamePaths(_renameMap)
			case "No":
				colors.RED.Print(response)
			}
		}

		return nil
	},
}

// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
	if err := RootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}

func init() {
	colors.InitColors()

	RootCmd.Flags().StringVarP(&pathFlag, "path", "p", "", "path to directory")
	RootCmd.Flags().StringVarP(&nameFlag, "name", "n", "", "regular expression for matching file or directory name; This flag filter files if content flag is used")
	RootCmd.Flags().StringVarP(&replaceFlag, "replace", "r", "", "replaces mached regular expression parts with given value")
	RootCmd.Flags().BoolVarP(&ignoreCaseFlag, "ignore-case", "i", false, "ignore case for all regular expresions; Add '(?i)' in front of specific regex for ignore case")
	RootCmd.Flags().BoolVarP(&showAbsolutePathsFlag, "absolute-paths", "a", false, "print absolute paths in result")
	RootCmd.Flags().BoolVarP(&forceReplaceFlag, "force-replace", "f", false, "Force replace without responding")
	RootCmd.Flags().StringVarP(&contentFlag, "content", "c", "", "regular expression for matching file content")

}

func findInTree(options *findOptions) error {
	fileInfo, err := os.Stat(options.Path)
	if err != nil {
		return fmt.Errorf("could not get fileInfo for %s: %v", options.Path, err)
	}

	if fileInfo.IsDir() {
		files, err := ioutil.ReadDir(options.Path)
		if err != nil {
			return fmt.Errorf("could not read directory %s: %v", options.Path, err)
		}
		for _, file := range files {
			childOptions := options.CreateCopy()
			childOptions.Path = path.Join(options.Path, file.Name())
			findInTree(childOptions)
		}
	}

	doAction(options, fileInfo)
	return nil
}

func doAction(options *findOptions, fileInfo os.FileInfo) {
	absolutePath, err := filepath.Abs(options.Path)
	if err != nil {
		log.Fatalf("could not get absolute path: %v", err)
	}
	finalPathPrint := getPathPrintFormat(options.Path, absolutePath, options.ShowAbsolutePaths)

	if options.Name != "" && options.Content == "" {
		re := createRegex(options.Name, options.IgnoreCase)

		if re.MatchString(fileInfo.Name()) {
			_numberOfResults++
			if options.ReplaceWith != "" {
				pathDir := filepath.Dir(absolutePath)
				newFileName := re.ReplaceAllString(fileInfo.Name(), options.ReplaceWith)

				if options.ForceReplace {
					err := os.Rename(absolutePath, filepath.FromSlash(path.Join(pathDir, newFileName)))
					if err != nil {
						fmt.Printf("could not rename file: %v", err)
					}
					colors.RED.Print(absolutePath)
					colors.CYAN.Print(" => ")
					colors.GREEN.Println(filepath.FromSlash(path.Join(pathDir, newFileName)))
				} else {
					_renameMap[absolutePath] = filepath.FromSlash(path.Join(pathDir, newFileName))

					fmt.Print(absolutePath)
					colors.CYAN.Print(" => ")
					fmt.Println(filepath.FromSlash(path.Join(pathDir, newFileName)))
				}
			} else {
				fmt.Println(filepath.FromSlash(finalPathPrint))
			}
		}
	}
	if options.Content != "" {
		if options.Name != "" {
			regName := createRegex(options.Name, options.IgnoreCase)
			if regName.MatchString(fileInfo.Name()) && !fileInfo.IsDir() {
				re := createRegex(options.Content, options.IgnoreCase)

				fileBytes, err := ioutil.ReadFile(absolutePath)
				if err != nil {
					log.Fatalf("could not read file content: %v", err)
				}
				fileString := string(fileBytes)

				fileLines := strings.Split(fileString, "\n")

				printedFileName := false
				for lineNumber, line := range fileLines {
					if re.MatchString(line) {
						_numberOfResults++
						if !printedFileName {
							colors.CYAN.Printf("%s:\n", finalPathPrint)
							printedFileName = !printedFileName
						}
						allIndexes := re.FindAllStringIndex(line, -1)

						colors.YELLOW.Printf("%v:", lineNumber+1)
						location := 0
						for _, match := range allIndexes {
							fmt.Printf("%s", line[location:match[0]])
							colors.GREEN.Printf("%s", line[match[0]:match[1]])
							location = match[1]
						}
						fmt.Printf("%s", line[location:])
						fmt.Println()
					}
				}
			}
		} else {
			if !fileInfo.IsDir() {
				re := createRegex(options.Content, options.IgnoreCase)

				fileBytes, err := ioutil.ReadFile(absolutePath)
				if err != nil {
					log.Fatalf("could not read file content: %v", err)
				}
				fileString := string(fileBytes)

				fileLines := strings.Split(fileString, "\n")

				printedFileName := false
				for lineNumber, line := range fileLines {
					if re.MatchString(line) {
						_numberOfResults++
						if !printedFileName {
							colors.CYAN.Printf("%s:\n", finalPathPrint)
							printedFileName = !printedFileName
						}
						allIndexes := re.FindAllStringIndex(line, -1)

						colors.YELLOW.Printf("%v:", lineNumber+1)
						location := 0
						for _, match := range allIndexes {
							fmt.Printf("%s", line[location:match[0]])
							colors.GREEN.Printf("%s", line[match[0]:match[1]])
							location = match[1]
						}
						fmt.Printf("%s", line[location:])
						fmt.Println()
					}
				}
			}
		}
	}
}

type findOptions struct {
	Path              string
	Name              string
	Content           string
	ReplaceWith       string
	IgnoreCase        bool
	ShowAbsolutePaths bool
	ForceReplace      bool
}

func (o *findOptions) CreateCopy() *findOptions {
	newFindOptions := &findOptions{
		Path:              o.Path,
		Name:              o.Name,
		Content:           o.Content,
		ReplaceWith:       o.ReplaceWith,
		IgnoreCase:        o.IgnoreCase,
		ShowAbsolutePaths: o.ShowAbsolutePaths,
		ForceReplace:      o.ForceReplace,
	}
	return newFindOptions
}

func waitResponse(question string, responseAliases map[string][]string) string {
	colors.YELLOW.Printf("%s ", question)
	var respond string

	for {
		fmt.Scanf("%s\n", &respond)

		for response, aliases := range responseAliases {
			for _, alias := range aliases {
				if respond == alias {
					return response
				}
			}
		}

		colors.YELLOW.Printf("%s ", question)
	}
}

func renamePaths(paths map[string]string) error {
	for oldPath, newPath := range paths {
		err := os.Rename(oldPath, newPath)
		if err != nil {
			return fmt.Errorf("could not rename file: %v", err)
		}
		colors.RED.Print(oldPath)
		colors.CYAN.Print(" => ")
		colors.GREEN.Println(newPath)
	}
	return nil
}

func getPathPrintFormat(filePath, absolutePath string, showAbsolute bool) string {
	var result = ""
	if showAbsolute {
		result = absolutePath
	} else {
		result = filePath
	}
	return filepath.Clean(result)
}

func createRegex(text string, ignoreCase bool) *regexp.Regexp {
	re, err := regexp.Compile(text)
	if err != nil {
		colors.RED.Printf("regular expresion for name flag is not valid\n")
		os.Exit(1)
	}
	if ignoreCase {
		re, err = regexp.Compile("(?i)" + text)
		if err != nil {
			colors.RED.Printf("regular expresion for name flag is not valid\n")
			os.Exit(1)
		}
	}
	return re
}
<commit_msg>started replace content functionality<commit_after>// Copyright © 2017 Mladen Popadic <mladen.popadic.4@gmail.com>

package cmd

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path"
	"path/filepath"
	"regexp"
	"strings"

	"github.com/mpopadic/go_n_find/colors"
	"github.com/spf13/cobra"
)

var (
	pathFlag              string
	nameFlag              string
	replaceFlag           string
	ignoreCaseFlag        bool
	showAbsolutePathsFlag bool
	forceReplaceFlag      bool
	contentFlag           string
)

var (
	_numberOfResults     int
	_renameMap           map[string]string
	_replaceContentFiles []string
)

// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
	Use:   "go_n_find",
	Short: "CLI for finding files and folders",
	Long:  `CLI tool for finding files and folders by name or content`,
	PreRunE: func(cmd *cobra.Command, args []string) error {
		if pathFlag == "" {
			return fmt.Errorf("path flag is required")
		}
		if nameFlag == "" && contentFlag == "" {
			return fmt.Errorf("name flag or content flag are required")
		}
		return nil
	},
	// Uncomment the following line if your bare application
	// has an action associated with it:
	RunE: func(cmd *cobra.Command, args []string) error {

		// Set findOptions
		options := &findOptions{
			Path:              pathFlag,
			Name:              nameFlag,
			Content:           contentFlag,
			ReplaceWith:       replaceFlag,
			IgnoreCase:        ignoreCaseFlag,
			ShowAbsolutePaths: showAbsolutePathsFlag,
			ForceReplace:      forceReplaceFlag,
		}

		_numberOfResults = 0

		if options.ReplaceWith != "" && !options.ForceReplace {
			_renameMap = make(map[string]string)
		}

		if err := findInTree(options); err != nil {
			return err
		}

		colors.CYAN.Printf("Number of results: %d\n", _numberOfResults)
		if options.ReplaceWith != "" && !options.ForceReplace && options.Content == "" {
			response := waitResponse("Are you sure? [Yes/No] ", map[string][]string{
				"Yes": []string{"Yes", "Y", "y"},
				"No":  []string{"No", "N", "n"},
			})
			switch response {
			case "Yes":
				renamePaths(_renameMap)
			case "No":
				colors.RED.Print(response)
			}
		}

		if options.ReplaceWith != "" && !options.ForceReplace && options.Content != "" {
			response := waitResponse("Are you sure? [Yes/No] ", map[string][]string{
				"Yes": []string{"Yes", "Y", "y"},
				"No":  []string{"No", "N", "n"},
			})
			switch response {
			case "Yes":
				renamePaths(_renameMap)
			case "No":
				colors.RED.Print(response)
			}
		}

		return nil
	},
}

// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
	if err := RootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}

func init() {
	colors.InitColors()

	RootCmd.Flags().StringVarP(&pathFlag, "path", "p", "", "path to directory")
	RootCmd.Flags().StringVarP(&nameFlag, "name", "n", "", "regular expression for matching file or directory name; This flag filter files if content flag is used")
	RootCmd.Flags().StringVarP(&replaceFlag, "replace", "r", "", "replaces mached regular expression parts with given value")
	RootCmd.Flags().BoolVarP(&ignoreCaseFlag, "ignore-case", "i", false, "ignore case for all regular expresions; Add '(?i)' in front of specific regex for ignore case")
	RootCmd.Flags().BoolVarP(&showAbsolutePathsFlag, "absolute-paths", "a", false, "print absolute paths in result")
	RootCmd.Flags().BoolVarP(&forceReplaceFlag, "force-replace", "f", false, "Force replace without responding")
	RootCmd.Flags().StringVarP(&contentFlag, "content", "c", "", "regular expression for matching file content")

}

func findInTree(options *findOptions) error {
	fileInfo, err := os.Stat(options.Path)
	if err != nil {
		return fmt.Errorf("could not get fileInfo for %s: %v", options.Path, err)
	}

	if fileInfo.IsDir() {
		files, err := ioutil.ReadDir(options.Path)
		if err != nil {
			return fmt.Errorf("could not read directory %s: %v", options.Path, err)
		}
		for _, file := range files {
			childOptions := options.CreateCopy()
			childOptions.Path = path.Join(options.Path, file.Name())
			findInTree(childOptions)
		}
	}

	doAction(options, fileInfo)
	return nil
}

func doAction(options *findOptions, fileInfo os.FileInfo) {
	absolutePath, err := filepath.Abs(options.Path)
	if err != nil {
		log.Fatalf("could not get absolute path: %v", err)
	}
	finalPathPrint := getPathPrintFormat(options.Path, absolutePath, options.ShowAbsolutePaths)

	if options.Name != "" && options.Content == "" {
		re := createRegex(options.Name, options.IgnoreCase)

		if re.MatchString(fileInfo.Name()) {
			_numberOfResults++
			if options.ReplaceWith != "" {
				pathDir := filepath.Dir(absolutePath)
				newFileName := re.ReplaceAllString(fileInfo.Name(), options.ReplaceWith)

				if options.ForceReplace {
					err := os.Rename(absolutePath, filepath.FromSlash(path.Join(pathDir, newFileName)))
					if err != nil {
						fmt.Printf("could not rename file: %v", err)
					}
					colors.RED.Print(absolutePath)
					colors.CYAN.Print(" => ")
					colors.GREEN.Println(filepath.FromSlash(path.Join(pathDir, newFileName)))
				} else {
					_renameMap[absolutePath] = filepath.FromSlash(path.Join(pathDir, newFileName))

					fmt.Print(absolutePath)
					colors.CYAN.Print(" => ")
					fmt.Println(filepath.FromSlash(path.Join(pathDir, newFileName)))
				}
			} else {
				fmt.Println(filepath.FromSlash(finalPathPrint))
			}
		}
	}
	if options.Content != "" {
		if options.Name != "" {
			regName := createRegex(options.Name, options.IgnoreCase)
			if regName.MatchString(fileInfo.Name()) && !fileInfo.IsDir() {
				re := createRegex(options.Content, options.IgnoreCase)

				fileBytes, err := ioutil.ReadFile(absolutePath)
				if err != nil {
					log.Fatalf("could not read file content: %v", err)
				}
				fileString := string(fileBytes)

				fileLines := strings.Split(fileString, "\n")

				printedFileName := false
				for lineNumber, line := range fileLines {
					if re.MatchString(line) {
						_numberOfResults++
						if !printedFileName {
							colors.CYAN.Printf("%s:\n", finalPathPrint)
							printedFileName = !printedFileName
						}
						allIndexes := re.FindAllStringIndex(line, -1)

						colors.YELLOW.Printf("%v:", lineNumber+1)
						location := 0
						for _, match := range allIndexes {
							fmt.Printf("%s", line[location:match[0]])
							colors.GREEN.Printf("%s", line[match[0]:match[1]])
							location = match[1]
						}
						fmt.Printf("%s", line[location:])
						fmt.Println()
					}
				}
			}
		} else {
			if !fileInfo.IsDir() {
				re := createRegex(options.Content, options.IgnoreCase)

				fileBytes, err := ioutil.ReadFile(absolutePath)
				if err != nil {
					log.Fatalf("could not read file content: %v", err)
				}
				fileString := string(fileBytes)

				fileLines := strings.Split(fileString, "\n")

				printedFileName := false
				for lineNumber, line := range fileLines {
					if re.MatchString(line) {
						_numberOfResults++
						if !printedFileName {
							colors.CYAN.Printf("%s:\n", finalPathPrint)
							printedFileName = !printedFileName
						}
						allIndexes := re.FindAllStringIndex(line, -1)

						colors.YELLOW.Printf("%v:", lineNumber+1)
						location := 0
						for _, match := range allIndexes {
							fmt.Printf("%s", line[location:match[0]])
							colors.GREEN.Printf("%s", line[match[0]:match[1]])
							location = match[1]
						}
						fmt.Printf("%s", line[location:])
						fmt.Println()
					}
				}
			}
		}
	}
}

type findOptions struct {
	Path              string
	Name              string
	Content           string
	ReplaceWith       string
	IgnoreCase        bool
	ShowAbsolutePaths bool
	ForceReplace      bool
}

func (o *findOptions) CreateCopy() *findOptions {
	newFindOptions := &findOptions{
		Path:              o.Path,
		Name:              o.Name,
		Content:           o.Content,
		ReplaceWith:       o.ReplaceWith,
		IgnoreCase:        o.IgnoreCase,
		ShowAbsolutePaths: o.ShowAbsolutePaths,
		ForceReplace:      o.ForceReplace,
	}
	return newFindOptions
}

func waitResponse(question string, responseAliases map[string][]string) string {
	colors.YELLOW.Printf("%s ", question)
	var respond string

	for {
		fmt.Scanf("%s\n", &respond)

		for response, aliases := range responseAliases {
			for _, alias := range aliases {
				if respond == alias {
					return response
				}
			}
		}

		colors.YELLOW.Printf("%s ", question)
	}
}

func renamePaths(paths map[string]string) error {
	for oldPath, newPath := range paths {
		err := os.Rename(oldPath, newPath)
		if err != nil {
			return fmt.Errorf("could not rename file: %v", err)
		}
		colors.RED.Print(oldPath)
		colors.CYAN.Print(" => ")
		colors.GREEN.Println(newPath)
	}
	return nil
}

func getPathPrintFormat(filePath, absolutePath string, showAbsolute bool) string {
	var result = ""
	if showAbsolute {
		result = absolutePath
	} else {
		result = filePath
	}
	return filepath.Clean(result)
}

func createRegex(text string, ignoreCase bool) *regexp.Regexp {
	re, err := regexp.Compile(text)
	if err != nil {
		colors.RED.Printf("regular expresion for name flag is not valid\n")
		os.Exit(1)
	}
	if ignoreCase {
		re, err = regexp.Compile("(?i)" + text)
		if err != nil {
			colors.RED.Printf("regular expresion for name flag is not valid\n")
			os.Exit(1)
		}
	}
	return re
}

func replaceContent(filePaths []string, oldContent *regexp.Regexp, newContent string, fileInfo os.FileInfo) {
	for _, filePath := range filePaths {
		fileBytes, err := ioutil.ReadFile(filePath)
		if err != nil {
			log.Fatalf("could not read file content: %v", err)
		}
		fileString := string(fileBytes)

		newFileString := oldContent.ReplaceAllString(fileString, newContent)

		err = ioutil.WriteFile(filePath, []byte(newFileString), fileInfo.Mode())
		if err != nil {
			fmt.Printf("could not write to file: %v", err)
		} else {
			colors.GREEN.Printf("%s\n", filePath)
		}
	}
}
<|endoftext|>