<commit_before>package command

import (
	"fmt"
	"strings"

	"github.com/hashicorp/terraform/backend"
	"github.com/hashicorp/terraform/command/arguments"
	"github.com/hashicorp/terraform/command/views"
	"github.com/hashicorp/terraform/configs"
	"github.com/hashicorp/terraform/plans"
	"github.com/hashicorp/terraform/terraform"
	"github.com/hashicorp/terraform/tfdiags"
)

// PlanCommand is a Command implementation that compares a Terraform
// configuration to an actual infrastructure and shows the differences.
type PlanCommand struct {
	Meta
}

func (c *PlanCommand) Run(args []string) int {
	var destroy, refresh, detailed bool
	var outPath string

	args = c.Meta.process(args)
	cmdFlags := c.Meta.extendedFlagSet("plan")
	cmdFlags.BoolVar(&destroy, "destroy", false, "destroy")
	cmdFlags.BoolVar(&refresh, "refresh", true, "refresh")
	cmdFlags.StringVar(&outPath, "out", "", "path")
	cmdFlags.IntVar(&c.Meta.parallelism, "parallelism", DefaultParallelism, "parallelism")
	cmdFlags.StringVar(&c.Meta.statePath, "state", "", "path")
	cmdFlags.BoolVar(&detailed, "detailed-exitcode", false, "detailed-exitcode")
	cmdFlags.BoolVar(&c.Meta.stateLock, "lock", true, "lock state")
	cmdFlags.DurationVar(&c.Meta.stateLockTimeout, "lock-timeout", 0, "lock timeout")
	cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
	if err := cmdFlags.Parse(args); err != nil {
		c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
		return 1
	}

	diags := c.parseTargetFlags()
	if diags.HasErrors() {
		c.showDiagnostics(diags)
		return 1
	}

	configPath, err := ModulePath(cmdFlags.Args())
	if err != nil {
		c.Ui.Error(err.Error())
		return 1
	}

	// Check for user-supplied plugin path
	if c.pluginPath, err = c.loadPluginPath(); err != nil {
		c.Ui.Error(fmt.Sprintf("Error loading plugin path: %s", err))
		return 1
	}

	var backendConfig *configs.Backend
	var configDiags tfdiags.Diagnostics
	backendConfig, configDiags = c.loadBackendConfig(configPath)
	diags = diags.Append(configDiags)
	if configDiags.HasErrors() {
		c.showDiagnostics(diags)
		return 1
	}

	// Load the backend
	b, backendDiags := c.Backend(&BackendOpts{
		Config: backendConfig,
	})
	diags = diags.Append(backendDiags)
	if backendDiags.HasErrors() {
		c.showDiagnostics(diags)
		return 1
	}

	// Emit any diagnostics we've accumulated before we delegate to the
	// backend, since the backend will handle its own diagnostics internally.
	c.showDiagnostics(diags)
	diags = nil

	// Build the operation
	opReq := c.Operation(b)
	opReq.ConfigDir = configPath
	opReq.Destroy = destroy
	opReq.Hooks = []terraform.Hook{c.uiHook()}
	opReq.PlanOutPath = outPath
	opReq.PlanRefresh = refresh
	opReq.ShowDiagnostics = c.showDiagnostics
	opReq.Type = backend.OperationTypePlan
	opReq.View = views.NewOperation(arguments.ViewHuman, c.RunningInAutomation, c.View)

	opReq.ConfigLoader, err = c.initConfigLoader()
	if err != nil {
		c.showDiagnostics(err)
		return 1
	}

	{
		var moreDiags tfdiags.Diagnostics
		opReq.Variables, moreDiags = c.collectVariableValues()
		diags = diags.Append(moreDiags)
		if moreDiags.HasErrors() {
			c.showDiagnostics(diags)
			return 1
		}
	}

	// c.Backend above has a non-obvious side-effect of also populating
	// c.backendState, which is the state-shaped formulation of the effective
	// backend configuration after evaluation of the backend configuration.
	// We will in turn adapt that to a plans.Backend to include in a plan file
	// if opReq.PlanOutPath was set to a non-empty value above.
	//
	// FIXME: It's ugly to be doing this inline here, but it's also not really
	// clear where would be better to do it. In future we should find a better
	// home for this logic, and ideally also stop depending on the side-effect
	// of c.Backend setting c.backendState.
	{
		// This is not actually a state in the usual sense, but rather a
		// representation of part of the current working directory's
		// "configuration state".
		backendPseudoState := c.backendState
		if backendPseudoState == nil {
			// Should never happen if c.Backend is behaving properly.
			diags = diags.Append(fmt.Errorf("Backend initialization didn't produce resolved configuration (This is a bug in Terraform)"))
			c.showDiagnostics(diags)
			return 1
		}
		var backendForPlan plans.Backend
		backendForPlan.Type = backendPseudoState.Type
		workspace, err := c.Workspace()
		if err != nil {
			c.Ui.Error(fmt.Sprintf("Error selecting workspace: %s", err))
			return 1
		}
		backendForPlan.Workspace = workspace

		// Configuration is a little more awkward to handle here because it's
		// stored in state as raw JSON but we need it as a plans.DynamicValue
		// to save it in the state. To do that conversion we need to know the
		// configuration schema of the backend.
		configSchema := b.ConfigSchema()
		config, err := backendPseudoState.Config(configSchema)
		if err != nil {
			// This means that the stored settings don't conform to the current
			// schema, which could either be because we're reading something
			// created by an older version that is no longer compatible, or
			// because the user manually tampered with the stored config.
			diags = diags.Append(tfdiags.Sourceless(
				tfdiags.Error,
				"Invalid backend initialization",
				fmt.Sprintf("The backend configuration for this working directory is not valid: %s.\n\nIf you have recently upgraded Terraform, you may need to re-run \"terraform init\" to re-initialize this working directory.", err),
			))
			c.showDiagnostics(diags)
			return 1
		}
		configForPlan, err := plans.NewDynamicValue(config, configSchema.ImpliedType())
		if err != nil {
			// This should never happen, since we've just decoded this value
			// using the same schema.
			diags = diags.Append(fmt.Errorf("Failed to encode backend configuration to store in plan: %s", err))
			c.showDiagnostics(diags)
			return 1
		}
		backendForPlan.Config = configForPlan
	}

	// Perform the operation
	op, err := c.RunOperation(b, opReq)
	if err != nil {
		c.showDiagnostics(err)
		return 1
	}

	if op.Result != backend.OperationSuccess {
		return op.Result.ExitStatus()
	}
	if detailed && !op.PlanEmpty {
		return 2
	}

	return op.Result.ExitStatus()
}

func (c *PlanCommand) Help() string {
	helpText := `
Usage: terraform plan [options]

  Generates a speculative execution plan, showing what actions Terraform
  would take to apply the current configuration. This command will not
  actually perform the planned actions.

  You can optionally save the plan to a file, which you can then pass to
  the "apply" command to perform exactly the actions described in the plan.

Options:

  -compact-warnings   If Terraform produces any warnings that are not
                      accompanied by errors, show them in a more compact form
                      that includes only the summary messages.

  -destroy            If set, a plan will be generated to destroy all resources
                      managed by the given configuration and state.

  -detailed-exitcode  Return detailed exit codes when the command exits. This
                      will change the meaning of exit codes to:
                      0 - Succeeded, diff is empty (no changes)
                      1 - Errored
                      2 - Succeeded, there is a diff

  -input=true         Ask for input for variables if not directly set.

  -lock=true          Lock the state file when locking is supported.

  -lock-timeout=0s    Duration to retry a state lock.

  -no-color           If specified, output won't contain any color.

  -out=path           Write a plan file to the given path. This can be used as
                      input to the "apply" command.

  -parallelism=n      Limit the number of concurrent operations. Defaults to 10.

  -refresh=true       Update state prior to checking for differences.

  -state=statefile    Path to a Terraform state file to use to look
                      up Terraform-managed resources. By default it will
                      use the state "terraform.tfstate" if it exists.

  -target=resource    Resource to target. Operation will be limited to this
                      resource and its dependencies. This flag can be used
                      multiple times.

  -var 'foo=bar'      Set a variable in the Terraform configuration. This
                      flag can be set multiple times.

  -var-file=foo       Set variables in the Terraform configuration from
                      a file. If "terraform.tfvars" or any ".auto.tfvars"
                      files are present, they will be automatically loaded.
`
	return strings.TrimSpace(helpText)
}

func (c *PlanCommand) Synopsis() string {
	return "Show changes required by the current configuration"
}
<commit_msg>cli: Remove no-op plan backend setup<commit_after>package command

import (
	"fmt"
	"strings"

	"github.com/hashicorp/terraform/backend"
	"github.com/hashicorp/terraform/command/arguments"
	"github.com/hashicorp/terraform/command/views"
	"github.com/hashicorp/terraform/configs"
	"github.com/hashicorp/terraform/terraform"
	"github.com/hashicorp/terraform/tfdiags"
)

// PlanCommand is a Command implementation that compares a Terraform
// configuration to an actual infrastructure and shows the differences.
type PlanCommand struct {
	Meta
}

func (c *PlanCommand) Run(args []string) int {
	var destroy, refresh, detailed bool
	var outPath string

	args = c.Meta.process(args)
	cmdFlags := c.Meta.extendedFlagSet("plan")
	cmdFlags.BoolVar(&destroy, "destroy", false, "destroy")
	cmdFlags.BoolVar(&refresh, "refresh", true, "refresh")
	cmdFlags.StringVar(&outPath, "out", "", "path")
	cmdFlags.IntVar(&c.Meta.parallelism, "parallelism", DefaultParallelism, "parallelism")
	cmdFlags.StringVar(&c.Meta.statePath, "state", "", "path")
	cmdFlags.BoolVar(&detailed, "detailed-exitcode", false, "detailed-exitcode")
	cmdFlags.BoolVar(&c.Meta.stateLock, "lock", true, "lock state")
	cmdFlags.DurationVar(&c.Meta.stateLockTimeout, "lock-timeout", 0, "lock timeout")
	cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
	if err := cmdFlags.Parse(args); err != nil {
		c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
		return 1
	}

	diags := c.parseTargetFlags()
	if diags.HasErrors() {
		c.showDiagnostics(diags)
		return 1
	}

	configPath, err := ModulePath(cmdFlags.Args())
	if err != nil {
		c.Ui.Error(err.Error())
		return 1
	}

	// Check for user-supplied plugin path
	if c.pluginPath, err = c.loadPluginPath(); err != nil {
		c.Ui.Error(fmt.Sprintf("Error loading plugin path: %s", err))
		return 1
	}

	var backendConfig *configs.Backend
	var configDiags tfdiags.Diagnostics
	backendConfig, configDiags = c.loadBackendConfig(configPath)
	diags = diags.Append(configDiags)
	if configDiags.HasErrors() {
		c.showDiagnostics(diags)
		return 1
	}

	// Load the backend
	b, backendDiags := c.Backend(&BackendOpts{
		Config: backendConfig,
	})
	diags = diags.Append(backendDiags)
	if backendDiags.HasErrors() {
		c.showDiagnostics(diags)
		return 1
	}

	// Emit any diagnostics we've accumulated before we delegate to the
	// backend, since the backend will handle its own diagnostics internally.
	c.showDiagnostics(diags)
	diags = nil

	// Build the operation
	opReq := c.Operation(b)
	opReq.ConfigDir = configPath
	opReq.Destroy = destroy
	opReq.Hooks = []terraform.Hook{c.uiHook()}
	opReq.PlanOutPath = outPath
	opReq.PlanRefresh = refresh
	opReq.ShowDiagnostics = c.showDiagnostics
	opReq.Type = backend.OperationTypePlan
	opReq.View = views.NewOperation(arguments.ViewHuman, c.RunningInAutomation, c.View)

	opReq.ConfigLoader, err = c.initConfigLoader()
	if err != nil {
		c.showDiagnostics(err)
		return 1
	}

	{
		var moreDiags tfdiags.Diagnostics
		opReq.Variables, moreDiags = c.collectVariableValues()
		diags = diags.Append(moreDiags)
		if moreDiags.HasErrors() {
			c.showDiagnostics(diags)
			return 1
		}
	}

	// Perform the operation
	op, err := c.RunOperation(b, opReq)
	if err != nil {
		c.showDiagnostics(err)
		return 1
	}

	if op.Result != backend.OperationSuccess {
		return op.Result.ExitStatus()
	}
	if detailed && !op.PlanEmpty {
		return 2
	}

	return op.Result.ExitStatus()
}

