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

// Package provision provides interfaces that need to be satisfied in order to
// implement a new provisioner on tsuru.
package provision

import (
	"errors"
	"fmt"
	"io"
	"net/url"

	"github.com/tsuru/tsuru/app/bind"
	"github.com/tsuru/tsuru/quota"
)

var (
	ErrInvalidStatus = errors.New("invalid status")
	ErrEmptyApp      = errors.New("no units for this app")
)

type UnitNotFoundError struct {
	ID string
}

func (e *UnitNotFoundError) Error() string {
	return fmt.Sprintf("unit %q not found", e.ID)
}

type InvalidProcessError struct {
	Msg string
}

func (e InvalidProcessError) Error() string {
	return fmt.Sprintf("process error: %s", e.Msg)
}

// Status represents the status of a unit in tsuru.
type Status string

func (s Status) String() string {
	return string(s)
}

func ParseStatus(status string) (Status, error) {
	switch status {
	case "created":
		return StatusCreated, nil
	case "building":
		return StatusBuilding, nil
	case "error":
		return StatusError, nil
	case "started":
		return StatusStarted, nil
	case "starting":
		return StatusStarting, nil
	case "stopped":
		return StatusStopped, nil
	case "asleep":
		return StatusAsleep, nil
	}
	return Status(""), ErrInvalidStatus
}

//     Flow:
//
//     +----------+                           Start          +---------+
//     | Building |                   +---------------------+| Stopped |
//     +----------+                   |                      +---------+
//           ^                        |                           ^
//           |                        |                           |
//      deploy unit                   |                         Stop
//           |                        |                           |
//           +                        v       RegisterUnit        +
//      +---------+  app unit   +----------+  SetUnitStatus  +---------+
//      | Created | +---------> | Starting | +-------------> | Started |
//      +---------+             +----------+                 +---------+
//                                    +                         ^ +
//                                    |                         | |
//                              SetUnitStatus                   | |
//                                    |                         | |
//                                    v                         | |
//                                +-------+     SetUnitStatus   | |
//                                | Error | +-------------------+ |
//                                +-------+ <---------------------+
const (
	// StatusCreated is the initial status of a unit in the database,
	// it should transition shortly to a more specific status
	StatusCreated = Status("created")

	// StatusBuilding is the status for units being provisioned by the
	// provisioner, like in the deployment.
	StatusBuilding = Status("building")

	// StatusError is the status for units that failed to start, because of
	// an application error.
	StatusError = Status("error")

	// StatusStarting is set when the container is started in docker.
	StatusStarting = Status("starting")

	// StatusStarted is for cases where the unit is up and running, and bound
	// to the proper status, it's set by RegisterUnit and SetUnitStatus.
	StatusStarted = Status("started")

	// StatusStopped is for cases where the unit has been stopped.
	StatusStopped = Status("stopped")

	// StatusAsleep is for cases where the unit has been asleep.
	StatusAsleep = Status("asleep")
)

// Unit represents a provision unit. Can be a machine, container or anything
// IP-addressable.
type Unit struct {
	ID          string
	Name        string
	AppName     string
	ProcessName string
	Type        string
	Ip          string
	Status      Status
	Address     *url.URL
}

// GetName returns the name of the unit.
func (u *Unit) GetID() string {
	return u.ID
}

// GetIp returns the Unit.IP.
func (u *Unit) GetIp() string {
	return u.Ip
}

// Available returns true if the unit is available. It will return true
// whenever the unit itself is available, even when the application process is
// not.
func (u *Unit) Available() bool {
	return u.Status == StatusStarted ||
		u.Status == StatusStarting ||
		u.Status == StatusError
}

// Named is something that has a name, providing the GetName method.
type Named interface {
	GetName() string
}

// App represents a tsuru app.
//
// It contains only relevant information for provisioning.
type App interface {
	Named

	BindUnit(*Unit) error
	UnbindUnit(*Unit) error

	// Log should be used to log messages in the app.
	Log(message, source, unit string) error

	// GetPlatform returns the platform (type) of the app. It is equivalent
	// to the Unit `Type` field.
	GetPlatform() string

	// GetDeploy returns the deploys that an app has.
	GetDeploys() uint

	Units() ([]Unit, error)

	// Run executes the command in app units. Commands executed with this
	// method should have access to environment variables defined in the
	// app.
	Run(cmd string, w io.Writer, once bool) error

	Envs() map[string]bind.EnvVar

	GetMemory() int64
	GetSwap() int64
	GetCpuShare() int

	SetUpdatePlatform(bool) error
	GetUpdatePlatform() bool

	GetRouter() (string, error)

	GetPool() string

	GetTeamOwner() string

	GetTeamsName() []string

	GetQuota() quota.Quota
	SetQuotaInUse(int) error
}

// CNameManager represents a provisioner that supports cname on applications.
type CNameManager interface {
	SetCName(app App, cname string) error
	UnsetCName(app App, cname string) error
}

// ShellOptions is the set of options that can be used when calling the method
// Shell in the provisioner.
type ShellOptions struct {
	App    App
	Conn   io.ReadWriteCloser
	Width  int
	Height int
	Unit   string
	Term   string
}

// ArchiveDeployer is a provisioner that can deploy archives.
type ArchiveDeployer interface {
	ArchiveDeploy(app App, archiveURL string, w io.Writer) (string, error)
}

// UploadDeployer is a provisioner that can deploy the application from an
// uploaded file.
type UploadDeployer interface {
	UploadDeploy(app App, file io.ReadCloser, w io.Writer) (string, error)
}

// ImageDeployer is a provisioner that can deploy the application from a
// previously generated image.
type ImageDeployer interface {
	ImageDeploy(app App, image string, w io.Writer) (string, error)
}

// Provisioner is the basic interface of this package.
//
// Any tsuru provisioner must implement this interface in order to provision
// tsuru apps.
type Provisioner interface {
	// Provision is called when tsuru is creating the app.
	Provision(App) error

	// Destroy is called when tsuru is destroying the app.
	Destroy(App) error

	// AddUnits adds units to an app. The first parameter is the app, the
	// second is the number of units to be added.
	//
	// It returns a slice containing all added units
	AddUnits(App, uint, string, io.Writer) ([]Unit, error)

	// RemoveUnits "undoes" AddUnits, removing the given number of units
	// from the app.
	RemoveUnits(App, uint, string, io.Writer) error

	// SetUnitStatus changes the status of a unit.
	SetUnitStatus(Unit, Status) error

	// ExecuteCommand runs a command in all units of the app.
	ExecuteCommand(stdout, stderr io.Writer, app App, cmd string, args ...string) error

	// ExecuteCommandOnce runs a command in one unit of the app.
	ExecuteCommandOnce(stdout, stderr io.Writer, app App, cmd string, args ...string) error

	// Restart restarts the units of the application, with an optional
	// string parameter represeting the name of the process to start. When
	// the process is empty, Restart will restart all units of the
	// application.
	Restart(App, string, io.Writer) error

	// Start starts the units of the application, with an optional string
	// parameter representing the name of the process to start. When the
	// process is empty, Start will start all units of the application.
	Start(App, string) error

	// Stop stops the units of the application, with an optional string
	// parameter representing the name of the process to start. When the
	// process is empty, Stop will stop all units of the application.
	Stop(App, string) error

	// Sleep puts the units of the application to sleep, with an optional string
	// parameter representing the name of the process to sleep. When the
	// process is empty, Sleep will put all units of the application to sleep.
	Sleep(App, string) error

	// Addr returns the address for an app.
	//
	// tsuru will use this method to get the IP (although it might not be
	// an actual IP, collector calls it "IP") of the app from the
	// provisioner.
	Addr(App) (string, error)

	// Swap change the router between two apps.
	Swap(App, App) error

	// Units returns information about units by App.
	Units(App) ([]Unit, error)

	// RoutableUnits returns information about routable units by App.
	RoutableUnits(App) ([]Unit, error)

	// Register a unit after the container has been created or restarted.
	RegisterUnit(Unit, map[string]interface{}) error

	// Open a remote shel in one of the units in the application.
	Shell(ShellOptions) error

	// Returns list of valid image names for app, these can be used for
	// rollback.
	ValidAppImages(string) ([]string, error)

	// Returns the metric backend environs for the app.
	MetricEnvs(App) map[string]string

	// Rollback a deploy
	Rollback(App, string, io.Writer) (string, error)
}

type MessageProvisioner interface {
	StartupMessage() (string, error)
}

// InitializableProvisioner is a provisioner that provides an initialization
// method that should be called when the app is started
type InitializableProvisioner interface {
	Initialize() error
}

// Provisioners can implement this interface to optionaly disable logs for a
// given app.
type OptionalLogsProvisioner interface {
	// Checks if logs are enabled for given app.
	LogsEnabled(App) (bool, string, error)
}

// PlatformOptions is the set of options provided to PlatformAdd and
// PlatformUpdate, in the ExtensibleProvisioner.
type PlatformOptions struct {
	Name   string
	Args   map[string]string
	Input  io.Reader
	Output io.Writer
}

// ExtensibleProvisioner is a provisioner where administrators can manage
// platforms (automatically adding, removing and updating platforms).
type ExtensibleProvisioner interface {
	PlatformAdd(PlatformOptions) error
	PlatformUpdate(PlatformOptions) error
	PlatformRemove(name string) error
}

var provisioners = make(map[string]Provisioner)

// Register registers a new provisioner in the Provisioner registry.
func Register(name string, p Provisioner) {
	provisioners[name] = p
}

// Get gets the named provisioner from the registry.
func Get(name string) (Provisioner, error) {
	p, ok := provisioners[name]
	if !ok {
		return nil, fmt.Errorf("unknown provisioner: %q", name)
	}
	return p, nil
}

// Registry returns the list of registered provisioners.
func Registry() []Provisioner {
	registry := make([]Provisioner, 0, len(provisioners))
	for _, p := range provisioners {
		registry = append(registry, p)
	}
	return registry
}

// Error represents a provisioning error. It encapsulates further errors.
type Error struct {
	Reason string
	Err    error
}

// Error is the string representation of a provisioning error.
func (e *Error) Error() string {
	var err string
	if e.Err != nil {
		err = e.Err.Error() + ": " + e.Reason
	} else {
		err = e.Reason
	}
	return err
}

type TsuruYamlRestartHooks struct {
	Before []string
	After  []string
}

type TsuruYamlHooks struct {
	Restart TsuruYamlRestartHooks
	Build   []string
}

type TsuruYamlHealthcheck struct {
	Path            string
	Method          string
	Status          int
	Match           string
	AllowedFailures int `json:"allowed_failures" bson:"allowed_failures"`
}

type TsuruYamlData struct {
	Hooks       TsuruYamlHooks
	Healthcheck TsuruYamlHealthcheck
}
<commit_msg>provision: add sleep to flow diagram<commit_after>// Copyright 2016 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package provision provides interfaces that need to be satisfied in order to
// implement a new provisioner on tsuru.
package provision

import (
	"errors"
	"fmt"
	"io"
	"net/url"

	"github.com/tsuru/tsuru/app/bind"
	"github.com/tsuru/tsuru/quota"
)

var (
	ErrInvalidStatus = errors.New("invalid status")
	ErrEmptyApp      = errors.New("no units for this app")
)

type UnitNotFoundError struct {
	ID string
}

func (e *UnitNotFoundError) Error() string {
	return fmt.Sprintf("unit %q not found", e.ID)
}