func (c *PlanCommand) Help() string {
	helpText := `
Usage: terraform plan [options]

  Generates a speculative execution plan, showing what actions Terraform
  would take to apply the current configuration. This command will not
  actually perform the planned actions.

  You can optionally save the plan to a file, which you can then pass to
  the "apply" command to perform exactly the actions described in the plan.

Options:

  -compact-warnings   If Terraform produces any warnings that are not
                      accompanied by errors, show them in a more compact form
                      that includes only the summary messages.

  -destroy            If set, a plan will be generated to destroy all resources
                      managed by the given configuration and state.

  -detailed-exitcode  Return detailed exit codes when the command exits. This
                      will change the meaning of exit codes to:
                      0 - Succeeded, diff is empty (no changes)
                      1 - Errored
                      2 - Succeeded, there is a diff

  -input=true         Ask for input for variables if not directly set.

  -lock=true          Lock the state file when locking is supported.

  -lock-timeout=0s    Duration to retry a state lock.

  -no-color           If specified, output won't contain any color.

  -out=path           Write a plan file to the given path. This can be used as
                      input to the "apply" command.

  -parallelism=n      Limit the number of concurrent operations. Defaults to 10.

  -refresh=true       Update state prior to checking for differences.

  -state=statefile    Path to a Terraform state file to use to look
                      up Terraform-managed resources. By default it will
                      use the state "terraform.tfstate" if it exists.

  -target=resource    Resource to target. Operation will be limited to this
                      resource and its dependencies. This flag can be used
                      multiple times.

  -var 'foo=bar'      Set a variable in the Terraform configuration. This
                      flag can be set multiple times.

  -var-file=foo       Set variables in the Terraform configuration from
                      a file. If "terraform.tfvars" or any ".auto.tfvars"
                      files are present, they will be automatically loaded.
`
	return strings.TrimSpace(helpText)
}

func (c *PlanCommand) Synopsis() string {
	return "Show changes required by the current configuration"
}
<|endoftext|>


<commit_before>package model

import (
	"errors"
	"fmt"
	"time"

	"appengine"
	"appengine/datastore"
)

var (
	ErrClassFull         = errors.New("Class is full")
	ErrClassExists       = errors.New("Class already exists")
	ErrClassNotEmpty     = errors.New("Class is not empty")
	ErrAlreadyRegistered = errors.New("Student is already registered for class")
)

type Class struct {
	ID          int64  `datastore: "-"`
	Title       string `datastore: ",noindex"`
	Description string `datastore: ",noindex"`
	Teacher     *datastore.Key

	DayOfWeek     string
	StartTime     time.Time `datastore: ",noindex"`
	LengthMinutes int32     `datastore: ",noindex"`

	BeginDate time.Time
	EndDate   time.Time
	Active    bool

	DropInOnly bool

	Capacity   int32 `datastore: ",noindex"`
	SpacesLeft int32
}

// NextClassTime returns the earliest start time of the class which starts strictly later than the
// given time.
func (c *Class) NextClassTime(after time.Time) time.Time {
	return time.Time{}
}

func (c *Class) key(ctx appengine.Context) *datastore.Key {
	return datastore.NewKey(ctx, "Class", "", c.ID, nil)
}

func (c *Class) Registrations() int32 {
	return c.Capacity - c.SpacesLeft
}

// A Scheduler is responsible for manipulating classes.
type Scheduler interface {
	AddNew(c *Class) error
	GetClass(id int64) *Class
	ListClasses(activeOnly bool) []*Class
	DeleteClass(c *Class) error
	ListOpenClasses(activeOnly bool) []*Class
	GetTeacherNames(classes []*Class) map[int64]string
	GetTeacher(class *Class) *UserAccount
	GetClassesForTeacher(teacher *UserAccount) []*Class
	WriteClass(class *Class) error
}

type scheduler struct {
	appengine.Context
}

func (s *scheduler) GetClass(id int64) *Class {
	key := datastore.NewKey(s, "Class", "", id, nil)
	class := &Class{}
	if err := datastore.Get(s, key, class); err != nil {
		s.Errorf("Error getting class %d: %s", id, err)
		return nil
	}
	class.ID = id
	return class
}

func (s *scheduler) AddNew(c *Class) error {
	key := datastore.NewIncompleteKey(s, "Class", nil)
	if _, err := datastore.Put(s, key, c); err != nil {
		return fmt.Errorf("Error writing class %s: %s", c.Title, err)
	}
	return nil
}

func (s *scheduler) ListClasses(activeOnly bool) []*Class {
	classes := []*Class{}
	q := datastore.NewQuery("Class")
	if activeOnly {
		q = q.Filter("Active =", true)
	}
	keys, err := q.GetAll(s, &classes)
	if err != nil {
		s.Errorf("Error listing classes: %s", err)
		return nil
	}
	for idx, key := range keys {
		classes[idx].ID = key.IntID()
	}
	return classes
}

func (s *scheduler) ListOpenClasses(activeOnly bool) []*Class {
	classes := []*Class{}
	q := datastore.NewQuery("Class").
		Filter("SpacesLeft >", 0)
	if activeOnly {
		q = q.Filter("Active =", true)
	}
	keys, err := q.GetAll(s, &classes)
	if err != nil {
		s.Errorf("Error listing classes: %s", err)
		return nil
	}
	for idx, key := range keys {
		classes[idx].ID = key.IntID()
	}
	return classes
}

func (s *scheduler) GetClassesForTeacher(t *UserAccount) []*Class {
	q := datastore.NewQuery("Class").
		Filter("Teacher =", t.key(s))
	classes := []*Class{}
	keys, err := q.GetAll(s, &classes)
	if err != nil {
		s.Errorf("Error listing classes for teacher %s: %s", t.AccountID, err)
		return nil
	}
	for idx, key := range keys {
		classes[idx].ID = key.IntID()
	}
	return classes
}

func (s *scheduler) GetTeacherNames(classes []*Class) map[int64]string {
	keys := make([]*datastore.Key, len(classes))
	teachers := make([]*UserAccount, len(classes))
	for idx, class := range classes {
		keys[idx] = class.Teacher
		teachers[idx] = &UserAccount{}
	}
	if err := datastore.GetMulti(s, keys, teachers); err != nil {
		s.Errorf("Error looking up teacher names: %s", err)
		return nil
	}
	names := map[int64]string{}
	for idx, class := range classes {
		names[class.ID] = teachers[idx].FirstName
	}
	return names
}

func (s *scheduler) GetTeacher(class *Class) *UserAccount {
	t := &UserAccount{}
	if err := datastore.Get(s, class.Teacher, t); err != nil {
		s.Criticalf("Couldn't get teacher for class %d: %s", class.ID, err)
		return nil
	}
	return t
}

func (s *scheduler) DeleteClass(c *Class) error {
	key := c.key(s)
	err := datastore.RunInTransaction(s, func(context appengine.Context) error {
		q := datastore.NewQuery("Registration").
			Ancestor(key).
			KeysOnly().
			Limit(1)
		keys, err := q.GetAll(context, nil)
		if err != nil {
			return err
		}
		if len(keys) > 0 {
			return ErrClassNotEmpty
		}
		if err := datastore.Delete(context, key); err != nil {
			return err
		}
		return nil
	}, nil)
	if err != nil && err != ErrClassNotEmpty {
		return fmt.Errorf("Error deleting class %d: %s", c.ID, err)
	}
	return err
}

func (s *scheduler) WriteClass(c *Class) error {
	key := c.key(s)
	if _, err := datastore.Put(s, key, c); err != nil {
		return fmt.Errorf("Error writing class %d: %s", c.ID, err)
	}
	return nil
}

func NewScheduler(c appengine.Context) Scheduler {
	return &scheduler{c}
}

// A Registration represents a reserved space in a class, either for the entire session or as a drop
// in.
type Registration struct {
	StudentID string
	ClassID   int64

	// If this registration is a drop in, Date is the start time of the class to which it applies.
	Date time.Time
}

func (r *Registration) key(c appengine.Context) *datastore.Key {
	classKey := datastore.NewKey(c, "Class", "", r.ClassID, nil)
	return datastore.NewKey(c, "Registration", r.StudentID, 0, classKey)
}

type Roster interface {
	LookupRegistration(studentID string) *Registration
	ListRegistrations() []*Registration
	GetStudents(registrations []*Registration) []*UserAccount
	AddStudent(studentID string) (*Registration, error)
	AddDropIn(studentID string, date time.Time) (*Registration, error)
}

type roster struct {
	appengine.Context
	class *Class
}

func NewRoster(c appengine.Context, class *Class) Roster {
	return &roster{c, class}
}

func (r *roster) ListRegistrations() []*Registration {
	q := datastore.NewQuery("Registration").
		Ancestor(r.class.key(r))
	rs := []*Registration{}
	if _, err := q.GetAll(r, &rs); err != nil {
		r.Errorf("Error looking up registrations for class %d: %s", r.class.ID, err)
		return nil
	}
	return rs
}

func (r *roster) GetStudents(rs []*Registration) []*UserAccount {
	keys := make([]*datastore.Key, len(rs))
	students := make([]*UserAccount, len(rs))
	for idx, reg := range rs {
		keys[idx] = datastore.NewKey(r, "UserAccount", reg.StudentID, 0, nil)
		students[idx] = &UserAccount{}
	}
	if err := datastore.GetMulti(r, keys, students); err != nil {
		r.Errorf("Error looking up students from registrations: %s", err)
		return nil
	}
	return students
}

func (r *roster) LookupRegistration(studentID string) *Registration {
	key := datastore.NewKey(r, "Registration", studentID, 0, r.class.key(r))
	reg := &Registration{}
	if err := datastore.Get(r, key, reg); err != nil {
		r.Errorf("Error looking up registration for student %s in class %d: %s", studentID, r.class.ID, err)
		return nil
	}
	return reg
}