type InvalidProcessError struct {
	Msg string
}

func (e InvalidProcessError) Error() string {
	return fmt.Sprintf("process error: %s", e.Msg)
}

// Status represents the status of a unit in tsuru.
type Status string

func (s Status) String() string {
	return string(s)
}

func ParseStatus(status string) (Status, error) {
	switch status {
	case "created":
		return StatusCreated, nil
	case "building":
		return StatusBuilding, nil
	case "error":
		return StatusError, nil
	case "started":
		return StatusStarted, nil
	case "starting":
		return StatusStarting, nil
	case "stopped":
		return StatusStopped, nil
	case "asleep":
		return StatusAsleep, nil
	}
	return Status(""), ErrInvalidStatus
}

//     Flow:
//
//     +----------+                           Start          +---------+
//     | Building |                   +---------------------+| Stopped |
//     +----------+                   |                      +---------+
//           ^                        |                           ^
//           |                        |                           |
//      deploy unit                   |                         Stop
//           |                        |                           |
//           +                        v       RegisterUnit        +
//      +---------+  app unit   +----------+  SetUnitStatus  +---------+  Sleep  +--------+
//      | Created | +---------> | Starting | +-------------> | Started |+------->| Asleep |
//      +---------+             +----------+                 +---------+         +--------+
//                                    +                         ^ +
//                                    |                         | |
//                              SetUnitStatus                   | |
//                                    |                         | |
//                                    v                         | |
//                                +-------+     SetUnitStatus   | |
//                                | Error | +-------------------+ |
//                                +-------+ <---------------------+
const (
	// StatusCreated is the initial status of a unit in the database,
	// it should transition shortly to a more specific status
	StatusCreated = Status("created")

	// StatusBuilding is the status for units being provisioned by the
	// provisioner, like in the deployment.
	StatusBuilding = Status("building")

	// StatusError is the status for units that failed to start, because of
	// an application error.
	StatusError = Status("error")

	// StatusStarting is set when the container is started in docker.
	StatusStarting = Status("starting")

	// StatusStarted is for cases where the unit is up and running, and bound
	// to the proper status, it's set by RegisterUnit and SetUnitStatus.
	StatusStarted = Status("started")

	// StatusStopped is for cases where the unit has been stopped.
	StatusStopped = Status("stopped")

	// StatusAsleep is for cases where the unit has been asleep.
	StatusAsleep = Status("asleep")
)

// Unit represents a provision unit. Can be a machine, container or anything
// IP-addressable.
type Unit struct {
	ID          string
	Name        string
	AppName     string
	ProcessName string
	Type        string
	Ip          string
	Status      Status
	Address     *url.URL
}

// GetName returns the name of the unit.
func (u *Unit) GetID() string {
	return u.ID
}

// GetIp returns the Unit.IP.
func (u *Unit) GetIp() string {
	return u.Ip
}

// Available returns true if the unit is available. It will return true
// whenever the unit itself is available, even when the application process is
// not.
func (u *Unit) Available() bool {
	return u.Status == StatusStarted ||
		u.Status == StatusStarting ||
		u.Status == StatusError
}

// Named is something that has a name, providing the GetName method.
type Named interface {
	GetName() string
}

// App represents a tsuru app.
//
// It contains only relevant information for provisioning.
type App interface {
	Named

	BindUnit(*Unit) error
	UnbindUnit(*Unit) error

	// Log should be used to log messages in the app.
	Log(message, source, unit string) error

	// GetPlatform returns the platform (type) of the app. It is equivalent
	// to the Unit `Type` field.
	GetPlatform() string

	// GetDeploy returns the deploys that an app has.
	GetDeploys() uint

	Units() ([]Unit, error)

	// Run executes the command in app units. Commands executed with this
	// method should have access to environment variables defined in the
	// app.
	Run(cmd string, w io.Writer, once bool) error

	Envs() map[string]bind.EnvVar

	GetMemory() int64
	GetSwap() int64
	GetCpuShare() int

	SetUpdatePlatform(bool) error
	GetUpdatePlatform() bool

	GetRouter() (string, error)

	GetPool() string

	GetTeamOwner() string

	GetTeamsName() []string

	GetQuota() quota.Quota
	SetQuotaInUse(int) error
}

// CNameManager represents a provisioner that supports cname on applications.
type CNameManager interface {
	SetCName(app App, cname string) error
	UnsetCName(app App, cname string) error
}

// ShellOptions is the set of options that can be used when calling the method
// Shell in the provisioner.
type ShellOptions struct {
	App    App
	Conn   io.ReadWriteCloser
	Width  int
	Height int
	Unit   string
	Term   string
}

// ArchiveDeployer is a provisioner that can deploy archives.
type ArchiveDeployer interface {
	ArchiveDeploy(app App, archiveURL string, w io.Writer) (string, error)
}

// UploadDeployer is a provisioner that can deploy the application from an
// uploaded file.
type UploadDeployer interface {
	UploadDeploy(app App, file io.ReadCloser, w io.Writer) (string, error)
}

// ImageDeployer is a provisioner that can deploy the application from a
// previously generated image.
type ImageDeployer interface {
	ImageDeploy(app App, image string, w io.Writer) (string, error)
}

// Provisioner is the basic interface of this package.
//
// Any tsuru provisioner must implement this interface in order to provision
// tsuru apps.
type Provisioner interface {
	// Provision is called when tsuru is creating the app.
	Provision(App) error

	// Destroy is called when tsuru is destroying the app.
	Destroy(App) error

	// AddUnits adds units to an app. The first parameter is the app, the
	// second is the number of units to be added.
	//
	// It returns a slice containing all added units
	AddUnits(App, uint, string, io.Writer) ([]Unit, error)

	// RemoveUnits "undoes" AddUnits, removing the given number of units
	// from the app.
	RemoveUnits(App, uint, string, io.Writer) error

	// SetUnitStatus changes the status of a unit.
	SetUnitStatus(Unit, Status) error

	// ExecuteCommand runs a command in all units of the app.
	ExecuteCommand(stdout, stderr io.Writer, app App, cmd string, args ...string) error

	// ExecuteCommandOnce runs a command in one unit of the app.
	ExecuteCommandOnce(stdout, stderr io.Writer, app App, cmd string, args ...string) error

	// Restart restarts the units of the application, with an optional
	// string parameter represeting the name of the process to start. When
	// the process is empty, Restart will restart all units of the
	// application.
	Restart(App, string, io.Writer) error

	// Start starts the units of the application, with an optional string
	// parameter representing the name of the process to start. When the
	// process is empty, Start will start all units of the application.
	Start(App, string) error

	// Stop stops the units of the application, with an optional string
	// parameter representing the name of the process to start. When the
	// process is empty, Stop will stop all units of the application.
	Stop(App, string) error

	// Sleep puts the units of the application to sleep, with an optional string
	// parameter representing the name of the process to sleep. When the
	// process is empty, Sleep will put all units of the application to sleep.
	Sleep(App, string) error

	// Addr returns the address for an app.
	//
	// tsuru will use this method to get the IP (although it might not be
	// an actual IP, collector calls it "IP") of the app from the
	// provisioner.
	Addr(App) (string, error)

	// Swap change the router between two apps.
	Swap(App, App) error

	// Units returns information about units by App.
	Units(App) ([]Unit, error)

	// RoutableUnits returns information about routable units by App.
	RoutableUnits(App) ([]Unit, error)

	// Register a unit after the container has been created or restarted.
	RegisterUnit(Unit, map[string]interface{}) error

	// Open a remote shel in one of the units in the application.
	Shell(ShellOptions) error

	// Returns list of valid image names for app, these can be used for
	// rollback.
	ValidAppImages(string) ([]string, error)

	// Returns the metric backend environs for the app.
	MetricEnvs(App) map[string]string

	// Rollback a deploy
	Rollback(App, string, io.Writer) (string, error)
}

type MessageProvisioner interface {
	StartupMessage() (string, error)
}

// InitializableProvisioner is a provisioner that provides an initialization
// method that should be called when the app is started
type InitializableProvisioner interface {
	Initialize() error
}

// Provisioners can implement this interface to optionaly disable logs for a
// given app.
type OptionalLogsProvisioner interface {
	// Checks if logs are enabled for given app.
	LogsEnabled(App) (bool, string, error)
}

// PlatformOptions is the set of options provided to PlatformAdd and
// PlatformUpdate, in the ExtensibleProvisioner.
type PlatformOptions struct {
	Name   string
	Args   map[string]string
	Input  io.Reader
	Output io.Writer
}

// ExtensibleProvisioner is a provisioner where administrators can manage
// platforms (automatically adding, removing and updating platforms).
type ExtensibleProvisioner interface {
	PlatformAdd(PlatformOptions) error
	PlatformUpdate(PlatformOptions) error
	PlatformRemove(name string) error
}

var provisioners = make(map[string]Provisioner)

// Register registers a new provisioner in the Provisioner registry.
func Register(name string, p Provisioner) {
	provisioners[name] = p
}

// Get gets the named provisioner from the registry.
func Get(name string) (Provisioner, error) {
	p, ok := provisioners[name]
	if !ok {
		return nil, fmt.Errorf("unknown provisioner: %q", name)
	}
	return p, nil
}

// Registry returns the list of registered provisioners.
func Registry() []Provisioner {
	registry := make([]Provisioner, 0, len(provisioners))
	for _, p := range provisioners {
		registry = append(registry, p)
	}
	return registry
}

// Error represents a provisioning error. It encapsulates further errors.
type Error struct {
	Reason string
	Err    error
}

// Error is the string representation of a provisioning error.
func (e *Error) Error() string {
	var err string
	if e.Err != nil {
		err = e.Err.Error() + ": " + e.Reason
	} else {
		err = e.Reason
	}
	return err
}

type TsuruYamlRestartHooks struct {
	Before []string
	After  []string
}

type TsuruYamlHooks struct {
	Restart TsuruYamlRestartHooks
	Build   []string
}

type TsuruYamlHealthcheck struct {
	Path            string
	Method          string
	Status          int
	Match           string
	AllowedFailures int `json:"allowed_failures" bson:"allowed_failures"`
}

type TsuruYamlData struct {
	Hooks       TsuruYamlHooks
	Healthcheck TsuruYamlHealthcheck
}
<|endoftext|>


<commit_before>// Package gotenv provides functionality to dynamically load the environment variables
package gotenv

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"regexp"
	"strings"
)

const (
	// Pattern for detecting valid line format
	linePattern = `\A\s*(?:export\s+)?([\w\.]+)(?:\s*=\s*|:\s+?)('(?:\'|[^'])*'|"(?:\"|[^"])*"|[^#\n]+)?\s*(?:\s*\#.*)?\z`

	// Pattern for detecting valid variable within a value
	variablePattern = `(\\)?(\$)(\{?([A-Z0-9_]+)?\}?)`
)

// Env holds key/value pair of valid environment variable
type Env map[string]string

/*
Load is function to load a file or multiple files and then export the valid variables into environment variables if they are not exists.
When it's called with no argument, it will load `.env` file on the current path and set the environment variables.
Otherwise, it will loop over the filenames parameter and set the proper environment variables.
*/
func Load(filenames ...string) error {
	return loadenv(false, filenames...)
}

/*
OverLoad is function to load a file or multiple files and then export and override the valid variables into environment variables.
*/
func OverLoad(filenames ...string) error {
	return loadenv(true, filenames...)
}