func (r *roster) AddStudent(studentID string) (*Registration, error) {
	reg := &Registration{
		ClassID:   r.class.ID,
		StudentID: studentID,
	}
	err := datastore.RunInTransaction(r, func(ctx appengine.Context) error {
		key := reg.key(ctx)
		old := &Registration{}
		if err := datastore.Get(ctx, key, old); err != datastore.ErrNoSuchEntity {
			if err != nil {
				return fmt.Errorf("Error looking up registration %+v: %s", reg, err)
			}
			return ErrAlreadyRegistered
		}

		classKey := datastore.NewKey(ctx, "Class", "", reg.ClassID, nil)
		class := &Class{}
		if err := datastore.Get(ctx, classKey, class); err != nil {
			return fmt.Errorf("Error looking up class %d for registration %+v: %s",
				reg.ClassID, reg, err)
		}
		class.ID = classKey.IntID()
		if class.SpacesLeft == 0 {
			return ErrClassFull
		}
		class.SpacesLeft--
		if _, err := datastore.Put(ctx, classKey, class); err != nil {
			return fmt.Errorf("Error updating class %d: %s", class.ID, err)
		}

		if _, err := datastore.Put(ctx, key, reg); err != nil {
			return fmt.Errorf("Error writing registration %+v: %s", reg, err)
		}
		return nil
	}, nil)
	if err != nil {
		return nil, err
	}
	return reg, nil
}

func (r *roster) getClass(ctx appengine.Context) *Class {
	class := &Class{}
	if err := datastore.Get(ctx, r.class.key(ctx), class); err != nil {
		ctx.Errorf("Couldnt' find class %d: %s", r.class.ID, err)
		return nil
	}
	class.ID = r.class.ID
	return class
}

func (r *roster) DropStudent(studentID string) error {
	err := datastore.RunInTransaction(r, func(ctx appengine.Context) error {
		reg := r.LookupRegistration(studentID)
		if reg == nil {
			return fmt.Errorf("Student %s not registered for class %d", studentID, r.class.ID)
		}
		class := r.getClass(ctx)
		if class == nil {
			return fmt.Errorf("No such class class %d", r.class.ID)
		}
		class.SpacesLeft++
		if class.SpacesLeft > class.Capacity {
			r.Warningf("Tried to increase space for class %d beyond capacity", class.ID)
			class.SpacesLeft = class.Capacity
		}
		if _, err := datastore.Put(ctx, class.key(ctx), class); err != nil {
			return fmt.Errorf("Error updating class %d: %s", class.ID, err)
		}
		if err := datastore.Delete(ctx, reg.key(ctx)); err != nil {
			return fmt.Errorf("Error deleting registration %+v: %s", reg, err)
		}
		return nil
	}, nil)
	return err
}

func (r *roster) AddDropIn(studentID string, date time.Time) (*Registration, error) {
	return nil, fmt.Errorf("Not yet implemented")
}

type Registrar interface {
	ListRegistrations() []*Registration
	ListRegisteredClasses() []*Class
}

type registrar struct {
	appengine.Context
	studentID string
}

func NewRegistrar(c appengine.Context, studentID string) Registrar {
	return &registrar{c, studentID}
}

func (r *registrar) ListRegistrations() []*Registration {
	rs := []*Registration{}
	q := datastore.NewQuery("Registration").
		Filter("StudentID =", r.studentID)
	if _, err := q.GetAll(r, &rs); err != nil {
		return nil
	}
	return rs
}

func (r *registrar) listPaperRegistrations() []*Class {
	account, err := GetAccountByID(r, r.studentID)
	if err != nil {
		r.Errorf("Error looking up paper registrations for %s: %s", r.studentID, err)
		return nil
	}
	r.Infof("Looking up paper registrations for %s", "PAPERREGISTRATION|"+account.Email)
	q := datastore.NewQuery("Registration").
		Filter("StudentID =", "PAPERREGISTRATION|"+account.Email).
		KeysOnly()
	regKeys, err := q.GetAll(r, nil)
	if err != nil {
		r.Errorf("Error getting paper reg keys for student %s: %s", r.studentID, err)
		return nil
	}
	if len(regKeys) == 0 {
		return nil
	}
	classKeys := make([]*datastore.Key, len(regKeys))
	for i, k := range regKeys {
		classKeys[i] = k.Parent()
	}
	tmp := make([]Class, len(classKeys))
	if err := datastore.GetMulti(r, classKeys, tmp); err != nil {
		r.Errorf("Error getting registered classes for %s: %s", r.studentID, err)
		return nil
	}
	classes := make([]*Class, len(classKeys))
	for i, c := range tmp {
		c.ID = classKeys[i].IntID()
		classes[i] = &tmp[i]
	}
	return classes
}

func (r *registrar) ListRegisteredClasses() []*Class {
	r.Infof("Listing registered classes for %s", r.studentID)
	q := datastore.NewQuery("Registration").
		Filter("StudentID =", r.studentID).
		KeysOnly()
	regKeys, err := q.GetAll(r, nil)
	if err != nil {
		r.Errorf("Error getting reg keys for student %s: %s", r.studentID, err)
		return nil
	}
	classKeys := make([]*datastore.Key, len(regKeys))
	classes := make([]*Class, len(classKeys))
	for i, k := range regKeys {
		classKeys[i] = k.Parent()
		classes[i] = &Class{}
	}
	if err := datastore.GetMulti(r, classKeys, classes); err != nil {
		r.Errorf("Error getting registered classes for %s: %s", r.studentID, err)
		return nil
	}
	classesByID := map[int64]*Class{}
	for _, class := range classes {
		classesByID[class.ID] = class
	}
	paperClasses := r.listPaperRegistrations()
	if paperClasses == nil {
		return classes
	}
	r.Infof("Found %d registrations for %s", len(paperClasses), r.studentID)
	for _, class := range paperClasses {
		classesByID[class.ID] = class
	}
	classes = []*Class{}
	for _, class := range classesByID {
		classes = append(classes, class)
	}
	return classes
}
<commit_msg>Removed unneccessary logging messages.<commit_after>package model

import (
	"errors"
	"fmt"
	"time"

	"appengine"
	"appengine/datastore"
)

var (
	ErrClassFull         = errors.New("Class is full")
	ErrClassExists       = errors.New("Class already exists")
	ErrClassNotEmpty     = errors.New("Class is not empty")
	ErrAlreadyRegistered = errors.New("Student is already registered for class")
)

type Class struct {
	ID          int64  `datastore: "-"`
	Title       string `datastore: ",noindex"`
	Description string `datastore: ",noindex"`
	Teacher     *datastore.Key

	DayOfWeek     string
	StartTime     time.Time `datastore: ",noindex"`
	LengthMinutes int32     `datastore: ",noindex"`

	BeginDate time.Time
	EndDate   time.Time
	Active    bool

	DropInOnly bool

	Capacity   int32 `datastore: ",noindex"`
	SpacesLeft int32
}

// NextClassTime returns the earliest start time of the class which starts strictly later than the
// given time.
func (c *Class) NextClassTime(after time.Time) time.Time {
	return time.Time{}
}

func (c *Class) key(ctx appengine.Context) *datastore.Key {
	return datastore.NewKey(ctx, "Class", "", c.ID, nil)
}

func (c *Class) Registrations() int32 {
	return c.Capacity - c.SpacesLeft
}

// A Scheduler is responsible for manipulating classes.
type Scheduler interface {
	AddNew(c *Class) error
	GetClass(id int64) *Class
	ListClasses(activeOnly bool) []*Class
	DeleteClass(c *Class) error
	ListOpenClasses(activeOnly bool) []*Class
	GetTeacherNames(classes []*Class) map[int64]string
	GetTeacher(class *Class) *UserAccount
	GetClassesForTeacher(teacher *UserAccount) []*Class
	WriteClass(class *Class) error
}

type scheduler struct {
	appengine.Context
}

func (s *scheduler) GetClass(id int64) *Class {
	key := datastore.NewKey(s, "Class", "", id, nil)
	class := &Class{}
	if err := datastore.Get(s, key, class); err != nil {
		s.Errorf("Error getting class %d: %s", id, err)
		return nil
	}
	class.ID = id
	return class
}

func (s *scheduler) AddNew(c *Class) error {
	key := datastore.NewIncompleteKey(s, "Class", nil)
	if _, err := datastore.Put(s, key, c); err != nil {
		return fmt.Errorf("Error writing class %s: %s", c.Title, err)
	}
	return nil
}

func (s *scheduler) ListClasses(activeOnly bool) []*Class {
	classes := []*Class{}
	q := datastore.NewQuery("Class")
	if activeOnly {
		q = q.Filter("Active =", true)
	}
	keys, err := q.GetAll(s, &classes)
	if err != nil {
		s.Errorf("Error listing classes: %s", err)
		return nil
	}
	for idx, key := range keys {
		classes[idx].ID = key.IntID()
	}
	return classes
}

func (s *scheduler) ListOpenClasses(activeOnly bool) []*Class {
	classes := []*Class{}
	q := datastore.NewQuery("Class").
		Filter("SpacesLeft >", 0)
	if activeOnly {
		q = q.Filter("Active =", true)
	}
	keys, err := q.GetAll(s, &classes)
	if err != nil {
		s.Errorf("Error listing classes: %s", err)
		return nil
	}
	for idx, key := range keys {
		classes[idx].ID = key.IntID()
	}
	return classes
}

func (s *scheduler) GetClassesForTeacher(t *UserAccount) []*Class {
	q := datastore.NewQuery("Class").
		Filter("Teacher =", t.key(s))
	classes := []*Class{}
	keys, err := q.GetAll(s, &classes)
	if err != nil {
		s.Errorf("Error listing classes for teacher %s: %s", t.AccountID, err)
		return nil
	}
	for idx, key := range keys {
		classes[idx].ID = key.IntID()
	}
	return classes
}

func (s *scheduler) GetTeacherNames(classes []*Class) map[int64]string {
	keys := make([]*datastore.Key, len(classes))
	teachers := make([]*UserAccount, len(classes))
	for idx, class := range classes {
		keys[idx] = class.Teacher
		teachers[idx] = &UserAccount{}
	}
	if err := datastore.GetMulti(s, keys, teachers); err != nil {
		s.Errorf("Error looking up teacher names: %s", err)
		return nil
	}
	names := map[int64]string{}
	for idx, class := range classes {
		names[class.ID] = teachers[idx].FirstName
	}
	return names
}

func (s *scheduler) GetTeacher(class *Class) *UserAccount {
	t := &UserAccount{}
	if err := datastore.Get(s, class.Teacher, t); err != nil {
		s.Criticalf("Couldn't get teacher for class %d: %s", class.ID, err)
		return nil
	}
	return t
}

func (s *scheduler) DeleteClass(c *Class) error {
	key := c.key(s)
	err := datastore.RunInTransaction(s, func(context appengine.Context) error {
		q := datastore.NewQuery("Registration").
			Ancestor(key).
			KeysOnly().
			Limit(1)
		keys, err := q.GetAll(context, nil)
		if err != nil {
			return err
		}
		if len(keys) > 0 {
			return ErrClassNotEmpty
		}
		if err := datastore.Delete(context, key); err != nil {
			return err
		}
		return nil
	}, nil)
	if err != nil && err != ErrClassNotEmpty {
		return fmt.Errorf("Error deleting class %d: %s", c.ID, err)
	}
	return err
}

func (s *scheduler) WriteClass(c *Class) error {
	key := c.key(s)
	if _, err := datastore.Put(s, key, c); err != nil {
		return fmt.Errorf("Error writing class %d: %s", c.ID, err)
	}
	return nil
}

func NewScheduler(c appengine.Context) Scheduler {
	return &scheduler{c}
}

// A Registration represents a reserved space in a class, either for the entire session or as a drop
// in.
type Registration struct {
	StudentID string
	ClassID   int64

	// If this registration is a drop in, Date is the start time of the class to which it applies.
	Date time.Time
}

func (r *Registration) key(c appengine.Context) *datastore.Key {
	classKey := datastore.NewKey(c, "Class", "", r.ClassID, nil)
	return datastore.NewKey(c, "Registration", r.StudentID, 0, classKey)
}

type Roster interface {
	LookupRegistration(studentID string) *Registration
	ListRegistrations() []*Registration
	GetStudents(registrations []*Registration) []*UserAccount
	AddStudent(studentID string) (*Registration, error)
	AddDropIn(studentID string, date time.Time) (*Registration, error)
}

type roster struct {
	appengine.Context
	class *Class
}

func NewRoster(c appengine.Context, class *Class) Roster {
	return &roster{c, class}
}

func (r *roster) ListRegistrations() []*Registration {
	q := datastore.NewQuery("Registration").
		Ancestor(r.class.key(r))
	rs := []*Registration{}
	if _, err := q.GetAll(r, &rs); err != nil {
		r.Errorf("Error looking up registrations for class %d: %s", r.class.ID, err)
		return nil
	}
	return rs
}

func (r *roster) GetStudents(rs []*Registration) []*UserAccount {
	keys := make([]*datastore.Key, len(rs))
	students := make([]*UserAccount, len(rs))
	for idx, reg := range rs {
		keys[idx] = datastore.NewKey(r, "UserAccount", reg.StudentID, 0, nil)
		students[idx] = &UserAccount{}
	}
	if err := datastore.GetMulti(r, keys, students); err != nil {
		r.Errorf("Error looking up students from registrations: %s", err)
		return nil
	}
	return students
}

func (r *roster) LookupRegistration(studentID string) *Registration {
	key := datastore.NewKey(r, "Registration", studentID, 0, r.class.key(r))
	reg := &Registration{}
	if err := datastore.Get(r, key, reg); err != nil {
		r.Errorf("Error looking up registration for student %s in class %d: %s", studentID, r.class.ID, err)
		return nil
	}
	return reg
}

func (r *roster) AddStudent(studentID string) (*Registration, error) {
	reg := &Registration{
		ClassID:   r.class.ID,
		StudentID: studentID,
	}
	err := datastore.RunInTransaction(r, func(ctx appengine.Context) error {
		key := reg.key(ctx)
		old := &Registration{}
		if err := datastore.Get(ctx, key, old); err != datastore.ErrNoSuchEntity {
			if err != nil {
				return fmt.Errorf("Error looking up registration %+v: %s", reg, err)
			}
			return ErrAlreadyRegistered
		}

		classKey := datastore.NewKey(ctx, "Class", "", reg.ClassID, nil)
		class := &Class{}
		if err := datastore.Get(ctx, classKey, class); err != nil {
			return fmt.Errorf("Error looking up class %d for registration %+v: %s",
				reg.ClassID, reg, err)
		}
		class.ID = classKey.IntID()
		if class.SpacesLeft == 0 {
			return ErrClassFull
		}
		class.SpacesLeft--
		if _, err := datastore.Put(ctx, classKey, class); err != nil {
			return fmt.Errorf("Error updating class %d: %s", class.ID, err)
		}

		if _, err := datastore.Put(ctx, key, reg); err != nil {
			return fmt.Errorf("Error writing registration %+v: %s", reg, err)
		}
		return nil
	}, nil)
	if err != nil {
		return nil, err
	}
	return reg, nil
}

func (r *roster) getClass(ctx appengine.Context) *Class {
	class := &Class{}
	if err := datastore.Get(ctx, r.class.key(ctx), class); err != nil {
		ctx.Errorf("Couldnt' find class %d: %s", r.class.ID, err)
		return nil
	}
	class.ID = r.class.ID
	return class
}

func (r *roster) DropStudent(studentID string) error {
	err := datastore.RunInTransaction(r, func(ctx appengine.Context) error {
		reg := r.LookupRegistration(studentID)
		if reg == nil {
			return fmt.Errorf("Student %s not registered for class %d", studentID, r.class.ID)
		}
		class := r.getClass(ctx)
		if class == nil {
			return fmt.Errorf("No such class class %d", r.class.ID)
		}
		class.SpacesLeft++
		if class.SpacesLeft > class.Capacity {
			r.Warningf("Tried to increase space for class %d beyond capacity", class.ID)
			class.SpacesLeft = class.Capacity
		}
		if _, err := datastore.Put(ctx, class.key(ctx), class); err != nil {
			return fmt.Errorf("Error updating class %d: %s", class.ID, err)
		}
		if err := datastore.Delete(ctx, reg.key(ctx)); err != nil {
			return fmt.Errorf("Error deleting registration %+v: %s", reg, err)
		}
		return nil
	}, nil)
	return err
}

func (r *roster) AddDropIn(studentID string, date time.Time) (*Registration, error) {
	return nil, fmt.Errorf("Not yet implemented")
}

type Registrar interface {
	ListRegistrations() []*Registration
	ListRegisteredClasses() []*Class
}

type registrar struct {
	appengine.Context
	studentID string
}

func NewRegistrar(c appengine.Context, studentID string) Registrar {
	return &registrar{c, studentID}
}

func (r *registrar) ListRegistrations() []*Registration {
	rs := []*Registration{}
	q := datastore.NewQuery("Registration").
		Filter("StudentID =", r.studentID)
	if _, err := q.GetAll(r, &rs); err != nil {
		return nil
	}
	return rs
}

func (r *registrar) listPaperRegistrations() []*Class {
	account, err := GetAccountByID(r, r.studentID)
	if err != nil {
		r.Errorf("Error looking up paper registrations for %s: %s", r.studentID, err)
		return nil
	}
	r.Infof("Looking up paper registrations for %s", "PAPERREGISTRATION|"+account.Email)
	q := datastore.NewQuery("Registration").
		Filter("StudentID =", "PAPERREGISTRATION|"+account.Email).
		KeysOnly()
	regKeys, err := q.GetAll(r, nil)
	if err != nil {
		r.Errorf("Error getting paper reg keys for student %s: %s", r.studentID, err)
		return nil
	}
	if len(regKeys) == 0 {
		return nil
	}
	classKeys := make([]*datastore.Key, len(regKeys))
	for i, k := range regKeys {
		classKeys[i] = k.Parent()
	}
	tmp := make([]Class, len(classKeys))
	if err := datastore.GetMulti(r, classKeys, tmp); err != nil {
		r.Errorf("Error getting registered classes for %s: %s", r.studentID, err)
		return nil
	}
	classes := make([]*Class, len(classKeys))
	for i, c := range tmp {
		c.ID = classKeys[i].IntID()
		classes[i] = &tmp[i]
	}
	return classes
}

func (r *registrar) ListRegisteredClasses() []*Class {
	q := datastore.NewQuery("Registration").
		Filter("StudentID =", r.studentID).
		KeysOnly()
	regKeys, err := q.GetAll(r, nil)
	if err != nil {
		r.Errorf("Error getting reg keys for student %s: %s", r.studentID, err)
		return nil
	}
	classKeys := make([]*datastore.Key, len(regKeys))
	classes := make([]*Class, len(classKeys))
	for i, k := range regKeys {
		classKeys[i] = k.Parent()
		classes[i] = &Class{}
	}
	if err := datastore.GetMulti(r, classKeys, classes); err != nil {
		r.Errorf("Error getting registered classes for %s: %s", r.studentID, err)
		return nil
	}
	classesByID := map[int64]*Class{}
	for _, class := range classes {
		classesByID[class.ID] = class
	}
	paperClasses := r.listPaperRegistrations()
	if paperClasses == nil {
		return classes
	}
	for _, class := range paperClasses {
		classesByID[class.ID] = class
	}
	classes = []*Class{}
	for _, class := range classesByID {
		classes = append(classes, class)
	}
	return classes
}
<|endoftext|>


<commit_before>package wspacego

import (
	. "github.com/r7kamura/gospel"
	"testing"
)

func TestCommnad(t *testing.T) {
	Describe(t, "Command Tests", func() {
		Context("Create Instance", func() {
			It("Initialize Instance", func() {
				cmd := "cmd"
				sut := NewCommand(cmd)
				Expect(sut).To(Exist)
			})
		})
		Context("Create Instance", func() {
			It("is exists", func() {
				cmd, subcmd := "cmd", "subcmd"
				Expect(NewSubCommand(cmd, subcmd)).To(Exist)
			})
		})
		Context("Create Instance", func() {
			It("Initialize Instance", func() {
				cmd, subcmd := "cmd", "subcmd"
				sut := NewSubCommand(cmd, subcmd)
				Expect(sut.cmd).To(Equal, cmd)
				Expect(sut.subcmd).To(Equal, subcmd)
				Expect(sut.param).To(Equal, 0)
			})
		})
	})
}
<commit_msg>指定したパラメータでインスタンスが作成できることをかくにんした<commit_after>package wspacego

import (
	. "github.com/r7kamura/gospel"
	"testing"
)

func TestCommnad(t *testing.T) {
	Describe(t, "Command Tests", func() {
		Context("Create Instance", func() {
			It("Initialize Instance", func() {
				cmd := "cmd"
				sut := NewCommand(cmd)
				Expect(sut).To(Exist)
			})
		})
		Context("Initial Instance", func() {
			cmd := "cmd"
			sut := NewCommand(cmd)
			Expect(sut.cmd).To(Equal, cmd)
		})
		Context("Create Instance", func() {
			It("is exists", func() {
				cmd, subcmd := "cmd", "subcmd"
				Expect(NewSubCommand(cmd, subcmd)).To(Exist)
			})
		})
		Context("Create Instance", func() {
			It("Initialize Instance", func() {
				cmd, subcmd := "cmd", "subcmd"
				sut := NewSubCommand(cmd, subcmd)
				Expect(sut.cmd).To(Equal, cmd)
				Expect(sut.subcmd).To(Equal, subcmd)
				Expect(sut.param).To(Equal, 0)
			})
		})
	})
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"errors"
	"fmt"
	exif "github.com/garyhouston/exif44"
	jseg "github.com/garyhouston/jpegsegs"
	tiff "github.com/garyhouston/tiff66"
	"io"
	"io/ioutil"
	"log"
	"os"
)

func processTIFF(file io.Reader) ([]byte, error) {
	buf, err := ioutil.ReadAll(file)
	if err != nil {
		return nil, err
	}
	validTIFF, order, ifdPos := tiff.GetHeader(buf)
	if !validTIFF {
		return nil, errors.New("processTIFF: invalid TIFF header")
	}
	root, err := tiff.GetIFDTree(buf, order, ifdPos, tiff.TIFFSpace)
	if err != nil {
		return nil, err
	}
	root.Fix(order)
	fileSize := tiff.HeaderSize + root.TreeSize()
	out := make([]byte, fileSize)
	tiff.PutHeader(out, order, tiff.HeaderSize)
	next, err := root.PutIFDTree(out, tiff.HeaderSize, order)
	if err != nil {
		return nil, err
	}
	out = out[:next]
	return out, nil
}