/*
Must is wrapper function that will panic when supplied function returns error
*/
func Must(fn func(filenames ...string) error, filenames ...string) {
	if err := fn(filenames...); err != nil {
		panic(err.Error())
	}
}

/*
Apply is function to load an io Reader then export the valid variables into environment variables if they are not exist.
*/
func Apply(r io.Reader) error {
	return parset(r, false)
}

/*
OverApply is function to load an io Reader then export and override the valid variables into environment variables.
*/
func OverApply(r io.Reader) error {
	return parset(r, true)
}

func loadenv(override bool, filenames ...string) error {
	if len(filenames) == 0 {
		filenames = []string{".env"}
	}

	for _, filename := range filenames {
		f, err := os.Open(filename)
		if err != nil {
			return err
		}

		err = parset(f, override)
		if err != nil {
			return err
		}

		f.Close()
	}

	return nil
}

// parse and set :)
func parset(r io.Reader, override bool) error {
	env, err := StrictParse(r)
	if err != nil {
		return err
	}

	for key, val := range env {
		setenv(key, val, override)
	}

	return nil
}

func setenv(key, val string, override bool) {
	if override {
		os.Setenv(key, val)
	} else {
		if _, present := os.LookupEnv(key); !present {
			os.Setenv(key, val)
		}
	}
}

// Parse is a function to parse line by line any io.Reader supplied and returns the valid Env key/value pair of valid variables.
// It expands the value of a variable from environment variable, but does not set the value to the environment itself.
// This function is skipping any invalid lines and only processing the valid one.
func Parse(r io.Reader) Env {
	env, _ := StrictParse(r)
	return env
}

// StrictParse is a function to parse line by line any io.Reader supplied and returns the valid Env key/value pair of valid variables.
// It expands the value of a variable from environment variable, but does not set the value to the environment itself.
// This function is returning an error if there is any invalid lines.
func StrictParse(r io.Reader) (Env, error) {
	env := make(Env)
	scanner := bufio.NewScanner(r)

	i := 1
	bom := string([]byte{239, 187, 191})

	for scanner.Scan() {
		line := scanner.Text()

		if i == 1 {
			line = strings.TrimPrefix(line, bom)
		}

		i++

		err := parseLine(line, env)
		if err != nil {
			return env, err
		}
	}

	return env, nil
}

func parseLine(s string, env Env) error {
	rl := regexp.MustCompile(linePattern)
	rm := rl.FindStringSubmatch(s)

	if len(rm) == 0 {
		return checkFormat(s, env)
	}

	key := rm[1]
	val := rm[2]

	// determine if string has quote prefix
	hdq := strings.HasPrefix(val, `"`)

	// determine if string has single quote prefix
	hsq := strings.HasPrefix(val, `'`)

	// trim whitespace
	val = strings.Trim(val, " ")

	// remove quotes '' or ""
	rq := regexp.MustCompile(`\A(['"])(.*)(['"])\z`)
	val = rq.ReplaceAllString(val, "$2")

	if hdq {
		val = strings.Replace(val, `\n`, "\n", -1)
		val = strings.Replace(val, `\r`, "\r", -1)

		// Unescape all characters except $ so variables can be escaped properly
		re := regexp.MustCompile(`\\([^$])`)
		val = re.ReplaceAllString(val, "$1")
	}

	rv := regexp.MustCompile(variablePattern)
	fv := func(s string) string {
		return varReplacement(s, hsq, env)
	}

	val = rv.ReplaceAllStringFunc(val, fv)
	val = parseVal(val, env)

	env[key] = val
	return nil
}

func parseExport(st string, env Env) error {
	if strings.HasPrefix(st, "export") {
		vs := strings.SplitN(st, " ", 2)

		if len(vs) > 1 {
			if _, ok := env[vs[1]]; !ok {
				return fmt.Errorf("line `%s` has an unset variable", st)
			}
		}
	}

	return nil
}

func varReplacement(s string, hsq bool, env Env) string {
	if strings.HasPrefix(s, "\\") {
		return strings.TrimPrefix(s, "\\")
	}

	if hsq {
		return s
	}

	sn := `(\$)(\{?([A-Z0-9_]+)\}?)`
	rn := regexp.MustCompile(sn)
	mn := rn.FindStringSubmatch(s)

	if len(mn) == 0 {
		return s
	}

	v := mn[3]

	replace, ok := env[v]
	if !ok {
		replace = os.Getenv(v)
	}

	return replace
}

func checkFormat(s string, env Env) error {
	st := strings.TrimSpace(s)

	if (st == "") || strings.HasPrefix(st, "#") {
		return nil
	}

	if err := parseExport(st, env); err != nil {
		return err
	}

	return fmt.Errorf("line `%s` doesn't match format", s)
}

func parseVal(val string, env Env) string {
	if strings.Contains(val, "=") {
		if !(val == "\n" || val == "\r") {
			kv := strings.Split(val, "\n")

			if len(kv) == 1 {
				kv = strings.Split(val, "\r")
			}

			if len(kv) > 1 {
				val = kv[0]

				for i := 1; i < len(kv); i++ {
					parseLine(kv[i], env)
				}
			}
		}
	}

	return val
}
<commit_msg>updated comments<commit_after>// Package gotenv provides functionality to dynamically load the environment variables
package gotenv

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"regexp"
	"strings"
)

const (
	// Pattern for detecting valid line format
	linePattern = `\A\s*(?:export\s+)?([\w\.]+)(?:\s*=\s*|:\s+?)('(?:\'|[^'])*'|"(?:\"|[^"])*"|[^#\n]+)?\s*(?:\s*\#.*)?\z`

	// Pattern for detecting valid variable within a value
	variablePattern = `(\\)?(\$)(\{?([A-Z0-9_]+)?\}?)`
)

// Env holds key/value pair of valid environment variable
type Env map[string]string

/*
Load is a function to load a file or multiple files and then export the valid variables into environment variables if they do not exist.
When it's called with no argument, it will load `.env` file on the current path and set the environment variables.
Otherwise, it will loop over the filenames parameter and set the proper environment variables.
*/
func Load(filenames ...string) error {
	return loadenv(false, filenames...)
}

/*
OverLoad is a function to load a file or multiple files and then export and override the valid variables into environment variables.
*/
func OverLoad(filenames ...string) error {
	return loadenv(true, filenames...)
}

/*
Must is wrapper function that will panic when supplied function returns an error.
*/
func Must(fn func(filenames ...string) error, filenames ...string) {
	if err := fn(filenames...); err != nil {
		panic(err.Error())
	}
}

/*
Apply is a function to load an io Reader then export the valid variables into environment variables if they do not exist.
*/
func Apply(r io.Reader) error {
	return parset(r, false)
}

/*
OverApply is a function to load an io Reader then export and override the valid variables into environment variables.
*/
func OverApply(r io.Reader) error {
	return parset(r, true)
}

func loadenv(override bool, filenames ...string) error {
	if len(filenames) == 0 {
		filenames = []string{".env"}
	}

	for _, filename := range filenames {
		f, err := os.Open(filename)
		if err != nil {
			return err
		}

		err = parset(f, override)
		if err != nil {
			return err
		}

		f.Close()
	}

	return nil
}

// parse and set :)
func parset(r io.Reader, override bool) error {
	env, err := StrictParse(r)
	if err != nil {
		return err
	}

	for key, val := range env {
		setenv(key, val, override)
	}

	return nil
}

func setenv(key, val string, override bool) {
	if override {
		os.Setenv(key, val)
	} else {
		if _, present := os.LookupEnv(key); !present {
			os.Setenv(key, val)
		}
	}
}

// Parse is a function to parse line by line any io.Reader supplied and returns the valid Env key/value pair of valid variables.
// It expands the value of a variable from the environment variable but does not set the value to the environment itself.
// This function is skipping any invalid lines and only processing the valid one.
func Parse(r io.Reader) Env {
	env, _ := StrictParse(r)
	return env
}

// StrictParse is a function to parse line by line any io.Reader supplied and returns the valid Env key/value pair of valid variables.
// It expands the value of a variable from the environment variable but does not set the value to the environment itself.
// This function is returning an error if there are any invalid lines.
func StrictParse(r io.Reader) (Env, error) {
	env := make(Env)
	scanner := bufio.NewScanner(r)

	i := 1
	bom := string([]byte{239, 187, 191})

	for scanner.Scan() {
		line := scanner.Text()

		if i == 1 {
			line = strings.TrimPrefix(line, bom)
		}

		i++

		err := parseLine(line, env)
		if err != nil {
			return env, err
		}
	}

	return env, nil
}

func parseLine(s string, env Env) error {
	rl := regexp.MustCompile(linePattern)
	rm := rl.FindStringSubmatch(s)

	if len(rm) == 0 {
		return checkFormat(s, env)
	}

	key := rm[1]
	val := rm[2]

	// determine if string has quote prefix
	hdq := strings.HasPrefix(val, `"`)

	// determine if string has single quote prefix
	hsq := strings.HasPrefix(val, `'`)

	// trim whitespace
	val = strings.Trim(val, " ")

	// remove quotes '' or ""
	rq := regexp.MustCompile(`\A(['"])(.*)(['"])\z`)
	val = rq.ReplaceAllString(val, "$2")

	if hdq {
		val = strings.Replace(val, `\n`, "\n", -1)
		val = strings.Replace(val, `\r`, "\r", -1)

		// Unescape all characters except $ so variables can be escaped properly
		re := regexp.MustCompile(`\\([^$])`)
		val = re.ReplaceAllString(val, "$1")
	}

	rv := regexp.MustCompile(variablePattern)
	fv := func(s string) string {
		return varReplacement(s, hsq, env)
	}

	val = rv.ReplaceAllStringFunc(val, fv)
	val = parseVal(val, env)

	env[key] = val
	return nil
}

func parseExport(st string, env Env) error {
	if strings.HasPrefix(st, "export") {
		vs := strings.SplitN(st, " ", 2)

		if len(vs) > 1 {
			if _, ok := env[vs[1]]; !ok {
				return fmt.Errorf("line `%s` has an unset variable", st)
			}
		}
	}

	return nil
}

func varReplacement(s string, hsq bool, env Env) string {
	if strings.HasPrefix(s, "\\") {
		return strings.TrimPrefix(s, "\\")
	}

	if hsq {
		return s
	}

	sn := `(\$)(\{?([A-Z0-9_]+)\}?)`
	rn := regexp.MustCompile(sn)
	mn := rn.FindStringSubmatch(s)

	if len(mn) == 0 {
		return s
	}

	v := mn[3]

	replace, ok := env[v]
	if !ok {
		replace = os.Getenv(v)
	}

	return replace
}

func checkFormat(s string, env Env) error {
	st := strings.TrimSpace(s)

	if (st == "") || strings.HasPrefix(st, "#") {
		return nil
	}

	if err := parseExport(st, env); err != nil {
		return err
	}

	return fmt.Errorf("line `%s` doesn't match format", s)
}

func parseVal(val string, env Env) string {
	if strings.Contains(val, "=") {
		if !(val == "\n" || val == "\r") {
			kv := strings.Split(val, "\n")

			if len(kv) == 1 {
				kv = strings.Split(val, "\r")
			}

			if len(kv) > 1 {
				val = kv[0]

				for i := 1; i < len(kv); i++ {
					parseLine(kv[i], env)
				}
			}
		}
	}

	return val
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"github.com/yushi/gother/statusboard"
	"github.com/yushi/gother/system"
	"net/http"
	"sort"
	"time"
)

func hello_handler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Hello Go!")
}

func get_proc_load_handler() func(w http.ResponseWriter, r *http.Request) {
	type StatHistory struct {
		label string
		stat  system.SystemStat
	}
	stats := make(map[string]*system.SystemStat)

	return func(w http.ResponseWriter, r *http.Request) {
		stats[time.Now().Format("15:04:05")] = system.GetSystemStat()
		datapoints := make(map[string][]statusboard.DataPoint)
		for _, val := range []string{"load1", "load5", "load15"} {
			keys := make([]string, 0)
			for k, _ := range stats {
				keys = append(keys, k)
			}
			sort.Strings(keys)
			for _, k := range keys {
				var v float64
				s := stats[k]
				switch val {
				case "load1":
					v = s.Load.Load1
				case "load5":
					v = s.Load.Load5
				case "load15":
					v = s.Load.Load15
				}
				datapoints[val] = append(
					datapoints[val],
					statusboard.DataPoint{
						Title: k,
						Value: v,
					})
			}
		}

		graph_entries := make([]statusboard.GraphEntry, 0)
		for cpu_type, datapoint := range datapoints {
			var color string
			switch cpu_type {
			case "Used":
				color = "Red"
			case "Inactive":
				color = "Blue"
			case "Free":
				color = "Green"
			}
			graph_entries = append(graph_entries,
				statusboard.GraphEntry{
					Title:      cpu_type,
					Color:      color,
					Datapoints: datapoint,
				},
			)
		}
		jsonobj := statusboard.GraphJSON{
			Graph: statusboard.GraphData{
				Title:         "Loadavg",
				Datasequences: graph_entries,
				Total:         false,
				Type:          "line",
			},
		}

		b, _ := json.Marshal(jsonobj)
		fmt.Fprintf(w, "%s", b)

	}
}

func get_proc_mem_handler() func(w http.ResponseWriter, r *http.Request) {
	type MemStat struct {
		label   string
		meminfo *system.MemInfo
	}
	memstats := make([]MemStat, 0)

	return func(w http.ResponseWriter, r *http.Request) {

		m := MemStat{
			label:   time.Now().Format("15:04:05"),
			meminfo: system.GetMemInfo(),
		}

		memstats = append(memstats, m)

		datapoints := map[string]*[]statusboard.DataPoint{
			"Used":     new([]statusboard.DataPoint),
			"Inactive": new([]statusboard.DataPoint),
			"Free":     new([]statusboard.DataPoint),
		}

		for _, memstat := range memstats {
			for memtype, datapoint := range datapoints {
				var val float64
				switch memtype {
				case "Used":
					val = float64(memstat.meminfo.Wired) +
						float64(memstat.meminfo.Active)
				case "Inactive":
					val = float64(memstat.meminfo.Inactive)
				case "Free":
					val = float64(memstat.meminfo.Free)
				}
				*datapoint = append(*datapoint,
					statusboard.DataPoint{
						Title: memstat.label,
						Value: val,
					})
			}
		}

		graph_entries := make([]statusboard.GraphEntry, 0)
		for memtype, datapoint := range datapoints {
			var color string
			switch memtype {
			case "Used":
				color = "Red"
			case "Inactive":
				color = "Blue"
			case "Free":
				color = "Green"
			}
			graph_entries = append(graph_entries,
				statusboard.GraphEntry{
					Title:      memtype,
					Color:      color,
					Datapoints: *datapoint,
				},
			)
		}
		jsonobj := statusboard.GraphJSON{
			Graph: statusboard.GraphData{
				Title:         "Memory",
				Datasequences: graph_entries,
				Total:         false,
				Type:          "line",
			},
		}

		b, _ := json.Marshal(jsonobj)
		fmt.Fprintf(w, "%s", b)
	}
}

func main() {
	http.HandleFunc("/hello", hello_handler)
	http.HandleFunc("/proc/mem", get_proc_mem_handler())
	http.HandleFunc("/proc/cpu", get_proc_load_handler())
	http.ListenAndServe(":8080", nil)
	fmt.Println("HOGE")
}
<commit_msg>support -p(port) option<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"github.com/yushi/gother/statusboard"
	"github.com/yushi/gother/system"
	"log"
	"net/http"
	"sort"
	"time"
)

func hello_handler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Hello Go!")
}

func get_proc_load_handler() func(w http.ResponseWriter, r *http.Request) {
	type StatHistory struct {
		label string
		stat  system.SystemStat
	}
	stats := make(map[string]*system.SystemStat)

	return func(w http.ResponseWriter, r *http.Request) {
		stats[time.Now().Format("15:04:05")] = system.GetSystemStat()
		datapoints := make(map[string][]statusboard.DataPoint)
		for _, val := range []string{"load1", "load5", "load15"} {
			keys := make([]string, 0)
			for k, _ := range stats {
				keys = append(keys, k)
			}
			sort.Strings(keys)
			for _, k := range keys {
				var v float64
				s := stats[k]
				switch val {
				case "load1":
					v = s.Load.Load1
				case "load5":
					v = s.Load.Load5
				case "load15":
					v = s.Load.Load15
				}
				datapoints[val] = append(
					datapoints[val],
					statusboard.DataPoint{
						Title: k,
						Value: v,
					})
			}
		}

		graph_entries := make([]statusboard.GraphEntry, 0)
		for cpu_type, datapoint := range datapoints {
			var color string
			switch cpu_type {
			case "Used":
				color = "Red"
			case "Inactive":
				color = "Blue"
			case "Free":
				color = "Green"
			}
			graph_entries = append(graph_entries,
				statusboard.GraphEntry{
					Title:      cpu_type,
					Color:      color,
					Datapoints: datapoint,
				},
			)
		}
		jsonobj := statusboard.GraphJSON{
			Graph: statusboard.GraphData{
				Title:         "Loadavg",
				Datasequences: graph_entries,
				Total:         false,
				Type:          "line",
			},
		}

		b, _ := json.Marshal(jsonobj)
		fmt.Fprintf(w, "%s", b)

	}
}

func get_proc_mem_handler() func(w http.ResponseWriter, r *http.Request) {
	type MemStat struct {
		label   string
		meminfo *system.MemInfo
	}
	memstats := make([]MemStat, 0)

	return func(w http.ResponseWriter, r *http.Request) {

		m := MemStat{
			label:   time.Now().Format("15:04:05"),
			meminfo: system.GetMemInfo(),
		}

		memstats = append(memstats, m)

		datapoints := map[string]*[]statusboard.DataPoint{
			"Used":     new([]statusboard.DataPoint),
			"Inactive": new([]statusboard.DataPoint),
			"Free":     new([]statusboard.DataPoint),
		}

		for _, memstat := range memstats {
			for memtype, datapoint := range datapoints {
				var val float64
				switch memtype {
				case "Used":
					val = float64(memstat.meminfo.Wired) +
						float64(memstat.meminfo.Active)
				case "Inactive":
					val = float64(memstat.meminfo.Inactive)
				case "Free":
					val = float64(memstat.meminfo.Free)
				}
				*datapoint = append(*datapoint,
					statusboard.DataPoint{
						Title: memstat.label,
						Value: val,
					})
			}
		}

		graph_entries := make([]statusboard.GraphEntry, 0)
		for memtype, datapoint := range datapoints {
			var color string
			switch memtype {
			case "Used":
				color = "Red"
			case "Inactive":
				color = "Blue"
			case "Free":
				color = "Green"
			}
			graph_entries = append(graph_entries,
				statusboard.GraphEntry{
					Title:      memtype,
					Color:      color,
					Datapoints: *datapoint,
				},
			)
		}
		jsonobj := statusboard.GraphJSON{
			Graph: statusboard.GraphData{
				Title:         "Memory",
				Datasequences: graph_entries,
				Total:         false,
				Type:          "line",
			},
		}

		b, _ := json.Marshal(jsonobj)
		fmt.Fprintf(w, "%s", b)
	}
}