func processJPEG(file io.Reader) ([]byte, error) {
	scanner, err := jseg.NewScanner(file)
	if err != nil {
		return nil, err
	}
	out := new(bytes.Buffer)
	dumper, err := jseg.NewDumper(out)
	if err != nil {
		return out.Bytes(), err
	}
	for {
		marker, buf, err := scanner.Scan()
		if err != nil {
			return out.Bytes(), err
		}
		if marker == jseg.SOS {
			// Start of scan data, no more metadata expected.
			if err := dumper.Dump(marker, nil); err != nil {
				return out.Bytes(), err
			}
			err := dumper.Copy(scanner)
			return out.Bytes(), err
		}
		if marker == jseg.APP0+1 {
			isExif, next := exif.GetHeader(buf)
			if isExif {
				tree, err := exif.GetExifTree(buf[next:])
				if err != nil {
					return out.Bytes(), err
				}
				tree.Tree.Fix(tree.Order)
				app1 := make([]byte, exif.HeaderSize+tree.TreeSize())
				next := exif.PutHeader(app1)
				_, err = tree.Put(app1[next:])
				if err != nil {
					return out.Bytes(), err
				}
				buf = app1
			}

		}
		if err := dumper.Dump(marker, buf); err != nil {
			return out.Bytes(), err
		}
	}
}

const (
	TIFFFile = 1
	JPEGFile = 2
)

// Determine if file is TIFF, JPEG or neither (error)
func fileType(file io.Reader) (int, error) {
	buf := make([]byte, tiff.HeaderSize)
	if _, err := io.ReadFull(file, buf); err != nil {
		return 0, err
	}
	if jseg.IsJPEGHeader(buf) {
		return JPEGFile, nil
	}
	if validTIFF, _, _ := tiff.GetHeader(buf); validTIFF {
		return TIFFFile, nil
	}
	return 0, errors.New("File doesn't have a TIFF or JPEG header")
}

// Decode a TIFF file, or the Exif segment in a JPEG file, then re-encode
// it and write to a new file.
func main() {
	if len(os.Args) != 3 {
		fmt.Printf("Usage: %s file outfile\n", os.Args[0])
		return
	}
	file, err := os.Open(os.Args[1])
	if err != nil {
		log.Fatal(err)
	}
	defer file.Close()
	fileType, err := fileType(file)
	if err != nil {
		log.Fatal(err)
	}
	if _, err := file.Seek(0, 0); err != nil {
		log.Fatal(err)
	}
	var out []byte
	if fileType == TIFFFile {
		out, err = processTIFF(file)
		if err != nil {
			log.Fatal(err)
		}
	} else {
		out, err = processJPEG(file)
		if err != nil {
			log.Fatal(err)
		}
	}
	ioutil.WriteFile(os.Args[2], out, 0644)
}
<commit_msg>reorganize<commit_after>package main

import (
	"errors"
	"fmt"
	exif "github.com/garyhouston/exif44"
	jseg "github.com/garyhouston/jpegsegs"
	tiff "github.com/garyhouston/tiff66"
	"io"
	"io/ioutil"
	"log"
	"os"
)

func processTIFF(infile io.Reader, outfile io.Writer) error {
	buf, err := ioutil.ReadAll(infile)
	if err != nil {
		return err
	}
	validTIFF, order, ifdPos := tiff.GetHeader(buf)
	if !validTIFF {
		return errors.New("processTIFF: invalid TIFF header")
	}
	root, err := tiff.GetIFDTree(buf, order, ifdPos, tiff.TIFFSpace)
	if err != nil {
		return err
	}
	root.Fix(order)
	fileSize := tiff.HeaderSize + root.TreeSize()
	out := make([]byte, fileSize)
	tiff.PutHeader(out, order, tiff.HeaderSize)
	_, err = root.PutIFDTree(out, tiff.HeaderSize, order)
	if err != nil {
		return err
	}
	_, err = outfile.Write(out)
	return err
}

func processJPEG(infile io.Reader, outfile io.Writer) error {
	scanner, err := jseg.NewScanner(infile)
	if err != nil {
		return err
	}
	dumper, err := jseg.NewDumper(outfile)
	if err != nil {
		return err
	}
	for {
		marker, buf, err := scanner.Scan()
		if err != nil {
			return err
		}
		if marker == jseg.SOS {
			// Start of scan data, no more metadata expected.
			if err := dumper.Dump(marker, nil); err != nil {
				return err
			}
			err := dumper.Copy(scanner)
			return err
		}
		if marker == jseg.APP0+1 {
			isExif, next := exif.GetHeader(buf)
			if isExif {
				tree, err := exif.GetExifTree(buf[next:])
				if err != nil {
					return err
				}
				tree.Tree.Fix(tree.Order)
				app1 := make([]byte, exif.HeaderSize+tree.TreeSize())
				next := exif.PutHeader(app1)
				_, err = tree.Put(app1[next:])
				if err != nil {
					return err
				}
				buf = app1
			}

		}
		if err := dumper.Dump(marker, buf); err != nil {
			return err
		}
	}
}

const (
	TIFFFile = 1
	JPEGFile = 2
)

// Determine if file is TIFF, JPEG or neither (error)
func fileType(file io.Reader) (int, error) {
	buf := make([]byte, tiff.HeaderSize)
	if _, err := io.ReadFull(file, buf); err != nil {
		return 0, err
	}
	if jseg.IsJPEGHeader(buf) {
		return JPEGFile, nil
	}
	if validTIFF, _, _ := tiff.GetHeader(buf); validTIFF {
		return TIFFFile, nil
	}
	return 0, errors.New("File doesn't have a TIFF or JPEG header")
}