func main() {
	port := flag.Int("p", 9090, "listen port")
	flag.Parse()

	http.HandleFunc("/hello", hello_handler)
	http.HandleFunc("/proc/mem", get_proc_mem_handler())
	http.HandleFunc("/proc/cpu", get_proc_load_handler())

	log.Printf("About to listen on %d", *port)
	err := http.ListenAndServe(fmt.Sprintf(":%d", *port), nil)
	if err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>// goupnp is an implementation of a client for UPnP devices.
package goupnp

import (
	"encoding/xml"
	"fmt"
	"net/http"
	"net/url"
)

// Non-exhaustive set of UPnP service types.
const (
	ServiceTypeLayer3Forwarding         = "urn:schemas-upnp-org:service:Layer3Forwarding:1"
	ServiceTypeWANCommonInterfaceConfig = "WANCommonInterfaceConfig:1"
	// WANPPPConnection is typically useful with regard to the external IP and
	// port forwarding.
	ServiceTypeWANPPPConnection = "WANPPPConnection:1"
)

// Non-exhaustive set of UPnP device types.
const (
	// Device type for InternetGatewayDevice.
	// http://upnp.org/specs/gw/upnp-gw-internetgatewaydevice-v1-device.pdf
	DeviceTypeInternetGatewayDevice = "urn:schemas-upnp-org:device:InternetGatewayDevice:1"
)

type ContextError struct {
	Context string
	Err     error
}

func (err ContextError) Error() string {
	return fmt.Sprintf("%s: %v", err.Context, err.Err)
}

type MaybeRootDevice struct {
	Root *RootDevice
	Err  error
}

// DiscoverDevices attempts to find targets of the given type. searchTarget is
// typically a value from a DeviceType* constant. An error is returned for
// errors while attempting to send the query. An error or RootDevice is
// returned for each discovered service.
func DiscoverDevices(searchTarget string) ([]MaybeRootDevice, error) {
	httpu, err := NewHTTPUClient()
	if err != nil {
		return nil, err
	}
	defer httpu.Close()
	responses, err := SSDPRawSearch(httpu, string(searchTarget), 2, 3)
	if err != nil {
		return nil, err
	}

	results := make([]MaybeRootDevice, len(responses))
	for i, response := range responses {
		maybe := &results[i]
		loc, err := response.Location()
		if err != nil {
			maybe.Err = ContextError{"unexpected bad location from search", err}
			continue
		}
		locStr := loc.String()
		root := new(RootDevice)
		if err := requestXml(locStr, DeviceXMLNamespace, root); err != nil {
			maybe.Err = ContextError{fmt.Sprintf("error requesting root device details from %q", locStr), err}
			continue
		}
		urlBase, err := url.Parse(root.URLBaseStr)
		if err != nil {
			maybe.Err = ContextError{fmt.Sprintf("error parsing URLBase %q from %q: %v", root.URLBaseStr, locStr), err}
			continue
		}
		root.SetURLBase(urlBase)
		maybe.Root = root
	}

	return results, nil
}

func requestXml(url string, defaultSpace string, doc interface{}) error {
	resp, err := http.Get(url)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode != 200 {
		return fmt.Errorf("goupnp: got response status %s from %q",
			resp.Status, url)
	}

	decoder := xml.NewDecoder(resp.Body)
	decoder.DefaultSpace = defaultSpace

	return decoder.Decode(doc)
}
<commit_msg>Correct service names, add standards reference.<commit_after>// goupnp is an implementation of a client for UPnP devices.
package goupnp

import (
	"encoding/xml"
	"fmt"
	"net/http"
	"net/url"
)

// Non-exhaustive set of UPnP service types.
const (
	ServiceTypeLayer3Forwarding         = "urn:schemas-upnp-org:service:Layer3Forwarding:1"
	ServiceTypeWANCommonInterfaceConfig = "urn:schemas-upnp-org:WANCommonInterfaceConfig:1"
	// WANPPPConnection is typically useful with regard to the external IP and
	// port forwarding.
	// http://upnp.org/specs/gw/UPnP-gw-WANPPPConnection-v1-Service.pdf
	ServiceTypeWANPPPConnection = "urn:schemas-upnp-org:WANPPPConnection:1"
)

// Non-exhaustive set of UPnP device types.
const (
	// Device type for InternetGatewayDevice.
	// http://upnp.org/specs/gw/upnp-gw-internetgatewaydevice-v1-device.pdf
	DeviceTypeInternetGatewayDevice = "urn:schemas-upnp-org:device:InternetGatewayDevice:1"
)

type ContextError struct {
	Context string
	Err     error
}

func (err ContextError) Error() string {
	return fmt.Sprintf("%s: %v", err.Context, err.Err)
}

type MaybeRootDevice struct {
	Root *RootDevice
	Err  error
}

// DiscoverDevices attempts to find targets of the given type. searchTarget is
// typically a value from a DeviceType* constant. An error is returned for
// errors while attempting to send the query. An error or RootDevice is
// returned for each discovered service.
func DiscoverDevices(searchTarget string) ([]MaybeRootDevice, error) {
	httpu, err := NewHTTPUClient()
	if err != nil {
		return nil, err
	}
	defer httpu.Close()
	responses, err := SSDPRawSearch(httpu, string(searchTarget), 2, 3)
	if err != nil {
		return nil, err
	}

	results := make([]MaybeRootDevice, len(responses))
	for i, response := range responses {
		maybe := &results[i]
		loc, err := response.Location()
		if err != nil {
			maybe.Err = ContextError{"unexpected bad location from search", err}
			continue
		}
		locStr := loc.String()
		root := new(RootDevice)
		if err := requestXml(locStr, DeviceXMLNamespace, root); err != nil {
			maybe.Err = ContextError{fmt.Sprintf("error requesting root device details from %q", locStr), err}
			continue
		}
		urlBase, err := url.Parse(root.URLBaseStr)
		if err != nil {
			maybe.Err = ContextError{fmt.Sprintf("error parsing URLBase %q from %q: %v", root.URLBaseStr, locStr), err}
			continue
		}
		root.SetURLBase(urlBase)
		maybe.Root = root
	}

	return results, nil
}

func requestXml(url string, defaultSpace string, doc interface{}) error {
	resp, err := http.Get(url)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode != 200 {
		return fmt.Errorf("goupnp: got response status %s from %q",
			resp.Status, url)
	}

	decoder := xml.NewDecoder(resp.Body)
	decoder.DefaultSpace = defaultSpace

	return decoder.Decode(doc)
}
<|endoftext|>


<commit_before>package autoupdate

import (
	"bytes"
	"compress/bzip2"
	"io"
	"io/ioutil"
	"net/http"
	"os"

	"github.com/blang/semver"
	"github.com/getlantern/flashlight/pro"
	"github.com/getlantern/flashlight/proxied"
	"github.com/getlantern/go-update"
)

type Updater interface {
	// PublishProgress: publish percentage of update already downloaded
	Progress(int)
}

// byteCounter wraps an existing io.Reader and keeps track of the byte
// count while downloading the latest update
type byteCounter struct {
	io.Reader // Underlying io.Reader to track bytes transferred
	Updater
	total    int64   // Total bytes transferred
	length   int64   // Expected length
	progress float64 // How much of the update has been downloaded
}

func (pt *byteCounter) Read(p []byte) (int, error) {
	n, err := pt.Reader.Read(p)
	if n > 0 {
		pt.total += int64(n)
		percentage := float64(pt.total) / float64(pt.length) * float64(100)
		pt.Updater.Progress(int(percentage))
	}
	return n, err
}

func doCheckUpdate(version, URL string, publicKey []byte) (string, error) {

	log.Debugf("Checking for new mobile version; current version: %s", version)

	httpClient := pro.GetHTTPClient()

	// specify go-update should use our httpClient
	update.SetHttpClient(httpClient)

	res, err := checkUpdate(version, URL, publicKey)
	if err != nil {
		log.Errorf("Error checking for update for mobile: %v", err)
		return "", err
	}

	if res == nil {
		log.Debugf("No new version available!")
		return "", nil
	}

	v, err := semver.Make(version)
	if err != nil {
		log.Errorf("Error checking for update; could not parse version number: %v", err)
		return "", err
	}

	if isNewerVersion(v, res.Version) {
		log.Debugf("Newer version of Lantern mobile available! %s at %s", res.Version, res.Url)
		return res.Url, nil
	}

	return "", nil
}

// CheckMobileUpdate checks if a new update is available for mobile.
func CheckMobileUpdate(updateServer, appVersion string) (string, error) {
	return doCheckUpdate(appVersion,
		updateServer+"/update", []byte(PackagePublicKey))
}

// UpdateMobile downloads the latest APK from the given url to file apkPath.
func UpdateMobile(url, apkPath string, updater Updater) error {
	out, err := os.Create(apkPath)
	if err != nil {
		log.Error(err)
		return err
	}
	defer out.Close()
	return doUpdateMobile(url, out, updater)
}

func doUpdateMobile(url string, out *os.File, updater Updater) error {
	var req *http.Request
	var res *http.Response
	var err error

	log.Debugf("Attempting to download APK from %s", url)

	httpClient := pro.GetHTTPClient()

	if req, err = http.NewRequest("GET", url, nil); err != nil {
		log.Errorf("Error downloading update: %v", err)
		return err
	}

	req.Header.Add("Accept-Encoding", "gzip")

	frontedURL := *req.URL
	frontedURL.Host = "d2yl1zps97e5mx.cloudfront.net"
	proxied.PrepareForFronting(req, frontedURL.String())

	if res, err = httpClient.Do(req); err != nil {
		log.Errorf("Error requesting update: %v", err)
		return err
	}

	defer res.Body.Close()

	// We use a special byteCounter that storres a reference
	// to the updater interface to make it easy to publish progress
	// for how much of the update has been downloaded already.
	bytespt := &byteCounter{Updater: updater,
		Reader: res.Body, length: res.ContentLength}

	contents, err := ioutil.ReadAll(bytespt)
	if err != nil {
		log.Errorf("Error reading update: %v", err)
		return err
	}

	_, err = io.Copy(out, bzip2.NewReader(bytes.NewReader(contents)))
	if err != nil {
		log.Errorf("Error copying update: %v", err)
		return err
	}

	return nil
}
<commit_msg>don't use pro.GetHTTPClient<commit_after>package autoupdate

import (
	"bytes"
	"compress/bzip2"
	"io"
	"io/ioutil"
	"net/http"
	"os"

	"github.com/blang/semver"
	"github.com/getlantern/flashlight/proxied"
	"github.com/getlantern/go-update"
)

var (
	httpClient = &http.Client{
		Transport: proxied.ParallelPreferChained(),
	}
)

type Updater interface {
	// PublishProgress: publish percentage of update already downloaded
	Progress(int)
}

// byteCounter wraps an existing io.Reader and keeps track of the byte
// count while downloading the latest update
type byteCounter struct {
	io.Reader // Underlying io.Reader to track bytes transferred
	Updater
	total    int64   // Total bytes transferred
	length   int64   // Expected length
	progress float64 // How much of the update has been downloaded
}

func (pt *byteCounter) Read(p []byte) (int, error) {
	n, err := pt.Reader.Read(p)
	if n > 0 {
		pt.total += int64(n)
		percentage := float64(pt.total) / float64(pt.length) * float64(100)
		pt.Updater.Progress(int(percentage))
	}
	return n, err
}

func doCheckUpdate(version, URL string, publicKey []byte) (string, error) {

	log.Debugf("Checking for new mobile version; current version: %s", version)

	// specify go-update should use our httpClient
	update.SetHttpClient(httpClient)

	res, err := checkUpdate(version, URL, publicKey)
	if err != nil {
		log.Errorf("Error checking for update for mobile: %v", err)
		return "", err
	}

	if res == nil {
		log.Debugf("No new version available!")
		return "", nil
	}

	v, err := semver.Make(version)
	if err != nil {
		log.Errorf("Error checking for update; could not parse version number: %v", err)
		return "", err
	}

	if isNewerVersion(v, res.Version) {
		log.Debugf("Newer version of Lantern mobile available! %s at %s", res.Version, res.Url)
		return res.Url, nil
	}

	return "", nil
}

// CheckMobileUpdate checks if a new update is available for mobile.
func CheckMobileUpdate(updateServer, appVersion string) (string, error) {
	return doCheckUpdate(appVersion,
		updateServer+"/update", []byte(PackagePublicKey))
}

// UpdateMobile downloads the latest APK from the given url to file apkPath.
func UpdateMobile(url, apkPath string, updater Updater) error {
	out, err := os.Create(apkPath)
	if err != nil {
		log.Error(err)
		return err
	}
	defer out.Close()
	return doUpdateMobile(url, out, updater)
}

func doUpdateMobile(url string, out *os.File, updater Updater) error {
	var req *http.Request
	var res *http.Response
	var err error

	log.Debugf("Attempting to download APK from %s", url)

	if req, err = http.NewRequest("GET", url, nil); err != nil {
		log.Errorf("Error downloading update: %v", err)
		return err
	}

	req.Header.Add("Accept-Encoding", "gzip")

	frontedURL := *req.URL
	frontedURL.Host = "d2yl1zps97e5mx.cloudfront.net"
	proxied.PrepareForFronting(req, frontedURL.String())

	if res, err = httpClient.Do(req); err != nil {
		log.Errorf("Error requesting update: %v", err)
		return err
	}

	defer res.Body.Close()

	// We use a special byteCounter that storres a reference
	// to the updater interface to make it easy to publish progress
	// for how much of the update has been downloaded already.
	bytespt := &byteCounter{Updater: updater,
		Reader: res.Body, length: res.ContentLength}

	contents, err := ioutil.ReadAll(bytespt)
	if err != nil {
		log.Errorf("Error reading update: %v", err)
		return err
	}

	_, err = io.Copy(out, bzip2.NewReader(bytes.NewReader(contents)))
	if err != nil {
		log.Errorf("Error copying update: %v", err)
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>package autoupdate

import (
	"bytes"
	"compress/bzip2"
	"io"
	"io/ioutil"
	"net/http"
	"os"

	"github.com/blang/semver"
	"github.com/getlantern/flashlight/pro"
	"github.com/getlantern/go-update"
)

type Updater interface {
	// PublishProgress: publish percentage of update already downloaded
	Progress(int)
}

// byteCounter wraps an existing io.Reader and keeps track of the byte
// count while downloading the latest update
type byteCounter struct {
	io.Reader // Underlying io.Reader to track bytes transferred
	Updater
	total    int64   // Total bytes transferred
	length   int64   // Expected length
	progress float64 // How much of the update has been downloaded
}

func (pt *byteCounter) Read(p []byte) (int, error) {
	n, err := pt.Reader.Read(p)
	if n > 0 {
		pt.total += int64(n)
		percentage := float64(pt.total) / float64(pt.length) * float64(100)
		pt.Updater.Progress(int(percentage))
	}
	return n, err
}

func doCheckUpdate(version, URL string, publicKey []byte) (string, error) {

	log.Debugf("Checking for new mobile version; current version: %s", version)

	httpClient := pro.GetHTTPClient()

	// specify go-update should use our httpClient
	update.SetHttpClient(httpClient)

	res, err := checkUpdate(version, URL, publicKey)
	if err != nil {
		log.Errorf("Error checking for update for mobile: %v", err)
		return "", err
	}

	if res == nil {
		log.Debugf("No new version available!")
		return "", nil
	}

	v, err := semver.Make(version)
	if err != nil {
		log.Errorf("Error checking for update; could not parse version number: %v", err)
		return "", err
	}

	if isNewerVersion(v, res.Version) {
		log.Debugf("Newer version of Lantern mobile available! %s at %s", res.Version, res.Url)
		return res.Url, nil
	}

	return "", nil
}

// CheckMobileUpdate checks if a new update is available for mobile.
func CheckMobileUpdate(updateServer, appVersion string) (string, error) {
	return doCheckUpdate(appVersion,
		updateServer+"/update", []byte(PackagePublicKey))
}

// UpdateMobile downloads the latest APK from the given url to file apkPath.
func UpdateMobile(url, apkPath string, updater Updater) error {
	out, err := os.Create(apkPath)
	if err != nil {
		log.Error(err)
		return err
	}
	defer out.Close()
	return doUpdateMobile(url, out, updater)
}

func doUpdateMobile(url string, out *os.File, updater Updater) error {
	var req *http.Request
	var res *http.Response
	var err error

	log.Debugf("Attempting to download APK from %s", url)

	httpClient := pro.GetHTTPClient()

	if req, err = http.NewRequest("GET", url, nil); err != nil {
		log.Errorf("Error downloading update: %v", err)
		return err
	}

	req.Header.Add("Accept-Encoding", "gzip")

	if res, err = httpClient.Do(req); err != nil {
		log.Errorf("Error requesting update: %v", err)
		return err
	}

	defer res.Body.Close()

	// We use a special byteCounter that storres a reference
	// to the updater interface to make it easy to publish progress
	// for how much of the update has been downloaded already.
	bytespt := &byteCounter{Updater: updater,
		Reader: res.Body, length: res.ContentLength}

	contents, err := ioutil.ReadAll(bytespt)
	if err != nil {
		log.Errorf("Error reading update: %v", err)
		return err
	}

	_, err = io.Copy(out, bzip2.NewReader(bytes.NewReader(contents)))
	if err != nil {
		log.Errorf("Error copying update: %v", err)
		return err
	}

	return nil
}
<commit_msg>fix error<commit_after>package autoupdate

import (
	"bytes"
	"compress/bzip2"
	"io"
	"io/ioutil"
	"net/http"
	"os"

	"github.com/blang/semver"
	"github.com/getlantern/flashlight/proxied"
	"github.com/getlantern/go-update"
)

type Updater interface {
	// PublishProgress: publish percentage of update already downloaded
	Progress(int)
}

// byteCounter wraps an existing io.Reader and keeps track of the byte
// count while downloading the latest update
type byteCounter struct {
	io.Reader // Underlying io.Reader to track bytes transferred
	Updater
	total    int64   // Total bytes transferred
	length   int64   // Expected length
	progress float64 // How much of the update has been downloaded
}

func (pt *byteCounter) Read(p []byte) (int, error) {
	n, err := pt.Reader.Read(p)
	if n > 0 {
		pt.total += int64(n)
		percentage := float64(pt.total) / float64(pt.length) * float64(100)
		pt.Updater.Progress(int(percentage))
	}
	return n, err
}

func doCheckUpdate(version, URL string, publicKey []byte) (string, error) {

	log.Debugf("Checking for new mobile version; current version: %s", version)

	httpClient := proxied.GetHTTPClient()

	// specify go-update should use our httpClient
	update.SetHttpClient(httpClient)

	res, err := checkUpdate(version, URL, publicKey)
	if err != nil {
		log.Errorf("Error checking for update for mobile: %v", err)
		return "", err
	}

	if res == nil {
		log.Debugf("No new version available!")
		return "", nil
	}

	v, err := semver.Make(version)
	if err != nil {
		log.Errorf("Error checking for update; could not parse version number: %v", err)
		return "", err
	}

	if isNewerVersion(v, res.Version) {
		log.Debugf("Newer version of Lantern mobile available! %s at %s", res.Version, res.Url)
		return res.Url, nil
	}

	return "", nil
}

// CheckMobileUpdate checks if a new update is available for mobile.
func CheckMobileUpdate(updateServer, appVersion string) (string, error) {
	return doCheckUpdate(appVersion,
		updateServer+"/update", []byte(PackagePublicKey))
}

// UpdateMobile downloads the latest APK from the given url to file apkPath.
func UpdateMobile(url, apkPath string, updater Updater) error {
	out, err := os.Create(apkPath)
	if err != nil {
		log.Error(err)
		return err
	}
	defer out.Close()
	return doUpdateMobile(url, out, updater)
}

func doUpdateMobile(url string, out *os.File, updater Updater) error {
	var req *http.Request
	var res *http.Response
	var err error

	log.Debugf("Attempting to download APK from %s", url)

	httpClient := proxied.GetHTTPClient()

	if req, err = http.NewRequest("GET", url, nil); err != nil {
		log.Errorf("Error downloading update: %v", err)
		return err
	}

	req.Header.Add("Accept-Encoding", "gzip")

	if res, err = httpClient.Do(req); err != nil {
		log.Errorf("Error requesting update: %v", err)
		return err
	}

	defer res.Body.Close()

	// We use a special byteCounter that storres a reference
	// to the updater interface to make it easy to publish progress
	// for how much of the update has been downloaded already.
	bytespt := &byteCounter{Updater: updater,
		Reader: res.Body, length: res.ContentLength}

	contents, err := ioutil.ReadAll(bytespt)
	if err != nil {
		log.Errorf("Error reading update: %v", err)
		return err
	}

	_, err = io.Copy(out, bzip2.NewReader(bytes.NewReader(contents)))
	if err != nil {
		log.Errorf("Error copying update: %v", err)
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"

	"github.com/urfave/cli"
)

var commandRehash = cli.Command{
	Name:      "rehash",
	Aliases:   []string{"r"},
	Usage:     "Rehash shim dir",
	ArgsUsage: "[options...]",
	Flags: []cli.Flag{
		cli.BoolFlag{
			Name:  "clean, c",
			Usage: "Only remove all comannd in shims",
		},
		cli.BoolFlag{
			Name:  "append, a",
			Usage: "Append a comannd to current shims",
		},
	},

	Action: rehash,
}

func rehash(c *cli.Context) {
	sdir := filepath.Join(envHome, "shims")
	tdir := filepath.Join(envHome, "tmp")
	if !c.Bool("append") {
		os.RemoveAll(sdir)
	}
	os.RemoveAll(tdir)
	if c.Bool("clean") {
		return
	}
	os.Mkdir(sdir, 0777)
	os.Mkdir(tdir, 0777)
	SearchConfig("", makeShimCommands)
}

func makeShimCommands(cmd string, fname string) *Config {
	makeShimCommand(fname)
	return nil
}
func makeShimCommand(fname string) bool {
	if isV {
		fmt.Println("search:", fname)
	}
	if _, err := os.Stat(fname); err != nil {
		return false
	}
	if isV {
		fmt.Println("File found.:", fname)
	}
	m := Config{}
	if err := LoadYaml(&m, fname); err != nil {
		if isV {
			fmt.Println("  File can not load.:", fname)
		}
		return false
	}
	if m.Commands == nil {
		if isV {
			fmt.Println("  Illigal file format.:", fname)
		}
		return false
	}
	shimDir := filepath.Join(envHome, "shims")
	for key := range m.Commands {
		if runtime.GOOS == `windows` {
			ioutil.WriteFile(filepath.Join(shimDir, key+`.bat`),
				[]byte("@echo off\nset DCENV_COMMAND="+key+"\ndcenv exec \""+key+"\" %*\n"),
				0777)
		} else {
			ioutil.WriteFile(filepath.Join(shimDir, key),
				[]byte("#!/bin/bash\nexport DCENV_COMMAND="+key+"\ndcenv exec \""+key+"\" \"$@\"\n"),
				0777)
		}
		if isV {
			fmt.Println("Write command in shims.:", key)
		}
	}
	return true
}
<commit_msg>Fix 'rehash' command<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"

	"github.com/urfave/cli"
)

var commandRehash = cli.Command{
	Name:      "rehash",
	Aliases:   []string{"r"},
	Usage:     "Rehash shim dir",
	ArgsUsage: "[options...]",
	Flags: []cli.Flag{
		cli.BoolFlag{
			Name:  "clean, c",
			Usage: "Only remove all comannd in shims",
		},
		cli.BoolFlag{
			Name:  "append, a",
			Usage: "Append a comannd to current shims",
		},
	},

	Action: rehash,
}

func rehash(c *cli.Context) {
	sdir := filepath.Join(envHome, "shims")
	tdir := filepath.Join(envHome, "tmp")
	i := 0
	e := error(nil)
	if !c.Bool("append") {
		for i = 0; i < 10; i++ {
			e = os.RemoveAll(sdir)
			if e == nil {
				break
			}
		}
		if e == nil {
			for i = 0; i < 10; i++ {
				e = os.Mkdir(sdir, 0777)
				if e == nil {
					break
				}
			}
		}
	}
	e = nil
	for i = 0; i < 10; i++ {
		e = os.RemoveAll(tdir)
		if e == nil {
			break
		}
	}
	if e == nil {
		for i = 0; i < 10; i++ {
			e = os.Mkdir(tdir, 0777)
			if e == nil {
				break
			}
		}
	}
	if c.Bool("clean") {
		return
	}
	SearchConfig("", makeShimCommands)
}

func makeShimCommands(cmd string, fname string) *Config {
	makeShimCommand(fname)
	return nil
}
func makeShimCommand(fname string) bool {
	if isV {
		fmt.Println("search:", fname)
	}
	if _, err := os.Stat(fname); err != nil {
		return false
	}
	if isV {
		fmt.Println("File found.:", fname)
	}
	m := Config{}
	if err := LoadYaml(&m, fname); err != nil {
		if isV {
			fmt.Println("  File can not load.:", fname)
		}
		return false
	}
	if m.Commands == nil {
		if isV {
			fmt.Println("  Illigal file format.:", fname)
		}
		return false
	}
	shimDir := filepath.Join(envHome, "shims")
	for key := range m.Commands {
		if runtime.GOOS == `windows` {
			ioutil.WriteFile(filepath.Join(shimDir, key+`.bat`),
				[]byte("@echo off\nset DCENV_COMMAND="+key+"\ndcenv exec \""+key+"\" %*\n"),
				0777)
		} else {
			ioutil.WriteFile(filepath.Join(shimDir, key),
				[]byte("#!/bin/bash\nexport DCENV_COMMAND="+key+"\ndcenv exec \""+key+"\" \"$@\"\n"),
				0777)
		}
		if isV {
			fmt.Println("Write command in shims.:", key)
		}
	}
	return true
}
<|endoftext|>


<commit_before>package render

import (
	"bytes"
	"fmt"
	"html/template"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"strings"
)

const (
	// ContentType header constant.
	ContentType = "Content-Type"
	// ContentLength header constant.
	ContentLength = "Content-Length"
	// ContentBinary header value for binary data.
	ContentBinary = "application/octet-stream"
	// ContentJSON header value for JSON data.
	ContentJSON = "application/json"
	// ContentJSONP header value for JSONP data.
	ContentJSONP = "application/javascript"
	// ContentHTML header value for HTML data.
	ContentHTML = "text/html"
	// ContentXHTML header value for XHTML data.
	ContentXHTML = "application/xhtml+xml"
	// ContentXML header value for XML data.
	ContentXML = "text/xml"
	// Default character encoding.
	defaultCharset = "UTF-8"
)

// Included helper functions for use when rendering HTML.
var helperFuncs = template.FuncMap{
	"yield": func() (string, error) {
		return "", fmt.Errorf("yield called with no layout defined")
	},
	"current": func() (string, error) {
		return "", nil
	},
}

// Delims represents a set of Left and Right delimiters for HTML template rendering.
type Delims struct {
	// Left delimiter, defaults to {{.
	Left string
	// Right delimiter, defaults to }}.
	Right string
}

// Options is a struct for specifying configuration options for the render.Render object.
type Options struct {
	// Directory to load templates. Default is "templates".
	Directory string
	// Asset function to use in place of directory. Defaults to nil.
	Asset func(name string) ([]byte, error)
	// AssetNames function to use in place of directory. Defaults to nil.
	AssetNames func() []string
	// Layout template name. Will not render a layout if blank (""). Defaults to blank ("").
	Layout string
	// Extensions to parse template files from. Defaults to [".tmpl"].
	Extensions []string
	// Funcs is a slice of FuncMaps to apply to the template upon compilation. This is useful for helper functions. Defaults to [].
	Funcs []template.FuncMap
	// Delims sets the action delimiters to the specified strings in the Delims struct.
	Delims Delims
	// Appends the given character set to the Content-Type header. Default is "UTF-8".
	Charset string
	// Outputs human readable JSON.
	IndentJSON bool
	// Outputs human readable XML. Default is false.
	IndentXML bool
	// Prefixes the JSON output with the given bytes. Default is false.
	PrefixJSON []byte
	// Prefixes the XML output with the given bytes.
	PrefixXML []byte
	// Allows changing of output to XHTML instead of HTML. Default is "text/html"
	HTMLContentType string
	// If IsDevelopment is set to true, this will recompile the templates on every request. Default is false.
	IsDevelopment bool
	// Unescape HTML characters "&<>" to their original values. Default is false.
	UnEscapeHTML bool
	// Streams JSON responses instead of marshalling prior to sending. Default is false.
	StreamingJSON bool
}

// HTMLOptions is a struct for overriding some rendering Options for specific HTML call.
type HTMLOptions struct {
	// Layout template name. Overrides Options.Layout.
	Layout string
}

// Render is a service that provides functions for easily writing JSON, XML,
// binary data, and HTML templates out to a HTTP Response.
type Render struct {
	// Customize Secure with an Options struct.
	opt             Options
	templates       *template.Template
	compiledCharset string
}

// New constructs a new Render instance with the supplied options.
func New(options ...Options) *Render {
	var o Options
	if len(options) == 0 {
		o = Options{}
	} else {
		o = options[0]
	}

	r := Render{
		opt: o,
	}

	r.prepareOptions()
	r.compileTemplates()

	return &r
}

func (r *Render) prepareOptions() {
	// Fill in the defaults if need be.
	if len(r.opt.Charset) == 0 {
		r.opt.Charset = defaultCharset
	}
	r.compiledCharset = "; charset=" + r.opt.Charset

	if len(r.opt.Directory) == 0 {
		r.opt.Directory = "templates"
	}
	if len(r.opt.Extensions) == 0 {
		r.opt.Extensions = []string{".tmpl"}
	}
	if len(r.opt.HTMLContentType) == 0 {
		r.opt.HTMLContentType = ContentHTML
	}
}

func (r *Render) compileTemplates() {
	if r.opt.Asset == nil || r.opt.AssetNames == nil {
		r.compileTemplatesFromDir()
		return
	}
	r.compileTemplatesFromAsset()
}

func (r *Render) compileTemplatesFromDir() {
	dir := r.opt.Directory
	r.templates = template.New(dir)
	r.templates.Delims(r.opt.Delims.Left, r.opt.Delims.Right)

	// Walk the supplied directory and compile any files that match our extension list.
	filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
		rel, err := filepath.Rel(dir, path)
		if err != nil {
			return err
		}

		ext := ""
		if strings.Index(rel, ".") != -1 {
			ext = "." + strings.Join(strings.Split(rel, ".")[1:], ".")
		}

		for _, extension := range r.opt.Extensions {
			if ext == extension {

				buf, err := ioutil.ReadFile(path)
				if err != nil {
					panic(err)
				}

				name := (rel[0 : len(rel)-len(ext)])
				tmpl := r.templates.New(filepath.ToSlash(name))

				// Add our funcmaps.
				for _, funcs := range r.opt.Funcs {
					tmpl.Funcs(funcs)
				}

				// Break out if this parsing fails. We don't want any silent server starts.
				template.Must(tmpl.Funcs(helperFuncs).Parse(string(buf)))
				break
			}
		}

		return nil
	})
}

func (r *Render) compileTemplatesFromAsset() {
	dir := r.opt.Directory
	r.templates = template.New(dir)
	r.templates.Delims(r.opt.Delims.Left, r.opt.Delims.Right)

	for _, path := range r.opt.AssetNames() {
		if !strings.HasPrefix(path, dir) {
			continue
		}

		rel, err := filepath.Rel(dir, path)
		if err != nil {
			panic(err)
		}

		ext := ""
		if strings.Index(rel, ".") != -1 {
			ext = "." + strings.Join(strings.Split(rel, ".")[1:], ".")
		}

		for _, extension := range r.opt.Extensions {
			if ext == extension {

				buf, err := r.opt.Asset(path)
				if err != nil {
					panic(err)
				}

				name := (rel[0 : len(rel)-len(ext)])
				tmpl := r.templates.New(filepath.ToSlash(name))

				// Add our funcmaps.
				for _, funcs := range r.opt.Funcs {
					tmpl.Funcs(funcs)
				}

				// Break out if this parsing fails. We don't want any silent server starts.
				template.Must(tmpl.Funcs(helperFuncs).Parse(string(buf)))
				break
			}
		}
	}
}

// Render is the generic function called by XML, JSON, Data, HTML, and can be called by custom implementations.
func (r *Render) Render(w http.ResponseWriter, e Engine, data interface{}) {
	err := e.Render(w, data)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

// XML marshals the given interface object and writes the XML response.
func (r *Render) XML(w http.ResponseWriter, status int, v interface{}) {
	head := Head{
		ContentType: ContentXML + r.compiledCharset,
		Status:      status,
	}

	x := XML{
		Head:   head,
		Indent: r.opt.IndentXML,
		Prefix: r.opt.PrefixXML,
	}

	r.Render(w, x, v)
}

// JSON marshals the given interface object and writes the JSON response.
func (r *Render) JSON(w http.ResponseWriter, status int, v interface{}) {
	head := Head{
		ContentType: ContentJSON + r.compiledCharset,
		Status:      status,
	}

	j := JSON{
		Head:          head,
		Indent:        r.opt.IndentJSON,
		Prefix:        r.opt.PrefixJSON,
		UnEscapeHTML:  r.opt.UnEscapeHTML,
		StreamingJSON: r.opt.StreamingJSON,
	}

	r.Render(w, j, v)
}

// JSONP marshals the given interface object and writes the JSON response.
func (r *Render) JSONP(w http.ResponseWriter, status int, callback string, v interface{}) {
	head := Head{
		ContentType: ContentJSONP + r.compiledCharset,
		Status:      status,
	}

	j := JSONP{
		Head:     head,
		Indent:   r.opt.IndentJSON,
		Callback: callback,
	}

	r.Render(w, j, v)
}

// Data writes out the raw bytes as binary data.
func (r *Render) Data(w http.ResponseWriter, status int, v []byte) {
	head := Head{
		ContentType: ContentBinary,
		Status:      status,
	}

	d := Data{
		Head: head,
	}

	r.Render(w, d, v)
}

// HTML builds up the response from the specified template and bindings.
func (r *Render) HTML(w http.ResponseWriter, status int, name string, binding interface{}, htmlOpt ...HTMLOptions) {
	// If we are in development mode, recompile the templates on every HTML request.
	if r.opt.IsDevelopment {
		r.compileTemplates()
	}

	opt := r.prepareHTMLOptions(htmlOpt)

	// Assign a layout if there is one.
	if len(opt.Layout) > 0 {
		r.addYield(name, binding)
		name = opt.Layout
	}

	head := Head{
		ContentType: r.opt.HTMLContentType + r.compiledCharset,
		Status:      status,
	}

	h := HTML{
		Head:      head,
		Name:      name,
		Templates: r.templates,
	}

	r.Render(w, h, binding)
}

func (r *Render) execute(name string, binding interface{}) (*bytes.Buffer, error) {
	buf := new(bytes.Buffer)
	return buf, r.templates.ExecuteTemplate(buf, name, binding)
}

func (r *Render) addYield(name string, binding interface{}) {
	funcs := template.FuncMap{
		"yield": func() (template.HTML, error) {
			buf, err := r.execute(name, binding)
			// Return safe HTML here since we are rendering our own template.
			return template.HTML(buf.String()), err
		},
		"current": func() (string, error) {
			return name, nil
		},
	}
	r.templates.Funcs(funcs)
}

func (r *Render) prepareHTMLOptions(htmlOpt []HTMLOptions) HTMLOptions {
	if len(htmlOpt) > 0 {
		return htmlOpt[0]
	}

	return HTMLOptions{
		Layout: r.opt.Layout,
	}
}
<commit_msg>extension should start from last dot.(both python and golang)<commit_after>package render

import (
	"bytes"
	"fmt"
	"html/template"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"strings"
)

const (
	// ContentType header constant.
	ContentType = "Content-Type"
	// ContentLength header constant.
	ContentLength = "Content-Length"
	// ContentBinary header value for binary data.
	ContentBinary = "application/octet-stream"
	// ContentJSON header value for JSON data.
	ContentJSON = "application/json"
	// ContentJSONP header value for JSONP data.
	ContentJSONP = "application/javascript"
	// ContentHTML header value for HTML data.
	ContentHTML = "text/html"
	// ContentXHTML header value for XHTML data.
	ContentXHTML = "application/xhtml+xml"
	// ContentXML header value for XML data.
	ContentXML = "text/xml"
	// Default character encoding.
	defaultCharset = "UTF-8"
)

// Included helper functions for use when rendering HTML.
var helperFuncs = template.FuncMap{
	"yield": func() (string, error) {
		return "", fmt.Errorf("yield called with no layout defined")
	},
	"current": func() (string, error) {
		return "", nil
	},
}

// Delims represents a set of Left and Right delimiters for HTML template rendering.
type Delims struct {
	// Left delimiter, defaults to {{.
	Left string
	// Right delimiter, defaults to }}.
	Right string
}

// Options is a struct for specifying configuration options for the render.Render object.
type Options struct {
	// Directory to load templates. Default is "templates".
	Directory string
	// Asset function to use in place of directory. Defaults to nil.
	Asset func(name string) ([]byte, error)
	// AssetNames function to use in place of directory. Defaults to nil.
	AssetNames func() []string
	// Layout template name. Will not render a layout if blank (""). Defaults to blank ("").
	Layout string
	// Extensions to parse template files from. Defaults to [".tmpl"].
	Extensions []string
	// Funcs is a slice of FuncMaps to apply to the template upon compilation. This is useful for helper functions. Defaults to [].
	Funcs []template.FuncMap
	// Delims sets the action delimiters to the specified strings in the Delims struct.
	Delims Delims
	// Appends the given character set to the Content-Type header. Default is "UTF-8".
	Charset string
	// Outputs human readable JSON.
	IndentJSON bool
	// Outputs human readable XML. Default is false.
	IndentXML bool
	// Prefixes the JSON output with the given bytes. Default is false.
	PrefixJSON []byte
	// Prefixes the XML output with the given bytes.
	PrefixXML []byte
	// Allows changing of output to XHTML instead of HTML. Default is "text/html"
	HTMLContentType string
	// If IsDevelopment is set to true, this will recompile the templates on every request. Default is false.
	IsDevelopment bool
	// Unescape HTML characters "&<>" to their original values. Default is false.
	UnEscapeHTML bool
	// Streams JSON responses instead of marshalling prior to sending. Default is false.
	StreamingJSON bool
}

// HTMLOptions is a struct for overriding some rendering Options for specific HTML call.
type HTMLOptions struct {
	// Layout template name. Overrides Options.Layout.
	Layout string
}

// Render is a service that provides functions for easily writing JSON, XML,
// binary data, and HTML templates out to a HTTP Response.
type Render struct {
	// Customize Secure with an Options struct.
	opt             Options
	templates       *template.Template
	compiledCharset string
}

// New constructs a new Render instance with the supplied options.
func New(options ...Options) *Render {
	var o Options
	if len(options) == 0 {
		o = Options{}
	} else {
		o = options[0]
	}

	r := Render{
		opt: o,
	}

	r.prepareOptions()
	r.compileTemplates()

	return &r
}

func (r *Render) prepareOptions() {
	// Fill in the defaults if need be.
	if len(r.opt.Charset) == 0 {
		r.opt.Charset = defaultCharset
	}
	r.compiledCharset = "; charset=" + r.opt.Charset

	if len(r.opt.Directory) == 0 {
		r.opt.Directory = "templates"
	}
	if len(r.opt.Extensions) == 0 {
		r.opt.Extensions = []string{".tmpl"}
	}
	if len(r.opt.HTMLContentType) == 0 {
		r.opt.HTMLContentType = ContentHTML
	}
}

func (r *Render) compileTemplates() {
	if r.opt.Asset == nil || r.opt.AssetNames == nil {
		r.compileTemplatesFromDir()
		return
	}
	r.compileTemplatesFromAsset()
}

func (r *Render) compileTemplatesFromDir() {
	dir := r.opt.Directory
	r.templates = template.New(dir)
	r.templates.Delims(r.opt.Delims.Left, r.opt.Delims.Right)

	// Walk the supplied directory and compile any files that match our extension list.
	filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
		rel, err := filepath.Rel(dir, path)
		if err != nil {
			return err
		}

		ext := ""
		if strings.Index(rel, ".") != -1 {
			ext = filepath.Ext(rel)
		}

		for _, extension := range r.opt.Extensions {
			if ext == extension {

				buf, err := ioutil.ReadFile(path)
				if err != nil {
					panic(err)
				}

				name := (rel[0 : len(rel)-len(ext)])
				tmpl := r.templates.New(filepath.ToSlash(name))

				// Add our funcmaps.
				for _, funcs := range r.opt.Funcs {
					tmpl.Funcs(funcs)
				}

				// Break out if this parsing fails. We don't want any silent server starts.
				template.Must(tmpl.Funcs(helperFuncs).Parse(string(buf)))
				break
			}
		}

		return nil
	})
}