// Decode a TIFF file, or the Exif segment in a JPEG file, then re-encode
// it and write to a new file.
func main() {
	if len(os.Args) != 3 {
		fmt.Printf("Usage: %s file outfile\n", os.Args[0])
		return
	}
	infile, err := os.Open(os.Args[1])
	if err != nil {
		log.Fatal(err)
	}
	defer infile.Close()
	fileType, err := fileType(infile)
	if err != nil {
		log.Fatal(err)
	}
	if _, err := infile.Seek(0, 0); err != nil {
		log.Fatal(err)
	}
	outfile, err := os.Create(os.Args[2])
	if err != nil {
		log.Fatal(err)
	}
	defer outfile.Close()
	if fileType == TIFFFile {
		err = processTIFF(infile, outfile)
		if err != nil {
			log.Fatal(err)
		}
	} else {
		err = processJPEG(infile, outfile)
		if err != nil {
			log.Fatal(err)
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 Factom Foundation
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package common

import (
	"bytes"
	"encoding/binary"
	"fmt"
)

// An Entry is the element which carries user data
// https://github.com/FactomProject/FactomDocs/blob/master/factomDataStructureDetails.md#entry
type Entry struct {
	Version     uint8  	// 1
	ChainID     *Hash   // 33
	ExIDSize    uint16 	// 2
	PayloadSize uint16 	// 2 Total of 38 bytes // to be changed to 37??
	ExtIDs      [][]byte
	Data        []byte
}

func (e *Entry) MarshalBinary() ([]byte, error) {
	var buf bytes.Buffer

	// Write Version
	binary.Write(&buf, binary.BigEndian, e.Version)

	// Write ChainID
	data, err := e.ChainID.MarshalBinary()
	if err != nil {
		return nil, err
	}
	buf.Write(data)

	// First compute the ExIDSize
	var exIDSize uint16

	for _, exId := range e.ExtIDs {
		exIDSize += 2 // Add 2 for the length
		exIDSize += uint16(len(exId))
	}

	// Write ExIDSize
	binary.Write(&buf, binary.BigEndian, exIDSize)

	// Write the Payload Size
	var payloadsize uint16
	payloadsize = uint16(len(e.Data)) + exIDSize
	if payloadsize > MAX_ENTRY_SIZE {
		return nil, fmt.Errorf("Size of entry exceeds Entry Size Limit, i.e ", payloadsize, " > ", MAX_ENTRY_SIZE)
	}
	binary.Write(&buf, binary.BigEndian, payloadsize)

	// Write out the External IDs
	for _, exId := range e.ExtIDs {
		var size uint16
		size = uint16(len(exId))
		binary.Write(&buf, binary.BigEndian, size)
		buf.Write(exId)
	}

	// Write out the Data
	buf.Write(e.Data)

	return buf.Bytes(), nil
}

func (e *Entry) NewUnmarshalBinary(d []byte) (err error) {
	buf := bytes.NewBuffer(d)

	// 1 byte Version
	e.Version, err = buf.ReadByte()
	if err != nil {
		return err
	}

	// 32 byte ChainID
	e.ChainID = new(Hash)
	e.ChainID.Bytes = make([]byte, 0, 32)
	if _, err := buf.Read(e.ChainID.Bytes); err != nil {
		return err
	}

	// 2 byte size of ExtIDs
	if err := binary.Read(buf, binary.BigEndian, int16(e.ExIDSize)); err != nil {
		return err
	}

	// 2 byte size of the Payload
	if err := binary.Read(buf, binary.BigEndian, int16(e.PayloadSize)); err != nil {
		return err
	}

	// unmarshal the extids
	for i := e.ExIDSize; i > 0; {
		xsize := int16(0)
		binary.Read(buf, binary.BigEndian, xsize)
		i -= 2

		x := make([]byte, 0, xsize)
		if n, err := buf.Read(x); err != nil {
			return err
		} else {
			if c := cap(x); n != c {
				return fmt.Errorf("Could not read ExtID: Read %d bytes of %d\n",
					n, c)
			}
			e.ExtIDs = append(e.ExtIDs, x)
			i -= uint16(n)
		}
	}

	// content
	e.Data = buf.Bytes()

	return nil
}

func (e *Entry) UnmarshalBinary(data []byte) (err error) {
	totalSize := len(data)

	// Get the Version byte
	e.Version, data = data[0], data[1:]

	// Get the ChainID
	e.ChainID = new(Hash)
	err = e.ChainID.UnmarshalBinary(data)
	if err != nil {
		return err
	}
	data = data[e.ChainID.MarshalledSize():]

	// Get the External ID Size
	e.ExIDSize, data = binary.BigEndian.Uint16(data[0:2]), data[2:]
	e.PayloadSize, data = binary.BigEndian.Uint16(data[0:2]), data[2:]

	if  totalSize> int(MAX_ENTRY_SIZE) || uint16(totalSize) != e.PayloadSize+38 {		// 38 to be changed to 37??
		return fmt.Errorf("Data is too long, or Lengths don't add up")
	} else if e.ExIDSize > e.PayloadSize {
		return fmt.Errorf("External IDs are longer than the payload size")
	}

	var size, cnt, eid_len uint16

	datas := data
	for size < e.ExIDSize {
		cnt++
		eid_len, datas = binary.BigEndian.Uint16(datas[0:2]), datas[2:]
		size += eid_len + 2
		if size > e.ExIDSize {
			return fmt.Errorf("Invalid External IDs")
		}
		datas = datas[eid_len:]
	}

	// we only get out of this nice when size == e.ExIDSize.
	// Otherwise we get an error.
	e.ExtIDs = make([][]byte, cnt, cnt)
	for i := uint16(0); i < cnt; i++ {
		eid_len, data = binary.BigEndian.Uint16(data[0:2]), data[2:]
		e.ExtIDs[i] = make([]byte, eid_len, eid_len)
		copy(e.ExtIDs[i], data[0:eid_len])
		data = data[eid_len:]
	}

	data_len := e.PayloadSize - e.ExIDSize
	e.Data = make([]byte, data_len, data_len)
	copy(e.Data, data)

	return nil
}

func GetChainID(chainName [][]byte) (chainID *Hash, err error) {
	byteSlice := make([]byte, 0, 64)

	if len(chainName) == 0 {
		err = fmt.Errorf("Some name is required to create a ChainID")
		return nil, err
	}

	for _, bytes := range chainName {
		byteSlice = append(byteSlice, Sha(bytes).Bytes...)
	}
	chainID = Sha(byteSlice)
	return chainID, nil
}

// To generate a chain id (hash) from a binary array name
// The algorithm is chainID = Sha(Sha(Name[0]) + Sha(Name[1] + ... + Sha(Name[n])
func (b *Entry) GenerateIDFromName() (chainID *Hash, err error) {
	return GetChainID(b.ExtIDs)
}
<commit_msg>func (*Entry) UnmarshalBinary<commit_after>// Copyright 2015 Factom Foundation
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package common

import (
	"bytes"
	"encoding/binary"
	"fmt"
)

// An Entry is the element which carries user data
// https://github.com/FactomProject/FactomDocs/blob/master/factomDataStructureDetails.md#entry
type Entry struct {
	Version     uint8  // 1
	ChainID     *Hash  // 33
	ExIDSize    uint16 // 2
	PayloadSize uint16 // 2 Total of 38 bytes // to be changed to 37??
	ExtIDs      [][]byte
	Data        []byte
}

func (e *Entry) MarshalBinary() ([]byte, error) {
	var buf bytes.Buffer

	// Write Version
	binary.Write(&buf, binary.BigEndian, e.Version)

	// Write ChainID
	data, err := e.ChainID.MarshalBinary()
	if err != nil {
		return nil, err
	}
	buf.Write(data)

	// First compute the ExIDSize
	var exIDSize uint16

	for _, exId := range e.ExtIDs {
		exIDSize += 2 // Add 2 for the length
		exIDSize += uint16(len(exId))
	}

	// Write ExIDSize
	binary.Write(&buf, binary.BigEndian, exIDSize)

	// Write the Payload Size
	var payloadsize uint16
	payloadsize = uint16(len(e.Data)) + exIDSize
	if payloadsize > MAX_ENTRY_SIZE {
		return nil, fmt.Errorf("Size of entry exceeds Entry Size Limit, i.e ", payloadsize, " > ", MAX_ENTRY_SIZE)
	}
	binary.Write(&buf, binary.BigEndian, payloadsize)

	// Write out the External IDs
	for _, exId := range e.ExtIDs {
		var size uint16
		size = uint16(len(exId))
		binary.Write(&buf, binary.BigEndian, size)
		buf.Write(exId)
	}

	// Write out the Data
	buf.Write(e.Data)

	return buf.Bytes(), nil
}

func (e *Entry) UnmarshalBinary(d []byte) (err error) {
	buf := bytes.NewBuffer(d)

	// 1 byte Version
	e.Version, err = buf.ReadByte()
	if err != nil {
		return err
	}

	// 32 byte ChainID
	e.ChainID = new(Hash)
	e.ChainID.Bytes = make([]byte, 32)
	if _, err := buf.Read(e.ChainID.Bytes); err != nil {
		return err
	}

	// 2 byte size of ExtIDs
	if err := binary.Read(buf, binary.BigEndian, &e.ExIDSize); err != nil {
		return err
	}

	// 2 byte size of the Payload
	if err := binary.Read(buf, binary.BigEndian, &e.PayloadSize); err != nil {
		return err
	}

	// unmarshal the extids
	for i := e.ExIDSize; i > 0; {
		var xsize int16
		binary.Read(buf, binary.BigEndian, &xsize)
		i -= 2

		x := make([]byte, xsize)
		if n, err := buf.Read(x); err != nil {
			return err
		} else {
			if c := cap(x); n != c {
				return fmt.Errorf("Could not read ExtID: Read %d bytes of %d\n",
					n, c)
			}
			e.ExtIDs = append(e.ExtIDs, x)
			i -= uint16(n)
		}
	}

	// content
	e.Data = buf.Bytes()

	return nil
}

func GetChainID(chainName [][]byte) (chainID *Hash, err error) {
	byteSlice := make([]byte, 0, 64)

	if len(chainName) == 0 {
		err = fmt.Errorf("Some name is required to create a ChainID")
		return nil, err
	}

	for _, bytes := range chainName {
		byteSlice = append(byteSlice, Sha(bytes).Bytes...)
	}
	chainID = Sha(byteSlice)
	return chainID, nil
}

// To generate a chain id (hash) from a binary array name
// The algorithm is chainID = Sha(Sha(Name[0]) + Sha(Name[1] + ... + Sha(Name[n])
func (b *Entry) GenerateIDFromName() (chainID *Hash, err error) {
	return GetChainID(b.ExtIDs)
}
<|endoftext|>


<commit_before>// +build go1.7
package docker

import (
	"crypto/tls"
	"net"
	"net/http"
	"strings"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/fsouza/go-dockerclient"
	"github.com/iron-io/worker/common"
	"github.com/iron-io/worker/runner/agent"
	"golang.org/x/net/context"
)

// wrap docker client calls so we can retry 500s, kind of sucks but fsouza doesn't
// bake in retries we can use internally, could contribute it at some point, would
// be much more convenient if we didn't have to do this, but it's better than ad hoc retries.
// also adds timeouts to many operations, varying by operation
// TODO could generate this, maybe not worth it, may not change often
type dockerClient interface {
	// Each of these are github.com/fsouza/go-dockerclient methods

	AttachToContainerNonBlocking(opts docker.AttachToContainerOptions) (docker.CloseWaiter, error)
	WaitContainer(ctx context.Context, id string) (int, error)
	StartContainer(id string, hostConfig *docker.HostConfig) error
	CreateContainer(opts docker.CreateContainerOptions) (*docker.Container, error)
	RemoveContainer(opts docker.RemoveContainerOptions) error
	PullImage(opts docker.PullImageOptions, auth docker.AuthConfiguration) error
	InspectImage(name string) (*docker.Image, error)
	InspectContainer(id string) (*docker.Container, error)
	StopContainer(id string, timeout uint) error
	Stats(opts docker.StatsOptions) error
}

// TODO: switch to github.com/docker/engine-api
func newClient(env *common.Environment) dockerClient {
	// TODO this was much easier, don't need special settings at the moment
	// docker, err := docker.NewClient(conf.Docker)
	client, err := docker.NewClientFromEnv()
	if err != nil {
		logrus.WithError(err).Fatal("couldn't create docker client")
	}

	client.HTTPClient = &http.Client{
		Transport: &http.Transport{
			Dial: (&net.Dialer{
				Timeout:   10 * time.Second,
				KeepAlive: 1 * time.Minute,
			}).Dial,
			TLSClientConfig: &tls.Config{
				ClientSessionCache: tls.NewLRUClientSessionCache(8192),
			},
			TLSHandshakeTimeout:   10 * time.Second,
			MaxIdleConnsPerHost:   512,
			Proxy:                 http.ProxyFromEnvironment,
			MaxIdleConns:          512,
			IdleConnTimeout:       90 * time.Second,
			ExpectContinueTimeout: 1 * time.Second,
		},
	}

	if err := client.Ping(); err != nil {
		logrus.WithError(err).Fatal("couldn't connect to docker daemon")
	}

	client.SetTimeout(120 * time.Second)

	// get 2 clients, one with a small timeout, one with a large timeout
	// long timeout used for:
	// * pull
	// * create_container

	clientLongTimeout, err := docker.NewClientFromEnv()
	if err != nil {
		logrus.WithError(err).Fatal("couldn't create other docker client")
	}

	clientLongTimeout.HTTPClient = &http.Client{
		Transport: &http.Transport{
			Dial: (&net.Dialer{
				Timeout:   10 * time.Second,
				KeepAlive: 1 * time.Minute,
			}).Dial,
			TLSClientConfig: &tls.Config{
				ClientSessionCache: tls.NewLRUClientSessionCache(8192),
			},
			TLSHandshakeTimeout:   10 * time.Second,
			MaxIdleConnsPerHost:   512,
			Proxy:                 http.ProxyFromEnvironment,
			MaxIdleConns:          512,
			IdleConnTimeout:       90 * time.Second,
			ExpectContinueTimeout: 1 * time.Second,
		},
	}

	if err := clientLongTimeout.Ping(); err != nil {
		logrus.WithError(err).Fatal("couldn't connect to docker daemon")
	}

	client.SetTimeout(30 * time.Minute) // TODO ? this seems high but... hub can be really slow

	return &dockerWrap{client, clientLongTimeout, env}
}

type dockerWrap struct {
	docker            *docker.Client
	dockerLongTimeout *docker.Client
	*common.Environment
}

func (d *dockerWrap) retry(f func() error) error {
	var b agent.Backoff
	then := time.Now()
	limit := 10 * time.Minute
	var err error
	for time.Since(then) < limit {
		timer := d.NewTimer("docker", "latency", 1)
		err = filter(f())
		timer.Measure()
		if agent.IsTemporary(err) || isDocker500(err) {
			logrus.WithError(err).Warn("docker temporary error, retrying")
			b.Sleep()
			d.Inc("task", "error.docker", 1, 1)
			continue
		}
		d.Inc("task", "error.docker", 1, 1)
		return err
	}
	d.Inc("task", "fail.docker", 1, 1)
	logrus.WithError(err).Warnf("retrying on docker errors exceeded %s, restart docker or rotate this instance?", limit)
	return err
}

func isDocker500(err error) bool {
	derr, ok := err.(*docker.Error)
	return ok && derr.Status >= 500
}

type temporary struct {
	error
}

func (t *temporary) Temporary() bool { return true }

func temp(err error) error {
	return &temporary{err}
}

// some 500s are totally cool
func filter(err error) error {
	// "API error (500): {\"message\":\"service endpoint with name task-57d722ecdecb9e7be16aff17 already exists\"}\n" -> ok since container exists
	switch {
	default:
		return err
	case err == nil:
		return err
	case strings.Contains(err.Error(), "service endpoint with name"):
	}
	logrus.WithError(err).Warn("filtering error")
	return nil
}

func (d *dockerWrap) AttachToContainerNonBlocking(opts docker.AttachToContainerOptions) (w docker.CloseWaiter, err error) {
	err = d.retry(func() error {
		w, err = d.docker.AttachToContainerNonBlocking(opts)
		if err != nil {
			// always retry if attach errors, task is running, we want logs!
			err = temp(err)
		}
		return err
	})
	return w, err
}

func (d *dockerWrap) WaitContainer(ctx context.Context, id string) (code int, err error) {
	// special one, since fsouza doesn't have context on this one and tasks can
	// take longer than 20 minutes
	for {
		// backup bail mechanism so this doesn't sit here forever
		select {
		case <-ctx.Done():
		default:
		}

		err = d.retry(func() error {
			code, err = d.docker.WaitContainer(id)
			return err
		})
		err = filterNoSuchContainer(err)
		if err == nil {
			break
		}
		logrus.WithError(err).Warn("retrying wait container (this is ok)")
	}
	return code, err
}

func filterNoSuchContainer(err error) error {
	if err == nil {
		return nil
	}
	_, containerNotFound := err.(*docker.NoSuchContainer)
	dockerErr, ok := err.(*docker.Error)
	if containerNotFound || (ok && dockerErr.Status == 404) {
		logrus.WithError(err).Error("filtering error")
		return nil
	}
	return err
}

func filterNotRunning(err error) error {
	if err == nil {
		return nil
	}

	_, containerNotRunning := err.(*docker.ContainerNotRunning)
	dockerErr, ok := err.(*docker.Error)
	if containerNotRunning || (ok && dockerErr.Status == 304) {
		logrus.WithError(err).Error("filtering error")
		return nil
	}

	return err
}

func (d *dockerWrap) StartContainer(id string, hostConfig *docker.HostConfig) (err error) {
	err = d.retry(func() error {
		err = d.docker.StartContainer(id, hostConfig)
		if _, ok := err.(*docker.NoSuchContainer); ok {
			// for some reason create will sometimes return successfully then say no such container here. wtf. so just retry like normal
			return temp(err)
		}
		return err
	})
	return err
}

func (d *dockerWrap) CreateContainer(opts docker.CreateContainerOptions) (c *docker.Container, err error) {
	err = d.retry(func() error {
		c, err = d.dockerLongTimeout.CreateContainer(opts)
		return err
	})
	return c, err
}

func (d *dockerWrap) RemoveContainer(opts docker.RemoveContainerOptions) (err error) {
	err = d.retry(func() error {
		err = d.docker.RemoveContainer(opts)
		return err
	})
	return filterNoSuchContainer(err)
}

func (d *dockerWrap) PullImage(opts docker.PullImageOptions, auth docker.AuthConfiguration) (err error) {
	err = d.retry(func() error {
		err = d.dockerLongTimeout.PullImage(opts, auth)
		return err
	})
	return err
}

func (d *dockerWrap) InspectImage(name string) (i *docker.Image, err error) {
	err = d.retry(func() error {
		i, err = d.docker.InspectImage(name)
		return err
	})
	return i, err
}

func (d *dockerWrap) InspectContainer(id string) (c *docker.Container, err error) {
	err = d.retry(func() error {
		c, err = d.docker.InspectContainer(id)
		return err
	})
	return c, err
}

func (d *dockerWrap) StopContainer(id string, timeout uint) (err error) {
	err = d.retry(func() error {
		err = d.docker.StopContainer(id, timeout)
		return err
	})
	return filterNotRunning(filterNoSuchContainer(err))
}

func (d *dockerWrap) Stats(opts docker.StatsOptions) (err error) {
	err = d.retry(func() error {
		err = d.docker.Stats(opts)
		return err
	})
	return err
}
<commit_msg>Amend log message of other docker ping<commit_after>// +build go1.7
package docker

import (
	"crypto/tls"
	"net"
	"net/http"
	"strings"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/fsouza/go-dockerclient"
	"github.com/iron-io/worker/common"
	"github.com/iron-io/worker/runner/agent"
	"golang.org/x/net/context"
)

// wrap docker client calls so we can retry 500s, kind of sucks but fsouza doesn't
// bake in retries we can use internally, could contribute it at some point, would
// be much more convenient if we didn't have to do this, but it's better than ad hoc retries.
// also adds timeouts to many operations, varying by operation
// TODO could generate this, maybe not worth it, may not change often
type dockerClient interface {
	// Each of these are github.com/fsouza/go-dockerclient methods

	AttachToContainerNonBlocking(opts docker.AttachToContainerOptions) (docker.CloseWaiter, error)
	WaitContainer(ctx context.Context, id string) (int, error)
	StartContainer(id string, hostConfig *docker.HostConfig) error
	CreateContainer(opts docker.CreateContainerOptions) (*docker.Container, error)
	RemoveContainer(opts docker.RemoveContainerOptions) error
	PullImage(opts docker.PullImageOptions, auth docker.AuthConfiguration) error
	InspectImage(name string) (*docker.Image, error)
	InspectContainer(id string) (*docker.Container, error)
	StopContainer(id string, timeout uint) error
	Stats(opts docker.StatsOptions) error
}

// TODO: switch to github.com/docker/engine-api
func newClient(env *common.Environment) dockerClient {
	// TODO this was much easier, don't need special settings at the moment
	// docker, err := docker.NewClient(conf.Docker)
	client, err := docker.NewClientFromEnv()
	if err != nil {
		logrus.WithError(err).Fatal("couldn't create docker client")
	}

	client.HTTPClient = &http.Client{
		Transport: &http.Transport{
			Dial: (&net.Dialer{
				Timeout:   10 * time.Second,
				KeepAlive: 1 * time.Minute,
			}).Dial,
			TLSClientConfig: &tls.Config{
				ClientSessionCache: tls.NewLRUClientSessionCache(8192),
			},
			TLSHandshakeTimeout:   10 * time.Second,
			MaxIdleConnsPerHost:   512,
			Proxy:                 http.ProxyFromEnvironment,
			MaxIdleConns:          512,
			IdleConnTimeout:       90 * time.Second,
			ExpectContinueTimeout: 1 * time.Second,
		},
	}

	if err := client.Ping(); err != nil {
		logrus.WithError(err).Fatal("couldn't connect to docker daemon")
	}

	client.SetTimeout(120 * time.Second)

	// get 2 clients, one with a small timeout, one with a large timeout
	// long timeout used for:
	// * pull
	// * create_container

	clientLongTimeout, err := docker.NewClientFromEnv()
	if err != nil {
		logrus.WithError(err).Fatal("couldn't create other docker client")
	}

	clientLongTimeout.HTTPClient = &http.Client{
		Transport: &http.Transport{
			Dial: (&net.Dialer{
				Timeout:   10 * time.Second,
				KeepAlive: 1 * time.Minute,
			}).Dial,
			TLSClientConfig: &tls.Config{
				ClientSessionCache: tls.NewLRUClientSessionCache(8192),
			},
			TLSHandshakeTimeout:   10 * time.Second,
			MaxIdleConnsPerHost:   512,
			Proxy:                 http.ProxyFromEnvironment,
			MaxIdleConns:          512,
			IdleConnTimeout:       90 * time.Second,
			ExpectContinueTimeout: 1 * time.Second,
		},
	}

	if err := clientLongTimeout.Ping(); err != nil {
		logrus.WithError(err).Fatal("couldn't connect to other docker daemon")
	}

	client.SetTimeout(30 * time.Minute) // TODO ? this seems high but... hub can be really slow

	return &dockerWrap{client, clientLongTimeout, env}
}

type dockerWrap struct {
	docker            *docker.Client
	dockerLongTimeout *docker.Client
	*common.Environment
}

func (d *dockerWrap) retry(f func() error) error {
	var b agent.Backoff
	then := time.Now()
	limit := 10 * time.Minute
	var err error
	for time.Since(then) < limit {
		timer := d.NewTimer("docker", "latency", 1)
		err = filter(f())
		timer.Measure()
		if agent.IsTemporary(err) || isDocker500(err) {
			logrus.WithError(err).Warn("docker temporary error, retrying")
			b.Sleep()
			d.Inc("task", "error.docker", 1, 1)
			continue
		}
		d.Inc("task", "error.docker", 1, 1)
		return err
	}
	d.Inc("task", "fail.docker", 1, 1)
	logrus.WithError(err).Warnf("retrying on docker errors exceeded %s, restart docker or rotate this instance?", limit)
	return err
}

func isDocker500(err error) bool {
	derr, ok := err.(*docker.Error)
	return ok && derr.Status >= 500
}

type temporary struct {
	error
}

func (t *temporary) Temporary() bool { return true }

func temp(err error) error {
	return &temporary{err}
}

// some 500s are totally cool
func filter(err error) error {
	// "API error (500): {\"message\":\"service endpoint with name task-57d722ecdecb9e7be16aff17 already exists\"}\n" -> ok since container exists
	switch {
	default:
		return err
	case err == nil:
		return err
	case strings.Contains(err.Error(), "service endpoint with name"):
	}
	logrus.WithError(err).Warn("filtering error")
	return nil
}

func (d *dockerWrap) AttachToContainerNonBlocking(opts docker.AttachToContainerOptions) (w docker.CloseWaiter, err error) {
	err = d.retry(func() error {
		w, err = d.docker.AttachToContainerNonBlocking(opts)
		if err != nil {
			// always retry if attach errors, task is running, we want logs!
			err = temp(err)
		}
		return err
	})
	return w, err
}

func (d *dockerWrap) WaitContainer(ctx context.Context, id string) (code int, err error) {
	// special one, since fsouza doesn't have context on this one and tasks can
	// take longer than 20 minutes
	for {
		// backup bail mechanism so this doesn't sit here forever
		select {
		case <-ctx.Done():
		default:
		}

		err = d.retry(func() error {
			code, err = d.docker.WaitContainer(id)
			return err
		})
		err = filterNoSuchContainer(err)
		if err == nil {
			break
		}
		logrus.WithError(err).Warn("retrying wait container (this is ok)")
	}
	return code, err
}

func filterNoSuchContainer(err error) error {
	if err == nil {
		return nil
	}
	_, containerNotFound := err.(*docker.NoSuchContainer)
	dockerErr, ok := err.(*docker.Error)
	if containerNotFound || (ok && dockerErr.Status == 404) {
		logrus.WithError(err).Error("filtering error")
		return nil
	}
	return err
}

func filterNotRunning(err error) error {
	if err == nil {
		return nil
	}

	_, containerNotRunning := err.(*docker.ContainerNotRunning)
	dockerErr, ok := err.(*docker.Error)
	if containerNotRunning || (ok && dockerErr.Status == 304) {
		logrus.WithError(err).Error("filtering error")
		return nil
	}

	return err
}

func (d *dockerWrap) StartContainer(id string, hostConfig *docker.HostConfig) (err error) {
	err = d.retry(func() error {
		err = d.docker.StartContainer(id, hostConfig)
		if _, ok := err.(*docker.NoSuchContainer); ok {
			// for some reason create will sometimes return successfully then say no such container here. wtf. so just retry like normal
			return temp(err)
		}
		return err
	})
	return err
}

func (d *dockerWrap) CreateContainer(opts docker.CreateContainerOptions) (c *docker.Container, err error) {
	err = d.retry(func() error {
		c, err = d.dockerLongTimeout.CreateContainer(opts)
		return err
	})
	return c, err
}

func (d *dockerWrap) RemoveContainer(opts docker.RemoveContainerOptions) (err error) {
	err = d.retry(func() error {
		err = d.docker.RemoveContainer(opts)
		return err
	})
	return filterNoSuchContainer(err)
}

func (d *dockerWrap) PullImage(opts docker.PullImageOptions, auth docker.AuthConfiguration) (err error) {
	err = d.retry(func() error {
		err = d.dockerLongTimeout.PullImage(opts, auth)
		return err
	})
	return err
}

func (d *dockerWrap) InspectImage(name string) (i *docker.Image, err error) {
	err = d.retry(func() error {
		i, err = d.docker.InspectImage(name)
		return err
	})
	return i, err
}

func (d *dockerWrap) InspectContainer(id string) (c *docker.Container, err error) {
	err = d.retry(func() error {
		c, err = d.docker.InspectContainer(id)
		return err
	})
	return c, err
}

func (d *dockerWrap) StopContainer(id string, timeout uint) (err error) {
	err = d.retry(func() error {
		err = d.docker.StopContainer(id, timeout)
		return err
	})
	return filterNotRunning(filterNoSuchContainer(err))
}

func (d *dockerWrap) Stats(opts docker.StatsOptions) (err error) {
	err = d.retry(func() error {
		err = d.docker.Stats(opts)
		return err
	})
	return err
}
<|endoftext|>


<commit_before>package main

import(
	"fmt"
	"gofire/command"
	"encoding/json"
	//"regexp"
	//"strings"
	"code.google.com/p/go.net/websocket"
)

type User struct {
	Name string
}

type Connection struct {
	//User who sends
	Usr *User
	//websocket-connection
	Conn *websocket.Conn
	// Buffered channel of outbound messages.
	send chan *command.Command
	// chatroom in which the user is
	chatRoom *ChatRoom
}

func (c *Connection) Read() {
	for {
		//var message string
		var rawIncome []byte

		err := websocket.Message.Receive(c.Conn, &rawIncome)
		if err != nil {
			fmt.Println(err)
			break
		}

		var cmd *command.Command

		//var userName string
		var found bool

		err = json.Unmarshal([]byte(rawIncome), &cmd)

		if err == nil {

			//REGISTER -> {REGISTER, USERNAME}
			if cmd.Type == command.REGISTER {
				//check if user name already is taken.
				for d := range server.registeredConnections {
					if d.Usr != nil && d.Usr.Name == string(cmd.Value) {
						found = true
					}
				}
				if found {
					break
				} else {
					c.Usr = &User{Name: string(cmd.Value)}
				}
			}

			/*if cmd.Type == command.MESSAGE {
				//check if the message is a private message.
				r, _ := regexp.MatchString("@", string(cmd.Value))
				if r {
					found = false
					userName = strings.Split(string(cmd.Value), " ")[0]
					userName = strings.Split(userName, "@")[1]
					for d := range server.registeredConnections {
						if d.Usr.Name == userName {
							d.send <- &Message{c.Usr, cmd.Value}
							found = true
						}
					}
					if found {
						c.send <- &Message{c.Usr, cmd.Value}
					} else {
						c.send <- &Message{&User{"From server"}, []byte("user not found")}
					}
					//else send the message to everyone
				} else {
					c.chatRoom.broadcast <- &Message{c.Usr, cmd.Value}
				}*/
			}

			if cmd.Type == command.BLOGIN {
				m, errm := json.Marshal(Message{c.Usr, []byte("Logged In")})
				if errm == nil{
					c.chatRoom.broadcast <- &command.Command{command.BMESSAGE, m}
				}else{
					fmt.Println(errm)
				}

			}

			if cmd.Type == command.BLOGOUT {
				m, errm := json.Marshal(Message{c.Usr, []byte("Logged out")})
				if errm == nil{
					c.chatRoom.broadcast <- &command.Command{command.BMESSAGE, m}
				}else{
					fmt.Println(errm)
				}

			}
		}

	c.Conn.Close()
}

func (c *Connection) Write() {
	for command := range c.send {
		//marshal in

		jsonC, _ := json.Marshal(command)

		err := websocket.Message.Send(c.Conn, string(jsonC))
		if err != nil {
			break
		}
	}
}
<commit_msg>bmessage command implementation<commit_after>package main

import(
	"fmt"
	"gofire/command"
	"encoding/json"
	//"regexp"
	//"strings"
	"code.google.com/p/go.net/websocket"
)

type User struct {
	Name string
}

type Connection struct {
	//User who sends
	Usr *User
	//websocket-connection
	Conn *websocket.Conn
	// Buffered channel of outbound messages.
	send chan *command.Command
	// chatroom in which the user is
	chatRoom *ChatRoom
}

func (c *Connection) Read() {
	for {
		//var message string
		var rawIncome []byte

		err := websocket.Message.Receive(c.Conn, &rawIncome)
		if err != nil {
			fmt.Println(err)
			break
		}

		var cmd *command.Command

		//var userName string
		var found bool

		err = json.Unmarshal([]byte(rawIncome), &cmd)

		if err == nil {
			//REGISTER -> {REGISTER, USERNAME}
			if cmd.Type == command.REGISTER {
				//check if user name already is taken.
				for d := range server.registeredConnections {
					if d.Usr != nil && d.Usr.Name == string(cmd.Value) {
						found = true
					}
				}
				if found {
					break
				} else {
					c.Usr = &User{Name: string(cmd.Value)}
				}
			}

			if cmd.Type == command.BMESSAGE {
				m, errm := json.Marshal(Message{c.Usr, cmd.Value})
				if errm == nil{
					c.chatRoom.broadcast <- &command.Command{command.BMESSAGE, m}
				}else{
					fmt.Println(errm)
				}
			}

			/*if cmd.Type == command.MESSAGE {
				//check if the message is a private message.
				r, _ := regexp.MatchString("@", string(cmd.Value))
				if r {
					found = false
					userName = strings.Split(string(cmd.Value), " ")[0]
					userName = strings.Split(userName, "@")[1]
					for d := range server.registeredConnections {
						if d.Usr.Name == userName {
							d.send <- &Message{c.Usr, cmd.Value}
							found = true
						}
					}
					if found {
						c.send <- &Message{c.Usr, cmd.Value}
					} else {
						c.send <- &Message{&User{"From server"}, []byte("user not found")}
					}
					//else send the message to everyone
				} else {
					c.chatRoom.broadcast <- &Message{c.Usr, cmd.Value}
				}*/
			}

			if cmd.Type == command.BLOGIN {
				m, errm := json.Marshal(Message{c.Usr, []byte("Logged In")})
				if errm == nil{
					c.chatRoom.broadcast <- &command.Command{command.BMESSAGE, m}
				}else{
					fmt.Println(errm)
				}

			}

			if cmd.Type == command.BLOGOUT {
				m, errm := json.Marshal(Message{c.Usr, []byte("Logged out")})
				if errm == nil{
					c.chatRoom.broadcast <- &command.Command{command.BMESSAGE, m}
				}else{
					fmt.Println(errm)
				}

			}
		}

	c.Conn.Close()
}

func (c *Connection) Write() {
	for command := range c.send {
		//marshal in

		jsonC, _ := json.Marshal(command)

		err := websocket.Message.Send(c.Conn, string(jsonC))
		if err != nil {
			break
		}
	}
}
<|endoftext|>


<commit_before>package filesystem

import (
	"io"
	"io/ioutil"
	"os"
	"path"
	"strconv"

	"github.com/appc/acserver/aci"
	"github.com/appc/acserver/storage"
	"github.com/appc/acserver/upload"
)

type Storage struct {
	directory string
	gpgPubKey *string
}

func NewStorage(directory string, gpgPubKey *string) (*Storage, error) {
	os.RemoveAll(path.Join(directory, "tmp"))

	if err := os.MkdirAll(path.Join(directory, "tmp"), 0755); err != nil {
		return nil, err
	}

	return &Storage{directory, gpgPubKey}, nil
}

func (s *Storage) GetGPGPubKey() ([]byte, error) {
	if s.gpgPubKey == nil {
		return []byte{}, storage.ErrGPGPubKeyNotProvided
	}

	return ioutil.ReadFile(*s.gpgPubKey)
}

func (s *Storage) ListACIs() ([]aci.Aci, error) {
	files, err := ioutil.ReadDir(s.directory)
	if err != nil {
		return nil, err
	}

	res := []aci.RawFile{}
	for _, file := range files {
		res = append(
			res,
			aci.RawFile{file.Name(), file.ModTime()},
		)
	}

	return aci.BuildAciList(res), nil
}

func (s *Storage) upload(path string, reader io.Reader) error {
	f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)

	if err != nil {
		return err
	}

	defer f.Close()

	_, err = io.Copy(f, reader)

	return err
}

func (s *Storage) UploadACI(up upload.Upload, reader io.Reader) error {
	return s.upload(
		path.Join(s.directory, "tmp", strconv.Itoa(int(up.ID))),
		reader,
	)
}

func (s *Storage) UploadASC(up upload.Upload, reader io.Reader) error {
	return s.upload(
		path.Join(s.directory, "tmp", strconv.Itoa(int(up.ID))+".asc"),
		reader,
	)
}

func (s *Storage) CancelUpload(up upload.Upload) error {
	os.Remove(path.Join(s.directory, "tmp", strconv.Itoa(int(up.ID))+".asc"))
	os.Remove(path.Join(s.directory, "tmp", strconv.Itoa(int(up.ID))))

	return nil
}

func (s *Storage) FinishUpload(up upload.Upload) error {
	if err := os.Rename(
		path.Join(s.directory, "tmp", strconv.Itoa(int(up.ID))),
		path.Join(s.directory, up.Image),
	); err != nil {
		return err
	}

	if err := os.Rename(
		path.Join(s.directory, "tmp", strconv.Itoa(int(up.ID))+".asc"),
		path.Join(s.directory, up.Image+".asc"),
	); err != nil {
		return err
	}

	return nil
}
<commit_msg>Add an fs impl of the DownloadACI method<commit_after>package filesystem

import (
	"io"
	"io/ioutil"
	"os"
	"path"
	"strconv"

	"github.com/appc/acserver/aci"
	"github.com/appc/acserver/storage"
	"github.com/appc/acserver/upload"
)

type Storage struct {
	directory string
	gpgPubKey *string
}

func NewStorage(directory string, gpgPubKey *string) (*Storage, error) {
	os.RemoveAll(path.Join(directory, "tmp"))

	if err := os.MkdirAll(path.Join(directory, "tmp"), 0755); err != nil {
		return nil, err
	}

	return &Storage{directory, gpgPubKey}, nil
}

func (s *Storage) GetGPGPubKey() ([]byte, error) {
	if s.gpgPubKey == nil {
		return []byte{}, storage.ErrGPGPubKeyNotProvided
	}

	return ioutil.ReadFile(*s.gpgPubKey)
}

func (s *Storage) ListACIs() ([]aci.Aci, error) {
	files, err := ioutil.ReadDir(s.directory)
	if err != nil {
		return nil, err
	}

	res := []aci.RawFile{}
	for _, file := range files {
		res = append(
			res,
			aci.RawFile{file.Name(), file.ModTime()},
		)
	}

	return aci.BuildAciList(res), nil
}

func (s *Storage) upload(path string, reader io.Reader) error {
	f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)

	if err != nil {
		return err
	}

	defer f.Close()

	_, err = io.Copy(f, reader)

	return err
}

func (s *Storage) UploadACI(up upload.Upload, reader io.Reader) error {
	return s.upload(
		path.Join(s.directory, "tmp", strconv.Itoa(int(up.ID))),
		reader,
	)
}

func (s *Storage) UploadASC(up upload.Upload, reader io.Reader) error {
	return s.upload(
		path.Join(s.directory, "tmp", strconv.Itoa(int(up.ID))+".asc"),
		reader,
	)
}

func (s *Storage) CancelUpload(up upload.Upload) error {
	os.Remove(path.Join(s.directory, "tmp", strconv.Itoa(int(up.ID))+".asc"))
	os.Remove(path.Join(s.directory, "tmp", strconv.Itoa(int(up.ID))))

	return nil
}

func (s *Storage) FinishUpload(up upload.Upload) error {
	if err := os.Rename(
		path.Join(s.directory, "tmp", strconv.Itoa(int(up.ID))),
		path.Join(s.directory, up.Image),
	); err != nil {
		return err
	}

	if err := os.Rename(
		path.Join(s.directory, "tmp", strconv.Itoa(int(up.ID))+".asc"),
		path.Join(s.directory, up.Image+".asc"),
	); err != nil {
		return err
	}

	return nil
}

func (s *Storage) DownloadACI(n string) (io.ReadSeeker, error) {
	return os.Open(path.Join(s.directory, n))
}
<|endoftext|>