func (r *Render) compileTemplatesFromAsset() {
	dir := r.opt.Directory
	r.templates = template.New(dir)
	r.templates.Delims(r.opt.Delims.Left, r.opt.Delims.Right)

	for _, path := range r.opt.AssetNames() {
		if !strings.HasPrefix(path, dir) {
			continue
		}

		rel, err := filepath.Rel(dir, path)
		if err != nil {
			panic(err)
		}

		ext := ""
		if strings.Index(rel, ".") != -1 {
			ext = "." + strings.Join(strings.Split(rel, ".")[1:], ".")
		}

		for _, extension := range r.opt.Extensions {
			if ext == extension {

				buf, err := r.opt.Asset(path)
				if err != nil {
					panic(err)
				}

				name := (rel[0 : len(rel)-len(ext)])
				tmpl := r.templates.New(filepath.ToSlash(name))

				// Add our funcmaps.
				for _, funcs := range r.opt.Funcs {
					tmpl.Funcs(funcs)
				}

				// Break out if this parsing fails. We don't want any silent server starts.
				template.Must(tmpl.Funcs(helperFuncs).Parse(string(buf)))
				break
			}
		}
	}
}

// Render is the generic function called by XML, JSON, Data, HTML, and can be called by custom implementations.
func (r *Render) Render(w http.ResponseWriter, e Engine, data interface{}) {
	err := e.Render(w, data)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

// XML marshals the given interface object and writes the XML response.
func (r *Render) XML(w http.ResponseWriter, status int, v interface{}) {
	head := Head{
		ContentType: ContentXML + r.compiledCharset,
		Status:      status,
	}

	x := XML{
		Head:   head,
		Indent: r.opt.IndentXML,
		Prefix: r.opt.PrefixXML,
	}

	r.Render(w, x, v)
}

// JSON marshals the given interface object and writes the JSON response.
func (r *Render) JSON(w http.ResponseWriter, status int, v interface{}) {
	head := Head{
		ContentType: ContentJSON + r.compiledCharset,
		Status:      status,
	}

	j := JSON{
		Head:          head,
		Indent:        r.opt.IndentJSON,
		Prefix:        r.opt.PrefixJSON,
		UnEscapeHTML:  r.opt.UnEscapeHTML,
		StreamingJSON: r.opt.StreamingJSON,
	}

	r.Render(w, j, v)
}

// JSONP marshals the given interface object and writes the JSON response.
func (r *Render) JSONP(w http.ResponseWriter, status int, callback string, v interface{}) {
	head := Head{
		ContentType: ContentJSONP + r.compiledCharset,
		Status:      status,
	}

	j := JSONP{
		Head:     head,
		Indent:   r.opt.IndentJSON,
		Callback: callback,
	}

	r.Render(w, j, v)
}

// Data writes out the raw bytes as binary data.
func (r *Render) Data(w http.ResponseWriter, status int, v []byte) {
	head := Head{
		ContentType: ContentBinary,
		Status:      status,
	}

	d := Data{
		Head: head,
	}

	r.Render(w, d, v)
}

// HTML builds up the response from the specified template and bindings.
func (r *Render) HTML(w http.ResponseWriter, status int, name string, binding interface{}, htmlOpt ...HTMLOptions) {
	// If we are in development mode, recompile the templates on every HTML request.
	if r.opt.IsDevelopment {
		r.compileTemplates()
	}

	opt := r.prepareHTMLOptions(htmlOpt)

	// Assign a layout if there is one.
	if len(opt.Layout) > 0 {
		r.addYield(name, binding)
		name = opt.Layout
	}

	head := Head{
		ContentType: r.opt.HTMLContentType + r.compiledCharset,
		Status:      status,
	}

	h := HTML{
		Head:      head,
		Name:      name,
		Templates: r.templates,
	}

	r.Render(w, h, binding)
}

func (r *Render) execute(name string, binding interface{}) (*bytes.Buffer, error) {
	buf := new(bytes.Buffer)
	return buf, r.templates.ExecuteTemplate(buf, name, binding)
}

func (r *Render) addYield(name string, binding interface{}) {
	funcs := template.FuncMap{
		"yield": func() (template.HTML, error) {
			buf, err := r.execute(name, binding)
			// Return safe HTML here since we are rendering our own template.
			return template.HTML(buf.String()), err
		},
		"current": func() (string, error) {
			return name, nil
		},
	}
	r.templates.Funcs(funcs)
}

func (r *Render) prepareHTMLOptions(htmlOpt []HTMLOptions) HTMLOptions {
	if len(htmlOpt) > 0 {
		return htmlOpt[0]
	}

	return HTMLOptions{
		Layout: r.opt.Layout,
	}
}
<|endoftext|>


<commit_before>package editor

import (
	"bytes"
	"context"
	"testing"
)

func TestCommandline(t *testing.T) {
	command := append([]byte("quit"), CharCtrlM)
	ed := commandline{
		streamSet: streamSet{in: NewReaderContext(context.TODO(), bytes.NewReader(command))},
		editor:    newEditor(),
		basic:     &basic{},
	}
	var (
		end continuity
		err error
	)
	for range command {
		end, _, err = ed.Run()
		if err != nil {
			t.Errorf("commandline: %v", err)
		}
	}
	if end != exit {
		t.Errorf("commandline (%q): want %v, but got %v", command, exit, end)
	}
}

func TestSubstitute(t *testing.T) {
	command := append([]byte("substitute a b"), CharCtrlM)
	ed := commandline{
		streamSet: streamSet{in: NewReaderContext(context.TODO(), bytes.NewReader(command))},
		editor:    newEditor(),
		basic:     &basic{},
	}
	ed.buf = []rune("a")
	for range command {
		_, _, err := ed.Run()
		if err != nil {
			t.Errorf("commandline: %v", err)
		}
	}
	got := string(ed.buf)
	want := "b"
	if got != want {
		t.Errorf("commandline (%q): want %v, but got %v", command, got, want)
	}
}
<commit_msg>Add additional test<commit_after>package editor

import (
	"bytes"
	"context"
	"testing"
)

func TestCommandline(t *testing.T) {
	command := append([]byte("quit"), CharCtrlM)
	ed := commandline{
		streamSet: streamSet{in: NewReaderContext(context.TODO(), bytes.NewReader(command))},
		editor:    newEditor(),
		basic:     &basic{},
	}
	var (
		end continuity
		err error
	)
	for range command {
		end, _, err = ed.Run()
		if err != nil {
			t.Errorf("commandline: %v", err)
		}
	}
	if end != exit {
		t.Errorf("commandline (%q): want %v, but got %v", command, exit, end)
	}
}

func TestSubstituteNoArgs(t *testing.T) {
	command := append([]byte("substitute"), CharCtrlM)
	ed := commandline{
		streamSet: streamSet{in: NewReaderContext(context.TODO(), bytes.NewReader(command))},
		editor:    newEditor(),
		basic:     &basic{},
	}
	ed.buf = []rune("a")
	for range command {
		_, _, err := ed.Run()
		if err != nil {
			t.Errorf("commandline: %v", err)
		}
	}
	got := string(ed.buf)
	want := "a"
	if got != want {
		t.Errorf("commandline (%q): want %v, but got %v", command, got, want)
	}
}

func TestSubstitute(t *testing.T) {
	command := append([]byte("substitute a b"), CharCtrlM)
	ed := commandline{
		streamSet: streamSet{in: NewReaderContext(context.TODO(), bytes.NewReader(command))},
		editor:    newEditor(),
		basic:     &basic{},
	}
	ed.buf = []rune("a")
	for range command {
		_, _, err := ed.Run()
		if err != nil {
			t.Errorf("commandline: %v", err)
		}
	}
	got := string(ed.buf)
	want := "b"
	if got != want {
		t.Errorf("commandline (%q): want %v, but got %v", command, got, want)
	}
}
<|endoftext|>