<commit_before>package cmdr

import (
	"code.google.com/p/go.crypto/ssh"
	"io"
	"io/ioutil"
	"bufio"
	"os/exec"
	"fmt"
	"reflect"
	"errors"
	"strings"
)

func NewClientConfig(username, password, pemfile string) (*ssh.ClientConfig, error) {
	if username != "" && password != "" {
		answers := keyboardInteractive(map[string]string{"Password: ": password,})
		return &ssh.ClientConfig{
			User: username,
			Auth: []ssh.AuthMethod{
				ssh.KeyboardInteractive(answers.Challenge),
			},
		}, nil
	}

	if username != "" && pemfile != "" {
		signer, err := loadPEM(pemfile)
		if err != nil {
			return nil, err
		}

		return &ssh.ClientConfig{
			User: username,
			Auth: []ssh.AuthMethod{
				ssh.PublicKeys(signer),
			},
		}, nil
	}

	return nil, fmt.Errorf("Missing valid arguments, must pass a (username and password) or (username and pemfile).")
}

type Command struct {
	Session *exec.Cmd
	Stdin	chan string
	Stdout	chan string
	Stderr	chan string
}

type SSHCommand struct {
	Command
	Config *ssh.ClientConfig
	Server string
	Session *ssh.Session
	client *ssh.Client
}

func NewCommand(inchan, outchan, errchan chan string) (*Command, error) {
	return &Command{Stdin: inchan, Stdout: outchan, Stderr: errchan}, nil
}

func NewSSHCommand(cfg *ssh.ClientConfig, server string, inchan, outchan, errchan chan string) (*SSHCommand, error) {
	return &SSHCommand{Config: cfg, Server: server, Command: Command{Stdin: inchan, Stdout: outchan, Stderr: errchan}}, nil
}

func (c *Command) Execute(cmd string, args ...string) error {
	c.Session = exec.Command(cmd, args...)

	if err := execute(c, ""); err != nil {
		fmt.Printf("Execute Error: %s\n", err)
		return err
	}
	return nil
}

func (s *SSHCommand) Execute(cmd string) (err error) {
	s.client, err = ssh.Dial("tcp", s.Server, s.Config)
	if err != nil {
		return err
	}
	s.Session, err = s.client.NewSession()
	if err != nil {
		return err
	}

	if err = execute(s, cmd); err != nil {
		return err
	}
	return nil
}

func (c *Command) ProcessStdIn(notifier chan error, w io.WriteCloser) {
	processInput(c.Stdin, notifier, w)
}

func (c *Command) ProcessStdOut(notifier chan error, r io.Reader)  {
	processOutput(c.Stdout, notifier, r)
}

func (c *Command) ProcessStdErr(notifier chan error, r io.Reader)  {
	processOutput(c.Stderr, notifier, r)
}

func (c *SSHCommand) ProcessStdIn(notifier chan error, w io.WriteCloser) {
	processInput(c.Stdin, notifier, w)
}

func (s *SSHCommand) ProcessStdOut(notifier chan error, r io.Reader)  {
	processOutput(s.Stdout, notifier, r)
}

func (s *SSHCommand) ProcessStdErr(notifier chan error, r io.Reader)  {
	processOutput(s.Stderr, notifier, r)
}

func (s *SSHCommand) Close() {
	s.Session.Close()
	s.client.Close()
}

func execute(obj interface{}, cmd string) error {
	var innotifier chan error
	var outnotifier chan error
	var errnotifier chan error
	var ioerrs []string

	value := reflect.ValueOf(obj)
	vsession := value.Elem().FieldByName("Session")
	vstdin := value.Elem().FieldByName("Stdin")
	vstdout := value.Elem().FieldByName("Stdout")
	vstderr := value.Elem().FieldByName("Stderr")

	// Checking if a channel has been passed in to handle Stdout
	if !vstdin.IsNil() {
		innotifier := make(chan error)
		if method := vsession.MethodByName("StdinPipe"); method.IsValid() {
			values := method.Call(nil)
			if values[1].IsNil() {
				pipe := values[0].Interface()
				if processMethod := value.MethodByName("ProcessStdIn"); processMethod.IsValid() {
					go processMethod.Call([]reflect.Value{reflect.ValueOf(innotifier), reflect.ValueOf(pipe)})
				} else {
					return fmt.Errorf("ProcessStdIn method not found\n")
				}
			} else {
				return fmt.Errorf("An error occurred connecting up to Stdin: %s\n", values[1].Interface())
			}
		}
	}

	if !vstdout.IsNil() {
		outnotifier = make(chan error)
		if method := vsession.MethodByName("StdoutPipe"); method.IsValid() {
			values := method.Call(nil)
			if values[1].IsNil() {
				pipe := values[0].Interface()
				if processMethod := value.MethodByName("ProcessStdOut"); processMethod.IsValid() {
					go processMethod.Call([]reflect.Value{reflect.ValueOf(outnotifier), reflect.ValueOf(pipe)})
				} else {
					return fmt.Errorf("ProcessStdOut method not found\n")
				}
			} else {
				return fmt.Errorf("An error occurred connecting up to Stdout: %s\n", values[1].Interface())
			}
		}
	}
	if !vstderr.IsNil() {
		errnotifier = make(chan error)
		if method := vsession.MethodByName("StderrPipe"); method.IsValid() {
			values := method.Call(nil)
			if values[1].IsNil() {
				pipe := values[0].Interface()
				if processMethod := value.MethodByName("ProcessStdErr"); processMethod.IsValid() {
					go processMethod.Call([]reflect.Value{reflect.ValueOf(errnotifier), reflect.ValueOf(pipe)})
				} else {
					return fmt.Errorf("ProcessStdOut method not found\n")
				}
			} else {
				return fmt.Errorf("An error occurred connecting up to Stderr: %s\n", values[1].Interface())
			}
		}
	}

	// Run the command for the session
	if vstart := vsession.MethodByName("Start"); vstart.IsValid() {
		switch v := obj.(type) {
		case *Command:
			vstart.Call(nil)
		case *SSHCommand:
			vstart.Call([]reflect.Value{reflect.ValueOf(cmd)})
		default:
			return fmt.Errorf("Not a valid type, expected *Command or *SSHCommand but recevied %s", v)
		}
	}

	//Append stdin error if available
	if !vstdin.IsNil() {
		ioerrs = append(ioerrs, processErrors(innotifier)...)
	}

	//Append stdout errors if available
	if !vstdout.IsNil() {
		ioerrs = append(ioerrs, processErrors(outnotifier)...)
	}

	//Append stderr errors if available
	if !vstderr.IsNil() {
		ioerrs = append(ioerrs, processErrors(errnotifier)...)
	}

	//Iterate the errors and return them
	if ioerrs != nil && len(ioerrs) > 0 {
		errstr := "Errors found processing IO streams: \n"
		for i := 0; i < len(ioerrs); i++ {
			errstr = errstr + ioerrs[i]
		}
		return errors.New(errstr)
	}

	return nil
}

func processInput(in chan string, notifier chan error, w io.WriteCloser) {
	defer close(notifier)
	// defer close(in)

	for {
		if in, ok := <-in; ok {
			input := strings.NewReader(in)
			if _, err := io.Copy(w, input); err != nil {
				notifier <-err
			}
		} else {
			return
		}
	}
}

func processOutput(out chan string, notifier chan error, r io.Reader) {
	defer close(notifier)
	defer close(out)

	bufr := bufio.NewReader(r)
	var str string
	var err error
	for {
		str, err = bufr.ReadString('\n')
		if len(str) > 1 {
			out <-str
		}
		if err != nil {
			break
		}
	}
	if err != io.EOF {
		notifier <-err
	}
}

func processErrors(notifier chan error) []string {
	var errlist []string
	for {
		err, ok := <-notifier
		if !ok {
			return errlist
		}
		errlist = append(errlist, err.Error())
	}
}

func loadPEM(filename string) (ssh.Signer, error) {
	privateKey, _ := ioutil.ReadFile(filename)
	signer, err := ssh.ParsePrivateKey(privateKey)
	if err != nil {
		return nil, err
	}
	return signer, nil
}

type keyboardInteractive map[string]string

func (k *keyboardInteractive) Challenge(user, instruction string, questions []string, echos []bool) ([]string, error) {
	var answers []string
	for _, q := range questions {
		answers = append(answers, (*k)[q])
	}
	return answers, nil
}
<commit_msg>Fixed a bug in the input channel where it was not being assigned correctly<commit_after>package cmdr

import (
	"code.google.com/p/go.crypto/ssh"
	"io"
	"io/ioutil"
	"bufio"
	"os/exec"
	"fmt"
	"reflect"
	"errors"
	"strings"
)

func NewClientConfig(username, password, pemfile string) (*ssh.ClientConfig, error) {
	if username != "" && password != "" {
		answers := keyboardInteractive(map[string]string{"Password: ": password,})
		return &ssh.ClientConfig{
			User: username,
			Auth: []ssh.AuthMethod{
				ssh.KeyboardInteractive(answers.Challenge),
			},
		}, nil
	}

	if username != "" && pemfile != "" {
		signer, err := loadPEM(pemfile)
		if err != nil {
			return nil, err
		}

		return &ssh.ClientConfig{
			User: username,
			Auth: []ssh.AuthMethod{
				ssh.PublicKeys(signer),
			},
		}, nil
	}

	return nil, fmt.Errorf("Missing valid arguments, must pass a (username and password) or (username and pemfile).")
}

type Command struct {
	Session *exec.Cmd
	Stdin	chan string
	Stdout	chan string
	Stderr	chan string
}

type SSHCommand struct {
	Command
	Config *ssh.ClientConfig
	Server string
	Session *ssh.Session
	client *ssh.Client
}

func NewCommand(inchan, outchan, errchan chan string) (*Command, error) {
	return &Command{Stdin: inchan, Stdout: outchan, Stderr: errchan}, nil
}

func NewSSHCommand(cfg *ssh.ClientConfig, server string, inchan, outchan, errchan chan string) (*SSHCommand, error) {
	return &SSHCommand{Config: cfg, Server: server, Command: Command{Stdin: inchan, Stdout: outchan, Stderr: errchan}}, nil
}

func (c *Command) Execute(cmd string, args ...string) error {
	c.Session = exec.Command(cmd, args...)

	if err := execute(c, ""); err != nil {
		fmt.Printf("Execute Error: %s\n", err)
		return err
	}
	return nil
}

func (s *SSHCommand) Execute(cmd string) (err error) {
	s.client, err = ssh.Dial("tcp", s.Server, s.Config)
	if err != nil {
		return err
	}
	s.Session, err = s.client.NewSession()
	if err != nil {
		return err
	}

	if err = execute(s, cmd); err != nil {
		return err
	}
	return nil
}

func (c *Command) ProcessStdIn(notifier chan error, w io.WriteCloser) {
	processInput(c.Stdin, notifier, w)
}

func (c *Command) ProcessStdOut(notifier chan error, r io.Reader)  {
	processOutput(c.Stdout, notifier, r)
}

func (c *Command) ProcessStdErr(notifier chan error, r io.Reader)  {
	processOutput(c.Stderr, notifier, r)
}

func (c *SSHCommand) ProcessStdIn(notifier chan error, w io.WriteCloser) {
	processInput(c.Stdin, notifier, w)
}

func (s *SSHCommand) ProcessStdOut(notifier chan error, r io.Reader)  {
	processOutput(s.Stdout, notifier, r)
}

func (s *SSHCommand) ProcessStdErr(notifier chan error, r io.Reader)  {
	processOutput(s.Stderr, notifier, r)
}

func (s *SSHCommand) Close() {
	s.Session.Close()
	s.client.Close()
}

func execute(obj interface{}, cmd string) error {
	var innotifier chan error
	var outnotifier chan error
	var errnotifier chan error
	var ioerrs []string

	value := reflect.ValueOf(obj)
	vsession := value.Elem().FieldByName("Session")
	vstdin := value.Elem().FieldByName("Stdin")
	vstdout := value.Elem().FieldByName("Stdout")
	vstderr := value.Elem().FieldByName("Stderr")

	// Checking if a channel has been passed in to handle Stdout
	if !vstdin.IsNil() {
		innotifier = make(chan error)
		if method := vsession.MethodByName("StdinPipe"); method.IsValid() {
			values := method.Call(nil)
			if values[1].IsNil() {
				pipe := values[0].Interface()
				if processMethod := value.MethodByName("ProcessStdIn"); processMethod.IsValid() {
					go processMethod.Call([]reflect.Value{reflect.ValueOf(innotifier), reflect.ValueOf(pipe)})
				} else {
					return fmt.Errorf("ProcessStdIn method not found\n")
				}
			} else {
				return fmt.Errorf("An error occurred connecting up to Stdin: %s\n", values[1].Interface())
			}
		}
	}

	if !vstdout.IsNil() {
		outnotifier = make(chan error)
		if method := vsession.MethodByName("StdoutPipe"); method.IsValid() {
			values := method.Call(nil)
			if values[1].IsNil() {
				pipe := values[0].Interface()
				if processMethod := value.MethodByName("ProcessStdOut"); processMethod.IsValid() {
					go processMethod.Call([]reflect.Value{reflect.ValueOf(outnotifier), reflect.ValueOf(pipe)})
				} else {
					return fmt.Errorf("ProcessStdOut method not found\n")
				}
			} else {
				return fmt.Errorf("An error occurred connecting up to Stdout: %s\n", values[1].Interface())
			}
		}
	}
	if !vstderr.IsNil() {
		errnotifier = make(chan error)
		if method := vsession.MethodByName("StderrPipe"); method.IsValid() {
			values := method.Call(nil)
			if values[1].IsNil() {
				pipe := values[0].Interface()
				if processMethod := value.MethodByName("ProcessStdErr"); processMethod.IsValid() {
					go processMethod.Call([]reflect.Value{reflect.ValueOf(errnotifier), reflect.ValueOf(pipe)})
				} else {
					return fmt.Errorf("ProcessStdOut method not found\n")
				}
			} else {
				return fmt.Errorf("An error occurred connecting up to Stderr: %s\n", values[1].Interface())
			}
		}
	}

	// Run the command for the session
	if vstart := vsession.MethodByName("Start"); vstart.IsValid() {
		switch v := obj.(type) {
		case *Command:
			vstart.Call(nil)
		case *SSHCommand:
			vstart.Call([]reflect.Value{reflect.ValueOf(cmd)})
		default:
			return fmt.Errorf("Not a valid type, expected *Command or *SSHCommand but recevied %s", v)
		}
	}

	//Append stdin error if available
	if !vstdin.IsNil() {
		ioerrs = append(ioerrs, processErrors(innotifier)...)
	}

	//Append stdout errors if available
	if !vstdout.IsNil() {
		ioerrs = append(ioerrs, processErrors(outnotifier)...)
	}

	//Append stderr errors if available
	if !vstderr.IsNil() {
		ioerrs = append(ioerrs, processErrors(errnotifier)...)
	}

	//Iterate the errors and return them
	if ioerrs != nil && len(ioerrs) > 0 {
		errstr := "Errors found processing IO streams: \n"
		for i := 0; i < len(ioerrs); i++ {
			errstr = errstr + ioerrs[i]
		}
		return errors.New(errstr)
	}

	return nil
}

func processInput(in chan string, notifier chan error, w io.WriteCloser) {
	defer close(notifier)

	for {
		if in, ok := <-in; ok {
			input := strings.NewReader(in)
			if _, err := io.Copy(w, input); err != nil {
				notifier <-err
			}
		} else {
			return
		}
	}
}

func processOutput(out chan string, notifier chan error, r io.Reader) {
	defer close(notifier)
	defer close(out)

	bufr := bufio.NewReader(r)
	var str string
	var err error
	for {
		str, err = bufr.ReadString('\n')
		if len(str) > 1 {
			out <-str
		}
		if err != nil {
			break
		}
	}
	if err != io.EOF {
		notifier <-err
	}
}

func processErrors(notifier chan error) []string {
	var errlist []string
	for {
		err, ok := <-notifier
		if !ok {
			return errlist
		}
		errlist = append(errlist, err.Error())
	}
}

func loadPEM(filename string) (ssh.Signer, error) {
	privateKey, _ := ioutil.ReadFile(filename)
	signer, err := ssh.ParsePrivateKey(privateKey)
	if err != nil {
		return nil, err
	}
	return signer, nil
}

type keyboardInteractive map[string]string

func (k *keyboardInteractive) Challenge(user, instruction string, questions []string, echos []bool) ([]string, error) {
	var answers []string
	for _, q := range questions {
		answers = append(answers, (*k)[q])
	}
	return answers, nil
}
<|endoftext|>


<commit_before>package sa

import (
	"encoding/json"
	"fmt"
	"math"
	"net"
	"time"

	"github.com/letsencrypt/boulder/core"
	"github.com/letsencrypt/boulder/probs"
	jose "github.com/square/go-jose"
)

var mediumBlobSize = int(math.Pow(2, 24))

type issuedNameModel struct {
	ID           int64     `db:"id"`
	ReversedName string    `db:"reversedName"`
	NotBefore    time.Time `db:"notBefore"`
	Serial       string    `db:"serial"`
}

// regModel is the description of a core.Registration in the database.
type regModel struct {
	ID        int64    `db:"id"`
	Key       []byte   `db:"jwk"`
	KeySHA256 string   `db:"jwk_sha256"`
	Contact   []string `db:"contact"`
	Agreement string   `db:"agreement"`
	// InitialIP is stored as sixteen binary bytes, regardless of whether it
	// represents a v4 or v6 IP address.
	InitialIP []byte    `db:"initialIp"`
	CreatedAt time.Time `db:"createdAt"`
	Status    string    `db:"status"`
	LockCol   int64
}

// challModel is the description of a core.Challenge in the database
//
// The Validation field is a stub; the column is only there for backward compatibility.
type challModel struct {
	ID              int64  `db:"id"`
	AuthorizationID string `db:"authorizationID"`

	Type   string          `db:"type"`
	Status core.AcmeStatus `db:"status"`
	Error  []byte          `db:"error"`
	// This field is unused, but is kept temporarily to avoid a database migration.
	// TODO(#1818): remove
	Validated        *time.Time `db:"validated"`
	Token            string     `db:"token"`
	KeyAuthorization string     `db:"keyAuthorization"`
	ValidationRecord []byte     `db:"validationRecord"`

	LockCol int64

	// obsoleteTLS is obsoleted. Only used for simpleHTTP and simpleHTTP is
	// dead. Only still here because gorp complains if its gone and locks up if
	// its private.
	ObsoleteTLS *bool `db:"tls"`
}

// getChallengesQuery fetches exactly the fields in challModel from the
// challenges table.
const getChallengesQuery = `
	SELECT id, authorizationID, type, status, error, validated, token,
		keyAuthorization, validationRecord, tls
	FROM challenges WHERE authorizationID = :authID ORDER BY id ASC`

// newReg creates a reg model object from a core.Registration
func registrationToModel(r *core.Registration) (*regModel, error) {
	key, err := json.Marshal(r.Key)
	if err != nil {
		return nil, err
	}

	sha, err := core.KeyDigest(r.Key)
	if err != nil {
		return nil, err
	}
	if r.InitialIP == nil {
		return nil, fmt.Errorf("initialIP was nil")
	}
	if r.Contact == nil {
		r.Contact = &[]string{}
	}
	rm := &regModel{
		ID:        r.ID,
		Key:       key,
		KeySHA256: sha,
		Contact:   *r.Contact,
		Agreement: r.Agreement,
		InitialIP: []byte(r.InitialIP.To16()),
		CreatedAt: r.CreatedAt,
		Status:    string(r.Status),
	}
	return rm, nil
}

func modelToRegistration(rm *regModel) (core.Registration, error) {
	k := &jose.JsonWebKey{}
	err := json.Unmarshal(rm.Key, k)
	if err != nil {
		err = fmt.Errorf("unable to unmarshal JsonWebKey in db: %s", err)
		return core.Registration{}, err
	}
	var contact *[]string
	// Contact can be nil when the DB contains the literal string "null". We
	// prefer to represent this in memory as a pointer to an empty slice rather
	// than a nil pointer.
	if rm.Contact == nil {
		contact = &[]string{}
	} else {
		contact = &rm.Contact
	}
	r := core.Registration{
		ID:        rm.ID,
		Key:       *k,
		Contact:   contact,
		Agreement: rm.Agreement,
		InitialIP: net.IP(rm.InitialIP),
		CreatedAt: rm.CreatedAt,
		Status:    core.AcmeStatus(rm.Status),
	}
	return r, nil
}

func challengeToModel(c *core.Challenge, authID string) (*challModel, error) {
	cm := challModel{
		ID:               c.ID,
		AuthorizationID:  authID,
		Type:             c.Type,
		Status:           c.Status,
		Token:            c.Token,
		KeyAuthorization: c.ProvidedKeyAuthorization,
	}
	if c.Error != nil {
		errJSON, err := json.Marshal(c.Error)
		if err != nil {
			return nil, err
		}
		if len(errJSON) > mediumBlobSize {
			return nil, fmt.Errorf("Error object is too large to store in the database")
		}
		cm.Error = errJSON
	}
	if len(c.ValidationRecord) > 0 {
		vrJSON, err := json.Marshal(c.ValidationRecord)
		if err != nil {
			return nil, err
		}
		if len(vrJSON) > mediumBlobSize {
			return nil, fmt.Errorf("Validation Record object is too large to store in the database")
		}
		cm.ValidationRecord = vrJSON
	}
	return &cm, nil
}

func modelToChallenge(cm *challModel) (core.Challenge, error) {
	c := core.Challenge{
		ID:     cm.ID,
		Type:   cm.Type,
		Status: cm.Status,
		Token:  cm.Token,
		ProvidedKeyAuthorization: cm.KeyAuthorization,
	}
	if len(cm.Error) > 0 {
		var problem probs.ProblemDetails
		err := json.Unmarshal(cm.Error, &problem)
		if err != nil {
			return core.Challenge{}, err
		}
		c.Error = &problem
	}
	if len(cm.ValidationRecord) > 0 {
		var vr []core.ValidationRecord
		err := json.Unmarshal(cm.ValidationRecord, &vr)
		if err != nil {
			return core.Challenge{}, err
		}
		c.ValidationRecord = vr
	}
	return c, nil
}
<commit_msg>Remove obsolete TLS field from challenge model. (#2166)<commit_after>package sa

import (
	"encoding/json"
	"fmt"
	"math"
	"net"
	"time"

	"github.com/letsencrypt/boulder/core"
	"github.com/letsencrypt/boulder/probs"
	jose "github.com/square/go-jose"
)

var mediumBlobSize = int(math.Pow(2, 24))

type issuedNameModel struct {
	ID           int64     `db:"id"`
	ReversedName string    `db:"reversedName"`
	NotBefore    time.Time `db:"notBefore"`
	Serial       string    `db:"serial"`
}

// regModel is the description of a core.Registration in the database.
type regModel struct {
	ID        int64    `db:"id"`
	Key       []byte   `db:"jwk"`
	KeySHA256 string   `db:"jwk_sha256"`
	Contact   []string `db:"contact"`
	Agreement string   `db:"agreement"`
	// InitialIP is stored as sixteen binary bytes, regardless of whether it
	// represents a v4 or v6 IP address.
	InitialIP []byte    `db:"initialIp"`
	CreatedAt time.Time `db:"createdAt"`
	Status    string    `db:"status"`
	LockCol   int64
}

// challModel is the description of a core.Challenge in the database
//
// The Validation field is a stub; the column is only there for backward compatibility.
type challModel struct {
	ID              int64  `db:"id"`
	AuthorizationID string `db:"authorizationID"`

	Type   string          `db:"type"`
	Status core.AcmeStatus `db:"status"`
	Error  []byte          `db:"error"`
	// This field is unused, but is kept temporarily to avoid a database migration.
	// TODO(#1818): remove
	Validated        *time.Time `db:"validated"`
	Token            string     `db:"token"`
	KeyAuthorization string     `db:"keyAuthorization"`
	ValidationRecord []byte     `db:"validationRecord"`

	LockCol int64
}

// getChallengesQuery fetches exactly the fields in challModel from the
// challenges table.
const getChallengesQuery = `
	SELECT id, authorizationID, type, status, error, validated, token,
		keyAuthorization, validationRecord
	FROM challenges WHERE authorizationID = :authID ORDER BY id ASC`

// newReg creates a reg model object from a core.Registration
func registrationToModel(r *core.Registration) (*regModel, error) {
	key, err := json.Marshal(r.Key)
	if err != nil {
		return nil, err
	}

	sha, err := core.KeyDigest(r.Key)
	if err != nil {
		return nil, err
	}
	if r.InitialIP == nil {
		return nil, fmt.Errorf("initialIP was nil")
	}
	if r.Contact == nil {
		r.Contact = &[]string{}
	}
	rm := &regModel{
		ID:        r.ID,
		Key:       key,
		KeySHA256: sha,
		Contact:   *r.Contact,
		Agreement: r.Agreement,
		InitialIP: []byte(r.InitialIP.To16()),
		CreatedAt: r.CreatedAt,
		Status:    string(r.Status),
	}
	return rm, nil
}

func modelToRegistration(rm *regModel) (core.Registration, error) {
	k := &jose.JsonWebKey{}
	err := json.Unmarshal(rm.Key, k)
	if err != nil {
		err = fmt.Errorf("unable to unmarshal JsonWebKey in db: %s", err)
		return core.Registration{}, err
	}
	var contact *[]string
	// Contact can be nil when the DB contains the literal string "null". We
	// prefer to represent this in memory as a pointer to an empty slice rather
	// than a nil pointer.
	if rm.Contact == nil {
		contact = &[]string{}
	} else {
		contact = &rm.Contact
	}
	r := core.Registration{
		ID:        rm.ID,
		Key:       *k,
		Contact:   contact,
		Agreement: rm.Agreement,
		InitialIP: net.IP(rm.InitialIP),
		CreatedAt: rm.CreatedAt,
		Status:    core.AcmeStatus(rm.Status),
	}
	return r, nil
}

func challengeToModel(c *core.Challenge, authID string) (*challModel, error) {
	cm := challModel{
		ID:               c.ID,
		AuthorizationID:  authID,
		Type:             c.Type,
		Status:           c.Status,
		Token:            c.Token,
		KeyAuthorization: c.ProvidedKeyAuthorization,
	}
	if c.Error != nil {
		errJSON, err := json.Marshal(c.Error)
		if err != nil {
			return nil, err
		}
		if len(errJSON) > mediumBlobSize {
			return nil, fmt.Errorf("Error object is too large to store in the database")
		}
		cm.Error = errJSON
	}
	if len(c.ValidationRecord) > 0 {
		vrJSON, err := json.Marshal(c.ValidationRecord)
		if err != nil {
			return nil, err
		}
		if len(vrJSON) > mediumBlobSize {
			return nil, fmt.Errorf("Validation Record object is too large to store in the database")
		}
		cm.ValidationRecord = vrJSON
	}
	return &cm, nil
}

func modelToChallenge(cm *challModel) (core.Challenge, error) {
	c := core.Challenge{
		ID:     cm.ID,
		Type:   cm.Type,
		Status: cm.Status,
		Token:  cm.Token,
		ProvidedKeyAuthorization: cm.KeyAuthorization,
	}
	if len(cm.Error) > 0 {
		var problem probs.ProblemDetails
		err := json.Unmarshal(cm.Error, &problem)
		if err != nil {
			return core.Challenge{}, err
		}
		c.Error = &problem
	}
	if len(cm.ValidationRecord) > 0 {
		var vr []core.ValidationRecord
		err := json.Unmarshal(cm.ValidationRecord, &vr)
		if err != nil {
			return core.Challenge{}, err
		}
		c.ValidationRecord = vr
	}
	return c, nil
}
<|endoftext|>


<commit_before>package rpmpack

import (
	"io/ioutil"
	"testing"
)

func TestFileOwner(t *testing.T) {
	r, err := NewRPM(RPMMetaData{})
	if err != nil {
		t.Errorf("NewRpm returned error %v", err)
		t.FailNow()
	}
	group := "testGroup"
	user := "testUser"

	r.AddFile(RPMFile{
		Name:  "/usr/local/hello",
		Body:  []byte("content of the file"),
		Group: group,
		Owner: user,
	})

	if err := r.Write(ioutil.Discard); err != nil {
		t.Errorf("NewRpm returned error %v", err)
	}
	if r.fileowners[0] != user {
		t.Errorf("File owner shoud be %s but is %s", user, r.fileowners[0])
	}
	if r.filegroups[0] != group {
		t.Errorf("File owner shoud be %s but is %s", group, r.filegroups[0])
	}
}
// https://github.com/google/rpmpack/issues/49
func Test100644(t *testing.T) {
	r, err := NewRPM(RPMMetaData{})
	if err != nil {
		t.Errorf("NewRpm returned error %v", err)
		t.FailNow()
	}
	r.AddFile(RPMFile{
		Name:  "/usr/local/hello",
		Body:  []byte("content of the file"),
		Mode: 0o0100644,
	})

	if err := r.Write(ioutil.Discard); err != nil {
		t.Errorf("Write returned error %v", err)
	}
	if r.filemodes[0] != 0100644 {
		t.Errorf("file mode want 0100644, got %o", r.filemodes[0])
	}
	if r.filelinktos[0] != "" {
		t.Errorf("linktos want empty (not a symlink), got %q", r.filelinktos[0])
	}

}
<commit_msg>Minor formatting changes in rpm_test.go<commit_after>package rpmpack

import (
	"io/ioutil"
	"testing"
)

func TestFileOwner(t *testing.T) {
	r, err := NewRPM(RPMMetaData{})
	if err != nil {
		t.Fatalf("NewRPM returned error %v", err)
	}
	group := "testGroup"
	user := "testUser"

	r.AddFile(RPMFile{
		Name:  "/usr/local/hello",
		Body:  []byte("content of the file"),
		Group: group,
		Owner: user,
	})

	if err := r.Write(ioutil.Discard); err != nil {
		t.Errorf("NewRPM returned error %v", err)
	}
	if r.fileowners[0] != user {
		t.Errorf("File owner shoud be %s but is %s", user, r.fileowners[0])
	}
	if r.filegroups[0] != group {
		t.Errorf("File owner shoud be %s but is %s", group, r.filegroups[0])
	}
}

// https://github.com/google/rpmpack/issues/49
func Test100644(t *testing.T) {
	r, err := NewRPM(RPMMetaData{})
	if err != nil {
		t.Errorf("NewRPM returned error %v", err)
		t.FailNow()
	}
	r.AddFile(RPMFile{
		Name: "/usr/local/hello",
		Body: []byte("content of the file"),
		Mode: 0100644,
	})

	if err := r.Write(ioutil.Discard); err != nil {
		t.Errorf("Write returned error %v", err)
	}
	if r.filemodes[0] != 0100644 {
		t.Errorf("file mode want 0100644, got %o", r.filemodes[0])
	}
	if r.filelinktos[0] != "" {
		t.Errorf("linktos want empty (not a symlink), got %q", r.filelinktos[0])
	}

}
<|endoftext|>


<commit_before>package dig

import (
	"bytes"
	"fmt"
)

// String representation of the entire Container
func (c Container) String() string {
	b := &bytes.Buffer{}
	fmt.Fprintln(b, "nodes: {")
	for k, v := range c.nodes {
		fmt.Fprintln(b, "\t", k, "->", v)
	}
	fmt.Fprintln(b, "}")

	fmt.Fprintln(b, "cache: {")
	for k, v := range c.cache {
		fmt.Fprintln(b, "\t", k, "=>", v)
	}
	fmt.Fprintln(b, "}")

	return b.String()
}

func (n node) String() string {
	return fmt.Sprintf(
		"deps: %v, constructor: %v", n.deps, n.ctype,
	)
}
<commit_msg>String(): Fix broken tests (#95)<commit_after>package dig

import (
	"bytes"
	"fmt"
)

// String representation of the entire Container
func (c Container) String() string {
	b := &bytes.Buffer{}
	fmt.Fprintln(b, "nodes: {")
	for k, v := range c.nodes {
		fmt.Fprintln(b, "\t", k, "->", v)
	}
	fmt.Fprintln(b, "}")

	fmt.Fprintln(b, "cache: {")
	for k, v := range c.cache {
		fmt.Fprintln(b, "\t", k, "=>", v)
	}
	fmt.Fprintln(b, "}")

	return b.String()
}

func (n node) String() string {
	deps := make([]string, len(n.deps))
	for i, d := range n.deps {
		deps[i] = fmt.Sprint(d.Type)
	}
	return fmt.Sprintf(
		"deps: %v, constructor: %v", deps, n.ctype,
	)
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/kelseyhightower/envconfig"
	"log"
	"net/http"
	"time"
)

type Config struct {
	VendorsURL      string `default:"file:///switchq/vendors.json" envconfig:"vendors_url"`
	StorageURL      string `default:"memory:" envconfig:"storage_url"`
	AddressURL      string `default:"file:///switchq/dhcp_harvest.inc" envconfig:"address_url"`
	PollInterval    string `default:"1m" envconfig:"poll_interval"`
	ProvisionTTL    string `default:"1h" envconfig:"provision_ttl"`
	ProvisionURL    string `default:"" envconfig:"provision_url"`
	RoleSelectorURL string `default:"" envconfig:"role_selector_url"`
	DefaultRole     string `default:"fabric-switch" envconfig:"default_role"`
	Script          string `default:"do-ansible"`

	vendors       Vendors
	storage       Storage
	addressSource AddressSource
	interval      time.Duration
	ttl           time.Duration
}

func checkError(err error, msg string, args ...interface{}) {
	if err != nil {
		log.Fatalf(msg, args...)
	}
}

func (c *Config) provision(rec AddressRec) error {
	log.Printf("[debug] Verifing that device '%s (%s)' isn't already in a provisioning state",
		rec.Name, rec.MAC)
	resp, err := http.Get(c.ProvisionURL + rec.MAC)
	log.Printf("%s%s", c.ProvisionURL, rec.MAC)
	if err != nil {
		log.Printf("[error] Error while retrieving provisioning state for device '%s (%s)' : %s",
			rec.Name, rec.MAC, err)
		return err
	}
	if resp.StatusCode != 404 && int(resp.StatusCode/100) != 2 {
		log.Printf("[error] Error while retrieving provisioning state for device '%s (%s)' : %s",
			rec.Name, rec.MAC, resp.Status)
		return fmt.Errorf(resp.Status)
	}
	defer resp.Body.Close()
	if resp.StatusCode != 404 {
		decoder := json.NewDecoder(resp.Body)
		var raw interface{}
		err = decoder.Decode(&raw)
		if err != nil {
			log.Printf("[error] Unable to unmarshal status response from provisioning service for device '%s (%s)' : %s",
				rec.Name, rec.MAC, err)
			return err
		}
		status := raw.(map[string]interface{})
		switch int(status["status"].(float64)) {
		case 0, 1: // "PENDING", "RUNNING"
			log.Printf("[info] Device '%s (%s)' is already scheduled to be provisioned",
				rec.Name, rec.MAC)
			return nil
		case 2: // "COMPLETE"
			// noop
		case 3: // "FAILED"
			c.storage.ClearProvisioned(rec.MAC)
		default:
			err = fmt.Errorf("unknown provisioning status : %d", status["status"])
			log.Printf("[error] received unknown provisioning status for device '%s (%s)' : %s",
				rec.Name, rec.MAC, err)
			return err
		}
	}
	log.Printf("[info] POSTing to '%s' for provisioning of '%s (%s)'", c.ProvisionURL, rec.Name, rec.MAC)
	data := map[string]string{
		"id":   rec.MAC,
		"name": rec.Name,
		"ip":   rec.IP,
		"mac":  rec.MAC,
	}
	if c.RoleSelectorURL != "" {
		data["role_selector"] = c.RoleSelectorURL
	}
	if c.DefaultRole != "" {
		data["role"] = c.DefaultRole
	}
	if c.Script != "" {
		data["script"] = c.Script
	}

	hc := http.Client{}
	var b []byte
	b, err = json.Marshal(data)
	if err != nil {
		log.Printf("[error] Unable to marshal provisioning data : %s", err)
		return err
	}
	req, err := http.NewRequest("POST", c.ProvisionURL, bytes.NewReader(b))
	if err != nil {
		log.Printf("[error] Unable to construct POST request to provisioner : %s", err)
		return err
	}

	req.Header.Add("Content-Type", "application/json")
	resp, err = hc.Do(req)
	if err != nil {
		log.Printf("[error] Unable to POST request to provisioner : %s", err)
		return err
	}

	defer resp.Body.Close()
	if resp.StatusCode != http.StatusAccepted {
		log.Printf("[error] Provisioning request not accepted by provisioner : %s", resp.Status)
		return err
	}

	now := time.Now()
	c.storage.MarkProvisioned(rec.MAC, &now)
	return nil
}

func (c *Config) processRecord(rec AddressRec) error {
	ok, err := c.vendors.Switchq(rec.MAC)
	if err != nil {
		return fmt.Errorf("unable to determine ventor of MAC '%s' (%s)", rec.MAC, err)
	}

	if !ok {
		// Not something we care about
		log.Printf("[debug] host with IP '%s' and MAC '%s' and named '%s' not a known switch type",
			rec.IP, rec.MAC, rec.Name)
		return nil
	}

	last, err := c.storage.LastProvisioned(rec.MAC)
	if err != nil {
		return err
	}

	// If TTL is 0 then we will only provision a switch once.
	if last == nil || (c.ttl > 0 && time.Since(*last) > c.ttl) {
		c.provision(rec)
	} else if c.ttl == 0 {
		log.Printf("[debug] device '%s' (%s, %s) has completed its one time provisioning, with a TTL set to %s",
			rec.Name, rec.IP, rec.MAC, c.ProvisionTTL)
	} else {
		log.Printf("[debug] device '%s' (%s, %s) has completed provisioning within the specified TTL of %s",
			rec.Name, rec.IP, rec.MAC, c.ProvisionTTL)
	}
	return nil
}

func main() {

	var err error
	config := Config{}
	envconfig.Process("SWITCHQ", &config)

	config.vendors, err = NewVendors(config.VendorsURL)
	checkError(err, "Unable to create known vendors list from specified URL '%s' : %s", config.VendorsURL, err)

	config.storage, err = NewStorage(config.StorageURL)
	checkError(err, "Unable to create require storage for specified URL '%s' : %s", config.StorageURL, err)

	config.addressSource, err = NewAddressSource(config.AddressURL)
	checkError(err, "Unable to create required address source for specified URL '%s' : %s", config.AddressURL, err)

	config.interval, err = time.ParseDuration(config.PollInterval)
	checkError(err, "Unable to parse specified poll interface '%s' : %s", config.PollInterval, err)

	config.ttl, err = time.ParseDuration(config.ProvisionTTL)
	checkError(err, "Unable to parse specified provision TTL value of '%s' : %s", config.ProvisionTTL, err)

	log.Printf(`Configuration:
		Vendors URL:       %s
		Storage URL:       %s
		Poll Interval:     %s
		Address Source:    %s
		Provision TTL:     %s
		Provision URL:     %s
		Role Selector URL: %s
		Default Role:      %s
		Script:            %s`,
		config.VendorsURL, config.StorageURL, config.PollInterval, config.AddressURL, config.ProvisionTTL,
		config.ProvisionURL, config.RoleSelectorURL, config.DefaultRole, config.Script)

	// We use two methods to attempt to find the MAC (hardware) address associated with an IP. The first
	// is to look in the table. The second is to send an ARP packet.
	for {
		log.Printf("[info] Checking for switches @ %s", time.Now())
		addresses, err := config.addressSource.GetAddresses()

		if err != nil {
			log.Printf("[error] unable to read addresses from address source : %s", err)
		} else {
			log.Printf("[info] Queried %d addresses from address source", len(addresses))

			for _, rec := range addresses {
				log.Printf("[debug] Processing %s(%s, %s)", rec.Name, rec.IP, rec.MAC)
				if err := config.processRecord(rec); err != nil {
					log.Printf("[error] Error when processing IP '%s' : %s", rec.IP, err)
				}
			}
		}

		time.Sleep(config.interval)
	}
}
<commit_msg>CORD-229 - updated switch provisioning to be more consistent with retries<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/kelseyhightower/envconfig"
	"log"
	"net/http"
	"time"
)

type Config struct {
	VendorsURL      string `default:"file:///switchq/vendors.json" envconfig:"vendors_url"`
	StorageURL      string `default:"memory:" envconfig:"storage_url"`
	AddressURL      string `default:"file:///switchq/dhcp_harvest.inc" envconfig:"address_url"`
	PollInterval    string `default:"1m" envconfig:"poll_interval"`
	ProvisionTTL    string `default:"1h" envconfig:"provision_ttl"`
	ProvisionURL    string `default:"" envconfig:"provision_url"`
	RoleSelectorURL string `default:"" envconfig:"role_selector_url"`
	DefaultRole     string `default:"fabric-switch" envconfig:"default_role"`
	Script          string `default:"do-ansible"`

	vendors       Vendors
	storage       Storage
	addressSource AddressSource
	interval      time.Duration
	ttl           time.Duration
}

func checkError(err error, msg string, args ...interface{}) {
	if err != nil {
		log.Fatalf(msg, args...)
	}
}

func (c *Config) getProvisionedState(rec AddressRec) (int, string, error) {
	log.Printf("[debug] Fetching provisioned state of device '%s' (%s, %s)",
		rec.Name, rec.IP, rec.MAC)
	resp, err := http.Get(c.ProvisionURL + rec.MAC)
	if err != nil {
		log.Printf("[error] Error while retrieving provisioning state for device '%s (%s, %s)' : %s",
			rec.Name, rec.IP, rec.MAC, err)
		return -1, "", err
	}
	if resp.StatusCode != 404 && int(resp.StatusCode/100) != 2 {
		log.Printf("[error] Error while retrieving provisioning state for device '%s (%s, %s)' : %s",
			rec.Name, rec.IP, rec.MAC, resp.Status)
		return -1, "", fmt.Errorf(resp.Status)
	}
	defer resp.Body.Close()
	if resp.StatusCode != 404 {
		decoder := json.NewDecoder(resp.Body)
		var raw interface{}
		err = decoder.Decode(&raw)
		if err != nil {
			log.Printf("[error] Unmarshal provisioning service response for device '%s (%s, %s)' : %s",
				rec.Name, rec.IP, rec.MAC, err)
			return -1, "", err
		}
		status := raw.(map[string]interface{})
		switch int(status["status"].(float64)) {
		case 0, 1: // "PENDING", "RUNNING"
			return int(status["status"].(float64)), "", nil
		case 2: // "COMPLETE"
			return 2, "", nil
		case 3: // "FAILED"
			return 3, status["message"].(string), nil
		default:
			err = fmt.Errorf("unknown provisioning status : %d", status["status"])
			log.Printf("[error] received unknown provisioning status for device '%s (%s)' : %s",
				rec.Name, rec.MAC, err)
			return -1, "", err
		}
	}

	// If we end up here that means that no record was found in the provisioning, so return
	// a status of -1, w/o an error
	return -1, "", nil
}

func (c *Config) provision(rec AddressRec) error {
	log.Printf("[info] POSTing to '%s' for provisioning of '%s (%s)'", c.ProvisionURL, rec.Name, rec.MAC)
	data := map[string]string{
		"id":   rec.MAC,
		"name": rec.Name,
		"ip":   rec.IP,
		"mac":  rec.MAC,
	}
	if c.RoleSelectorURL != "" {
		data["role_selector"] = c.RoleSelectorURL
	}
	if c.DefaultRole != "" {
		data["role"] = c.DefaultRole
	}
	if c.Script != "" {
		data["script"] = c.Script
	}

	hc := http.Client{}
	var b []byte
	b, err := json.Marshal(data)
	if err != nil {
		log.Printf("[error] Unable to marshal provisioning data : %s", err)
		return err
	}
	req, err := http.NewRequest("POST", c.ProvisionURL, bytes.NewReader(b))
	if err != nil {
		log.Printf("[error] Unable to construct POST request to provisioner : %s", err)
		return err
	}

	req.Header.Add("Content-Type", "application/json")
	resp, err := hc.Do(req)
	if err != nil {
		log.Printf("[error] Unable to POST request to provisioner : %s", err)
		return err
	}

	defer resp.Body.Close()
	if resp.StatusCode != http.StatusAccepted {
		log.Printf("[error] Provisioning request not accepted by provisioner : %s", resp.Status)
		return err
	}

	return nil
}

func (c *Config) processRecord(rec AddressRec) error {
	ok, err := c.vendors.Switchq(rec.MAC)
	if err != nil {
		return fmt.Errorf("unable to determine ventor of MAC '%s' (%s)", rec.MAC, err)
	}

	if !ok {
		// Not something we care about
		log.Printf("[debug] host with IP '%s' and MAC '%s' and named '%s' not a known switch type",
			rec.IP, rec.MAC, rec.Name)
		return nil
	}

	last, err := c.storage.LastProvisioned(rec.MAC)
	if err != nil {
		return err
	}

	if last == nil {
		log.Printf("[debug] no TTL for device '%s' (%s, %s)",
			rec.Name, rec.IP, rec.MAC)
	} else {
		log.Printf("[debug] TTL for device '%s' (%s, %s) is %v",
			rec.Name, rec.IP, rec.MAC, *last)
	}

	// Verify if the provision status of the node is complete, if in an error state then TTL means
	// nothing
	state, message, err := c.getProvisionedState(rec)
	switch state {
	case 0, 1: // Pending or Running
		log.Printf("[debug] device '%s' (%s, %s) is being provisioned",
			rec.Name, rec.IP, rec.MAC)
		return nil
	case 2: // Complete
		log.Printf("[debug] device '%s' (%s, %s) has completed provisioning",
			rec.Name, rec.IP, rec.MAC)
		// If no last record then set the TTL
		if last == nil {
			now := time.Now()
			last = &now
			c.storage.MarkProvisioned(rec.MAC, last)
			log.Printf("[debug] Storing TTL for device '%s' (%s, %s) as %v",
				rec.Name, rec.IP, rec.MAC, now)
			return nil
		}
	case 3: // Failed
		log.Printf("[debug] device '%s' (%s, %s) failed last provisioning with message '%s', reattempt",
			rec.Name, rec.IP, rec.MAC, message)
		c.storage.ClearProvisioned(rec.MAC)
		last = nil
	default: // No record
	}

	// If TTL is 0 then we will only provision a switch once.
	if last == nil || (c.ttl > 0 && time.Since(*last) > c.ttl) {
		if last != nil {
			c.storage.ClearProvisioned(rec.MAC)
			log.Printf("[debug] device '%s' (%s, %s) TTL expired, reprovisioning",
				rec.Name, rec.IP, rec.MAC)
		}
		c.provision(rec)
	} else if c.ttl == 0 {
		log.Printf("[debug] device '%s' (%s, %s) has completed its one time provisioning, with a TTL set to %s",
			rec.Name, rec.IP, rec.MAC, c.ProvisionTTL)
	} else {
		log.Printf("[debug] device '%s' (%s, %s) has completed provisioning within the specified TTL of %s",
			rec.Name, rec.IP, rec.MAC, c.ProvisionTTL)
	}
	return nil
}

func main() {

	var err error
	config := Config{}
	envconfig.Process("SWITCHQ", &config)

	config.vendors, err = NewVendors(config.VendorsURL)
	checkError(err, "Unable to create known vendors list from specified URL '%s' : %s", config.VendorsURL, err)

	config.storage, err = NewStorage(config.StorageURL)
	checkError(err, "Unable to create require storage for specified URL '%s' : %s", config.StorageURL, err)

	config.addressSource, err = NewAddressSource(config.AddressURL)
	checkError(err, "Unable to create required address source for specified URL '%s' : %s", config.AddressURL, err)

	config.interval, err = time.ParseDuration(config.PollInterval)
	checkError(err, "Unable to parse specified poll interface '%s' : %s", config.PollInterval, err)

	config.ttl, err = time.ParseDuration(config.ProvisionTTL)
	checkError(err, "Unable to parse specified provision TTL value of '%s' : %s", config.ProvisionTTL, err)

	log.Printf(`Configuration:
		Vendors URL:       %s
		Storage URL:       %s
		Poll Interval:     %s
		Address Source:    %s
		Provision TTL:     %s
		Provision URL:     %s
		Role Selector URL: %s
		Default Role:      %s
		Script:            %s`,
		config.VendorsURL, config.StorageURL, config.PollInterval, config.AddressURL, config.ProvisionTTL,
		config.ProvisionURL, config.RoleSelectorURL, config.DefaultRole, config.Script)

	// We use two methods to attempt to find the MAC (hardware) address associated with an IP. The first
	// is to look in the table. The second is to send an ARP packet.
	for {
		log.Printf("[info] Checking for switches @ %s", time.Now())
		addresses, err := config.addressSource.GetAddresses()

		if err != nil {
			log.Printf("[error] unable to read addresses from address source : %s", err)
		} else {
			log.Printf("[info] Queried %d addresses from address source", len(addresses))

			for _, rec := range addresses {
				log.Printf("[debug] Processing %s(%s, %s)", rec.Name, rec.IP, rec.MAC)
				if err := config.processRecord(rec); err != nil {
					log.Printf("[error] Error when processing IP '%s' : %s", rec.IP, err)
				}
			}
		}

		time.Sleep(config.interval)
	}
}
<|endoftext|>


<commit_before>package nats

import (
	"testing"
	"time"
)

// More advanced tests on subscriptions

func TestServerAutoUnsub(t *testing.T) {
	nc := newConnection(t)
	defer nc.Close()
	received := 0
	max := 10
	sub, err := nc.Subscribe("foo", func(_ *Msg) {
		received += 1
	})
	if err != nil {
		t.Fatal("Failed to subscribe: ", err)
	}
	sub.AutoUnsubscribe(max)
	total := 100
	for i := 0; i < total; i++ {
		nc.Publish("foo", []byte("Hello"))
	}
	nc.Flush()
	if received != max {
		t.Fatalf("Received %d msgs, wanted only %d\n", received, max)
	}
}

func TestClientSyncAutoUnsub(t *testing.T) {
	nc := newConnection(t)
	defer nc.Close()
	received := 0
	max := 10
	sub, _ := nc.SubscribeSync("foo")
	total := 100
	for i := 0; i < total; i++ {
		nc.Publish("foo", []byte("Hello"))
	}
	sub.AutoUnsubscribe(max)
	nc.Flush()
	for {
		_, err := sub.NextMsg(1 * time.Millisecond)
		if err != nil {
			break
		}
		received += 1
	}
	if received != max {
		t.Fatalf("Received %d msgs, wanted only %d\n", received, max)
	}
}

func TestClientASyncAutoUnsub(t *testing.T) {
	nc := newConnection(t)
	defer nc.Close()
	received := 0
	max := 10
	sub, err := nc.Subscribe("foo", func(_ *Msg) {
		received += 1
	})
	if err != nil {
		t.Fatal("Failed to subscribe: ", err)
	}
	total := 100
	for i := 0; i < total; i++ {
		nc.Publish("foo", []byte("Hello"))
	}
	sub.AutoUnsubscribe(max)
	nc.Flush()
	if received != max {
		t.Fatalf("Received %d msgs, wanted only %d\n", received, max)
	}
}

func TestCloseSubRelease(t *testing.T) {
	nc := newConnection(t)
	sub, _ := nc.SubscribeSync("foo")
	start := time.Now()
	go func() {
		time.Sleep(5 * time.Millisecond)
		nc.Close()
	}()
	_, err := sub.NextMsg(50 * time.Millisecond)
	if err == nil {
		t.Fatalf("Expected an error from NextMsg")
	}
	elapsed := time.Since(start)
	if elapsed > 10*time.Millisecond {
		t.Fatalf("Too much time has elapsed to release NextMsg: %dms",
			(elapsed / time.Millisecond))
	}
}

func TestIsValidSubscriber(t *testing.T) {
	nc := newConnection(t)
	defer nc.Close()

	sub, err := nc.SubscribeSync("foo")
	if !sub.IsValid() {
		t.Fatalf("Subscription should be valid")
	}
	for i := 0; i < 10; i++ {
		nc.Publish("foo", []byte("Hello"))
	}
	_, err = sub.NextMsg(100 * time.Millisecond)
	if err != nil {
		t.Fatalf("NextMsg returned an error")
	}
	sub.Unsubscribe()
	_, err = sub.NextMsg(100 * time.Millisecond)
	if err == nil {
		t.Fatalf("NextMsg should have returned an error")
	}
}

func TestSlowSubscriber(t *testing.T) {
	nc := newConnection(t)
	defer nc.Close()

	sub, _ := nc.SubscribeSync("foo")
	for i := 0; i < (maxChanLen + 10); i++ {
		nc.Publish("foo", []byte("Hello"))
	}
	timeout := 500 * time.Millisecond
	start := time.Now()
	nc.FlushTimeout(timeout)
	elapsed := time.Since(start)
	if elapsed >= timeout {
		t.Fatalf("Flush did not return before timeout: %d > %d", elapsed, timeout)
	}
	// Make sure NextMsg returns an error to indicate slow consumer
	_, err := sub.NextMsg(100 * time.Millisecond)
	if err == nil {
		t.Fatalf("NextMsg did not return an error")
	}
}

func TestSlowAsyncSubscriber(t *testing.T) {
	nc := newConnection(t)
	defer nc.Close()

	nc.Subscribe("foo", func(_ *Msg) {
		time.Sleep(100 * time.Second)
	})
	for i := 0; i < (maxChanLen + 10); i++ {
		nc.Publish("foo", []byte("Hello"))
	}
	timeout := 500 * time.Millisecond
	start := time.Now()
	err := nc.FlushTimeout(timeout)
	elapsed := time.Since(start)
	if elapsed >= timeout {
		t.Fatalf("Flush did not return before timeout")
	}
	if err == nil {
		t.Fatal("Expected an error indicating slow consumer")
	}
}

func TestAsyncErrHandler(t *testing.T) {
	nc := newConnection(t)
	defer nc.Close()

	cbCalled := false
	subj := "async_test"

	sub, err := nc.Subscribe(subj, func(_ *Msg) {
		time.Sleep(100 * time.Second)
	})
	if err != nil {
		t.Fatalf("Could not subscribe: %v\n", err)
	}

	nc.Opts.AsyncErrorCB = func(c *Conn, s *Subscription, e error) {
		if s != sub {
			t.Fatal("Did not receive proper subscription")
		}
		if e != ErrSlowConsumer {
			t.Fatalf("Did not receive proper error: %v vs %v\n", e, ErrSlowConsumer)
		}
		cbCalled = true
	}

	b := []byte("Hello World!")
	for i := 0; i < (maxChanLen + 10); i++ {
		nc.Publish(subj, b)
	}
	nc.Flush()

	if !cbCalled {
		t.Fatal("Failed to call async err handler")
	}
}

// Test to make sure that we can send and async receive messages on
// different subjects within a callback.
func TestAsyncSubscriberStarvation(t *testing.T) {
	nc := newConnection(t)
	defer nc.Close()

	// Helper
	nc.Subscribe("helper", func(m *Msg) {
		nc.Publish(m.Reply, []byte("Hello"))
	})

	ch := make(chan bool)

	// Kickoff
	nc.Subscribe("start", func(m *Msg) {
		// Helper Response
		response := NewInbox()
		nc.Subscribe(response, func(_ *Msg) {
			ch <- true
		})
		nc.PublishRequest("helper", response, []byte("Help Me!"))
	})

	nc.Publish("start", []byte("Begin"))
	nc.Flush()

	if e := wait(ch); e != nil {
		t.Fatal("Was stalled inside of callback waiting on another callback")
	}
}

// FIXME: Hack, make this better
func TestStopServer(t *testing.T) {
	s.stopServer()
}
<commit_msg>Fix data races<commit_after>package nats

import (
	"testing"
	"time"
)

// More advanced tests on subscriptions

func TestServerAutoUnsub(t *testing.T) {
	nc := newConnection(t)
	defer nc.Close()
	received := 0
	max := 10
	sub, err := nc.Subscribe("foo", func(_ *Msg) {
		received += 1
	})
	if err != nil {
		t.Fatal("Failed to subscribe: ", err)
	}
	sub.AutoUnsubscribe(max)
	total := 100
	for i := 0; i < total; i++ {
		nc.Publish("foo", []byte("Hello"))
	}
	nc.Flush()
	if received != max {
		t.Fatalf("Received %d msgs, wanted only %d\n", received, max)
	}
}

func TestClientSyncAutoUnsub(t *testing.T) {
	nc := newConnection(t)
	defer nc.Close()
	received := 0
	max := 10
	sub, _ := nc.SubscribeSync("foo")
	total := 100
	for i := 0; i < total; i++ {
		nc.Publish("foo", []byte("Hello"))
	}
	sub.AutoUnsubscribe(max)
	nc.Flush()
	for {
		_, err := sub.NextMsg(1 * time.Millisecond)
		if err != nil {
			break
		}
		received += 1
	}
	if received != max {
		t.Fatalf("Received %d msgs, wanted only %d\n", received, max)
	}
}

func TestClientASyncAutoUnsub(t *testing.T) {
	nc := newConnection(t)
	defer nc.Close()
	received := 0
	max := 10
	sub, err := nc.Subscribe("foo", func(_ *Msg) {
		received += 1
	})
	if err != nil {
		t.Fatal("Failed to subscribe: ", err)
	}
	total := 100
	for i := 0; i < total; i++ {
		nc.Publish("foo", []byte("Hello"))
	}
	sub.AutoUnsubscribe(max)
	nc.Flush()
	if received != max {
		t.Fatalf("Received %d msgs, wanted only %d\n", received, max)
	}
}

func TestCloseSubRelease(t *testing.T) {
	nc := newConnection(t)
	sub, _ := nc.SubscribeSync("foo")
	start := time.Now()
	go func() {
		time.Sleep(5 * time.Millisecond)
		nc.Close()
	}()
	_, err := sub.NextMsg(50 * time.Millisecond)
	if err == nil {
		t.Fatalf("Expected an error from NextMsg")
	}
	elapsed := time.Since(start)
	if elapsed > 10*time.Millisecond {
		t.Fatalf("Too much time has elapsed to release NextMsg: %dms",
			(elapsed / time.Millisecond))
	}
}

func TestIsValidSubscriber(t *testing.T) {
	nc := newConnection(t)
	defer nc.Close()

	sub, err := nc.SubscribeSync("foo")
	if !sub.IsValid() {
		t.Fatalf("Subscription should be valid")
	}
	for i := 0; i < 10; i++ {
		nc.Publish("foo", []byte("Hello"))
	}
	_, err = sub.NextMsg(100 * time.Millisecond)
	if err != nil {
		t.Fatalf("NextMsg returned an error")
	}
	sub.Unsubscribe()
	_, err = sub.NextMsg(100 * time.Millisecond)
	if err == nil {
		t.Fatalf("NextMsg should have returned an error")
	}
}

func TestSlowSubscriber(t *testing.T) {
	nc := newConnection(t)
	defer nc.Close()

	sub, _ := nc.SubscribeSync("foo")
	for i := 0; i < (maxChanLen + 10); i++ {
		nc.Publish("foo", []byte("Hello"))
	}
	timeout := 500 * time.Millisecond
	start := time.Now()
	nc.FlushTimeout(timeout)
	elapsed := time.Since(start)
	if elapsed >= timeout {
		t.Fatalf("Flush did not return before timeout: %d > %d", elapsed, timeout)
	}
	// Make sure NextMsg returns an error to indicate slow consumer
	_, err := sub.NextMsg(100 * time.Millisecond)
	if err == nil {
		t.Fatalf("NextMsg did not return an error")
	}
}

func TestSlowAsyncSubscriber(t *testing.T) {
	nc := newConnection(t)
	defer nc.Close()

	nc.Subscribe("foo", func(_ *Msg) {
		time.Sleep(100 * time.Second)
	})
	for i := 0; i < (maxChanLen + 10); i++ {
		nc.Publish("foo", []byte("Hello"))
	}
	timeout := 500 * time.Millisecond
	start := time.Now()
	err := nc.FlushTimeout(timeout)
	elapsed := time.Since(start)
	if elapsed >= timeout {
		t.Fatalf("Flush did not return before timeout")
	}
	if err == nil {
		t.Fatal("Expected an error indicating slow consumer")
	}
}

func TestAsyncErrHandler(t *testing.T) {
	nc := newConnection(t)
	defer nc.Close()

	ch := make(chan bool)
	subj := "async_test"

	sub, err := nc.Subscribe(subj, func(_ *Msg) {
		time.Sleep(100 * time.Second)
	})
	if err != nil {
		t.Fatalf("Could not subscribe: %v\n", err)
	}

	nc.Opts.AsyncErrorCB = func(c *Conn, s *Subscription, e error) {
		if s != sub {
			t.Fatal("Did not receive proper subscription")
		}
		if e != ErrSlowConsumer {
			t.Fatalf("Did not receive proper error: %v vs %v\n", e, ErrSlowConsumer)
		}
		ch <- true
	}

	b := []byte("Hello World!")
	for i := 0; i < (maxChanLen + 10); i++ {
		nc.Publish(subj, b)
	}
	nc.Flush()

	if e := wait(ch); e != nil {
		t.Fatal("Failed to call async err handler")
	}
}

// Test to make sure that we can send and async receive messages on
// different subjects within a callback.
func TestAsyncSubscriberStarvation(t *testing.T) {
	nc := newConnection(t)
	defer nc.Close()

	// Helper
	nc.Subscribe("helper", func(m *Msg) {
		nc.Publish(m.Reply, []byte("Hello"))
	})

	ch := make(chan bool)

	// Kickoff
	nc.Subscribe("start", func(m *Msg) {
		// Helper Response
		response := NewInbox()
		nc.Subscribe(response, func(_ *Msg) {
			ch <- true
		})
		nc.PublishRequest("helper", response, []byte("Help Me!"))
	})

	nc.Publish("start", []byte("Begin"))
	nc.Flush()

	if e := wait(ch); e != nil {
		t.Fatal("Was stalled inside of callback waiting on another callback")
	}
}

// FIXME: Hack, make this better
func TestStopServer(t *testing.T) {
	s.stopServer()
}
<|endoftext|>


<commit_before>// job.go
//
// Copyright (c) 2016, Ayke van Laethem
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package sync

import (
	"bytes"
	"path"

	"github.com/aykevl/dtsync/dtdiff"
	"github.com/aykevl/dtsync/tree"
)

// Action is the type for the ACTION_* constants
type Action int

// Some job action constants. The names should be obvious.
const (
	ACTION_COPY   Action = iota
	ACTION_UPDATE Action = iota
	ACTION_CHMOD  Action = iota
	ACTION_REMOVE Action = iota
)

func (a Action) String() string {
	s := "action?"
	switch a {
	case ACTION_COPY:
		s = "copy"
	case ACTION_UPDATE:
		s = "update"
	case ACTION_CHMOD:
		s = "chmod"
	case ACTION_REMOVE:
		s = "remove"
	}
	return s
}

// Job is one action to apply (copy, update or delete)
type Job struct {
	result        *Result
	applied       bool
	action        Action
	status1       *dtdiff.Entry
	status2       *dtdiff.Entry
	statusParent1 *dtdiff.Entry
	statusParent2 *dtdiff.Entry
	// The direction is a special one.
	// When it is changed, file1, file2 etc are also changed.
	// And if it is a copy or delete, the action is reversed (copy becomes
	// delete, and delete becomes copy).
	//
	// Values:
	//   1 left-to-right aka forwards (file1 → file2)
	//   0 undecided (conflict, user must choose)
	//  -1 right-to-left aka backwards (file1 ← file2)
	direction       int
	hasNewDirection bool
	newDirection    int
}

// String returns a representation of this job for debugging.
func (j *Job) String() string {
	return "Job(" + j.Action().String() + "," + j.Name() + ")"
}

// Name returns the filename of the file to be copied, updated, or removed.
func (j *Job) Name() string {
	var name1, name2 string
	if j.status1 != nil {
		name1 = j.status1.Name()
	}
	if j.status2 != nil {
		name2 = j.status2.Name()
	}
	if j.Action() == ACTION_REMOVE {
		name1, name2 = name2, name1
	}
	switch j.Direction() {
	case 1:
		return name1
	case 0:
		return name1 + "," + name2
	case -1:
		return name2
	default:
		panic("unknown direction")
	}
}

// Apply this job (copying, updating, or removing).
func (j *Job) Apply() error {
	if j.applied {
		return ErrAlreadyApplied
	}

	status1 := j.status1
	status2 := j.status2
	statusParent1 := j.statusParent1
	statusParent2 := j.statusParent2
	fs1 := j.result.fs1
	fs2 := j.result.fs2

	switch j.Direction() {
	case 1:
		// don't swap
	case 0:
		return ErrConflict
	case -1:
		// swap: we're going the opposite direction
		status1, status2 = status2, status1
		statusParent1, statusParent2 = statusParent2, statusParent1
		fs1, fs2 = fs2, fs1
	default:
		panic("unknown direction")
	}
	j.applied = true

	// Add error now, remove it at the end when there was no error (all errors
	// return early).
	j.result.countTotal++
	j.result.countError++

	switch j.Action() {
	case ACTION_COPY:
		err := copyFile(fs1, fs2, status1, statusParent2)
		if err != nil {
			return err
		}
	case ACTION_UPDATE:
		info, parentInfo, err := tree.Update(fs1, fs2, status1, status2)
		if err != nil {
			return err
		}
		if !bytes.Equal(info.Hash(), status1.Hash()) {
			// The first file got updated between the scan and update.
			// TODO Should we report this as an error?
			status1.UpdateHash(info.Hash(), nil)
		}
		status2.Update(info, info.Hash(), status1)
		statusParent2.Update(parentInfo, nil, statusParent1)
	case ACTION_REMOVE:
		parentInfo, err := fs2.Remove(status2)
		if err != nil {
			return err
		}
		status2.Remove()
		statusParent2.Update(parentInfo, nil, statusParent1)
	case ACTION_CHMOD:
		info, err := fs2.Chmod(status2, status1)
		if err != nil {
			return err
		}
		status2.Update(info, status2.Hash(), status1)
	default:
		panic("unknown action (must not happen)")
	}

	// There was no error.
	j.result.countError--
	if j.result.countTotal == len(j.result.jobs) && j.result.countError == 0 {
		j.result.markSynced()
	}
	return nil
}

func copyFile(fs1, fs2 tree.Tree, status1, statusParent2 *dtdiff.Entry) error {
	if status1.Type() == tree.TYPE_DIRECTORY {
		info, err := fs2.CreateDir(status1.Name(), statusParent2, status1)
		if err != nil {
			return err
		}
		status2, err := statusParent2.Add(info, status1)
		if err != nil {
			panic(err)
		}
		list := status1.List()
		for _, child1 := range list {
			err := copyFile(fs1, fs2, child1, status2)
			if err != nil {
				// TODO revert
				return err
			}
		}
	} else {
		info, parentInfo, err := tree.Copy(fs1, fs2, status1, statusParent2)
		if err != nil {
			return err
		}
		statusParent2.Update(parentInfo, nil, nil)
		_, err = statusParent2.Add(info, status1)
		if err != nil {
			return err
		}
	}
	return nil
}

// Direction returns the sync direction of this file, with 1 for left-to-right,
// 0 for undecided (conflict), and -1 for right-to-left.
func (j *Job) Direction() int {
	if j.hasNewDirection {
		return j.newDirection
	}
	return j.direction
}

// SetDirection sets the job direction, which must be -1, 0, or 1. Any other
// value will cause a panic.
func (j *Job) SetDirection(direction int) {
	switch direction {
	case -1, 0, 1:
	default:
		panic("invalid direction")
	}
	j.newDirection = direction
	j.hasNewDirection = true
}

// Action returns the (possibly flipped) action constant.
func (j *Job) Action() Action {
	if j.hasNewDirection && j.direction != 0 && j.newDirection != 0 && j.direction != j.newDirection {
		switch j.action {
		case ACTION_COPY:
			return ACTION_REMOVE
		case ACTION_REMOVE:
			return ACTION_COPY
		default:
			return j.action
		}
	}
	return j.action
}

// Applied returns true if this action was already applied.
func (j *Job) Applied() bool {
	return j.applied
}

// StatusLeft returns an identifying string of what happened on the left side of
// the sync.
func (j *Job) StatusLeft() string {
	return j.status(j.status1, j.statusParent1, j.status2, j.statusParent2)
}

// StatusRight is similar to StatusLeft.
func (j *Job) StatusRight() string {
	return j.status(j.status2, j.statusParent2, j.status1, j.statusParent1)
}

// status returns the change that was applied to this file (new, modified,
// removed).
func (j *Job) status(status, statusParent, otherStatus, otherStatusParent *dtdiff.Entry) string {
	if status == nil {
		if statusParent.HasRevision(otherStatus) {
			return "removed"
		} else {
			return ""
		}
	} else if otherStatus == nil {
		if otherStatusParent.HasRevision(status) {
			return ""
		} else {
			return "new"
		}
	}
	if status.After(otherStatus) {
		return "modified"
	}
	return ""
}

// RelativePath returns the path relative to it's root.
func (j *Job) RelativePath() string {
	// This must be updated when we implement file or directory moves: then the
	// paths cannot be assumed to be the same.
	var relpath []string
	if j.status1 == nil {
		relpath = j.status2.RelativePath()
	} else {
		relpath = j.status1.RelativePath()
	}
	return path.Join(relpath...)
}
<commit_msg>sync: improve Job.String()<commit_after>// job.go
//
// Copyright (c) 2016, Ayke van Laethem
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package sync

import (
	"bytes"
	"path"

	"github.com/aykevl/dtsync/dtdiff"
	"github.com/aykevl/dtsync/tree"
)

// Action is the type for the ACTION_* constants
type Action int

// Some job action constants. The names should be obvious.
const (
	ACTION_COPY   Action = iota
	ACTION_UPDATE Action = iota
	ACTION_CHMOD  Action = iota
	ACTION_REMOVE Action = iota
)

func (a Action) String() string {
	s := "action?"
	switch a {
	case ACTION_COPY:
		s = "copy"
	case ACTION_UPDATE:
		s = "update"
	case ACTION_CHMOD:
		s = "chmod"
	case ACTION_REMOVE:
		s = "remove"
	}
	return s
}

// Job is one action to apply (copy, update or delete)
type Job struct {
	result        *Result
	applied       bool
	action        Action
	status1       *dtdiff.Entry
	status2       *dtdiff.Entry
	statusParent1 *dtdiff.Entry
	statusParent2 *dtdiff.Entry
	// The direction is a special one.
	// When it is changed, file1, file2 etc are also changed.
	// And if it is a copy or delete, the action is reversed (copy becomes
	// delete, and delete becomes copy).
	//
	// Values:
	//   1 left-to-right aka forwards (file1 → file2)
	//   0 undecided (conflict, user must choose)
	//  -1 right-to-left aka backwards (file1 ← file2)
	direction       int
	hasNewDirection bool
	newDirection    int
}

// String returns a representation of this job for debugging.
func (j *Job) String() string {
	return "Job(" + j.Action().String() + "," + j.Path() + ")"
}

// Name returns the filename of the file to be copied, updated, or removed.
func (j *Job) Name() string {
	status1, status2 := j.primary()
	switch j.Direction() {
	case 1:
		return status1.Name()
	case 0:
		return status1.Name() + "," + status2.Name()
	case -1:
		return status2.Name()
	default:
		panic("unknown direction")
	}
}

// Path returns the relative path separated by forward slashes (/). Just like
// Name().
func (j *Job) Path() string {
	status1, status2 := j.primary()
	switch j.Direction() {
	case 1:
		return path.Join(status1.RelativePath()...)
	case 0:
		switch {
		case status1 == nil:
			return path.Join(status2.RelativePath()...)
		case status2 == nil:
			return path.Join(status1.RelativePath()...)
		default:
			return path.Join(status1.RelativePath()...) + "," + path.Join(status2.RelativePath()...)
		}
	case -1:
		return path.Join(status2.RelativePath()...)
	default:
		panic("unknown direction")
	}
}

func (j *Job) primary() (*dtdiff.Entry, *dtdiff.Entry) {
	status1, status2 := j.status1, j.status2
	if j.Action() == ACTION_REMOVE {
		status1, status2 = status2, status1
	}
	return status1, status2
}

// Apply this job (copying, updating, or removing).
func (j *Job) Apply() error {
	if j.applied {
		return ErrAlreadyApplied
	}

	status1 := j.status1
	status2 := j.status2
	statusParent1 := j.statusParent1
	statusParent2 := j.statusParent2
	fs1 := j.result.fs1
	fs2 := j.result.fs2

	switch j.Direction() {
	case 1:
		// don't swap
	case 0:
		return ErrConflict
	case -1:
		// swap: we're going the opposite direction
		status1, status2 = status2, status1
		statusParent1, statusParent2 = statusParent2, statusParent1
		fs1, fs2 = fs2, fs1
	default:
		panic("unknown direction")
	}
	j.applied = true

	// Add error now, remove it at the end when there was no error (all errors
	// return early).
	j.result.countTotal++
	j.result.countError++

	switch j.Action() {
	case ACTION_COPY:
		err := copyFile(fs1, fs2, status1, statusParent2)
		if err != nil {
			return err
		}
	case ACTION_UPDATE:
		info, parentInfo, err := tree.Update(fs1, fs2, status1, status2)
		if err != nil {
			return err
		}
		if !bytes.Equal(info.Hash(), status1.Hash()) {
			// The first file got updated between the scan and update.
			// TODO Should we report this as an error?
			status1.UpdateHash(info.Hash(), nil)
		}
		status2.Update(info, info.Hash(), status1)
		statusParent2.Update(parentInfo, nil, statusParent1)
	case ACTION_REMOVE:
		parentInfo, err := fs2.Remove(status2)
		if err != nil {
			return err
		}
		status2.Remove()
		statusParent2.Update(parentInfo, nil, statusParent1)
	case ACTION_CHMOD:
		info, err := fs2.Chmod(status2, status1)
		if err != nil {
			return err
		}
		status2.Update(info, status2.Hash(), status1)
	default:
		panic("unknown action (must not happen)")
	}

	// There was no error.
	j.result.countError--
	if j.result.countTotal == len(j.result.jobs) && j.result.countError == 0 {
		j.result.markSynced()
	}
	return nil
}

func copyFile(fs1, fs2 tree.Tree, status1, statusParent2 *dtdiff.Entry) error {
	if status1.Type() == tree.TYPE_DIRECTORY {
		info, err := fs2.CreateDir(status1.Name(), statusParent2, status1)
		if err != nil {
			return err
		}
		status2, err := statusParent2.Add(info, status1)
		if err != nil {
			panic(err)
		}
		list := status1.List()
		for _, child1 := range list {
			err := copyFile(fs1, fs2, child1, status2)
			if err != nil {
				// TODO revert
				return err
			}
		}
	} else {
		info, parentInfo, err := tree.Copy(fs1, fs2, status1, statusParent2)
		if err != nil {
			return err
		}
		statusParent2.Update(parentInfo, nil, nil)
		_, err = statusParent2.Add(info, status1)
		if err != nil {
			return err
		}
	}
	return nil
}

// Direction returns the sync direction of this file, with 1 for left-to-right,
// 0 for undecided (conflict), and -1 for right-to-left.
func (j *Job) Direction() int {
	if j.hasNewDirection {
		return j.newDirection
	}
	return j.direction
}

// SetDirection sets the job direction, which must be -1, 0, or 1. Any other
// value will cause a panic.
func (j *Job) SetDirection(direction int) {
	switch direction {
	case -1, 0, 1:
	default:
		panic("invalid direction")
	}
	j.newDirection = direction
	j.hasNewDirection = true
}

// Action returns the (possibly flipped) action constant.
func (j *Job) Action() Action {
	if j.hasNewDirection && j.direction != 0 && j.newDirection != 0 && j.direction != j.newDirection {
		switch j.action {
		case ACTION_COPY:
			return ACTION_REMOVE
		case ACTION_REMOVE:
			return ACTION_COPY
		default:
			return j.action
		}
	}
	return j.action
}

// Applied returns true if this action was already applied.
func (j *Job) Applied() bool {
	return j.applied
}

// StatusLeft returns an identifying string of what happened on the left side of
// the sync.
func (j *Job) StatusLeft() string {
	return j.status(j.status1, j.statusParent1, j.status2, j.statusParent2)
}

// StatusRight is similar to StatusLeft.
func (j *Job) StatusRight() string {
	return j.status(j.status2, j.statusParent2, j.status1, j.statusParent1)
}

// status returns the change that was applied to this file (new, modified,
// removed).
func (j *Job) status(status, statusParent, otherStatus, otherStatusParent *dtdiff.Entry) string {
	if status == nil {
		if statusParent.HasRevision(otherStatus) {
			return "removed"
		} else {
			return ""
		}
	} else if otherStatus == nil {
		if otherStatusParent.HasRevision(status) {
			return ""
		} else {
			return "new"
		}
	}
	if status.After(otherStatus) {
		return "modified"
	}
	return ""
}

// RelativePath returns the path relative to it's root.
func (j *Job) RelativePath() string {
	// This must be updated when we implement file or directory moves: then the
	// paths cannot be assumed to be the same.
	var relpath []string
	if j.status1 == nil {
		relpath = j.status2.RelativePath()
	} else {
		relpath = j.status1.RelativePath()
	}
	return path.Join(relpath...)
}
<|endoftext|>


<commit_before>package pongo2

import (
	"github.com/astaxie/beego"
	p2 "github.com/flosch/pongo2"
)

type tagURLNode struct {
	objectEvaluators []p2.INodeEvaluator
}

func (node *tagURLNode) Execute(ctx *p2.ExecutionContext) (string, error) {
	args := make([]string, len(node.objectEvaluators))
	for i, ev := range node.objectEvaluators {
		obj, err := ev.Evaluate(ctx)
		if err != nil {
			return "", err
		}
		args[i] = obj.String()
	}

	url := beego.UrlFor(args[0], args[1:]...)
	return url, nil
}

// tagURLForParser implements a {% urlfor %} tag.
//
// urlfor takes one argument for the controller, as well as any number of key/value pairs for additional URL data.
// Example: {% url "UserController.View" ":slug" "oal" %}
func tagURLForParser(doc *p2.Parser, start *p2.Token, arguments *p2.Parser) (p2.INodeTag, error) {
	if (arguments.Count()-1)%2 != 0 {
		return nil, arguments.Error("URL takes one argument for the controller and any number of optional pairs of key/value pairs.", nil)
	}

	evals := []p2.INodeEvaluator{}
	for arguments.Remaining() > 0 {
		eval, err := arguments.ParseExpression()
		evals = append(evals, eval)
		if err != nil {
			return nil, err
		}
	}

	return &tagURLNode{evals}, nil
}

func init() {
	p2.RegisterTag("urlfor", tagURLForParser)
}
<commit_msg>Check number of arguments after parsing.<commit_after>package pongo2

import (
	"github.com/astaxie/beego"
	p2 "github.com/flosch/pongo2"
)

type tagURLNode struct {
	objectEvaluators []p2.INodeEvaluator
}

func (node *tagURLNode) Execute(ctx *p2.ExecutionContext) (string, error) {
	args := make([]string, len(node.objectEvaluators))
	for i, ev := range node.objectEvaluators {
		obj, err := ev.Evaluate(ctx)
		if err != nil {
			return "", err
		}
		args[i] = obj.String()
	}

	url := beego.UrlFor(args[0], args[1:]...)
	return url, nil
}

// tagURLForParser implements a {% urlfor %} tag.
//
// urlfor takes one argument for the controller, as well as any number of key/value pairs for additional URL data.
// Example: {% url "UserController.View" ":slug" "oal" %}
func tagURLForParser(doc *p2.Parser, start *p2.Token, arguments *p2.Parser) (p2.INodeTag, error) {
	evals := []p2.INodeEvaluator{}
	for arguments.Remaining() > 0 {
		expr, err := arguments.ParseExpression()
		evals = append(evals, expr)
		if err != nil {
			return nil, err
		}
	}

	if (len(evals)-1)%2 != 0 {
		return nil, arguments.Error("URL takes one argument for the controller and any number of optional pairs of key/value pairs.", nil)
	}

	return &tagURLNode{evals}, nil
}

func init() {
	p2.RegisterTag("urlfor", tagURLForParser)
}
<|endoftext|>


<commit_before>// Copyright 2018 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package sysfs

import (
	"fmt"
	"io/ioutil"
	"os"
	"reflect"
	"strconv"
	"strings"
	"syscall"
)

// NetClassIface contains info from files in /sys/class/net/<iface>
// for single interface (iface).
type NetClassIface struct {
	Name             string // Interface name
	AddrAssignType   *int64 `fileName:"addr_assign_type"`   // /sys/class/net/<iface>/addr_assign_type
	AddrLen          *int64 `fileName:"addr_len"`           // /sys/class/net/<iface>/addr_len
	Address          string `fileName:"address"`            // /sys/class/net/<iface>/address
	Broadcast        string `fileName:"broadcast"`          // /sys/class/net/<iface>/broadcast
	Carrier          *int64 `fileName:"carrier"`            // /sys/class/net/<iface>/carrier
	CarrierChanges   *int64 `fileName:"carrier_changes"`    // /sys/class/net/<iface>/carrier_changes
	CarrierUpCount   *int64 `fileName:"carrier_up_count"`   // /sys/class/net/<iface>/carrier_up_count
	CarrierDownCount *int64 `fileName:"carrier_down_count"` // /sys/class/net/<iface>/carrier_down_count
	DevID            *int64 `fileName:"dev_id"`             // /sys/class/net/<iface>/dev_id
	Dormant          *int64 `fileName:"dormant"`            // /sys/class/net/<iface>/dormant
	Duplex           string `fileName:"duplex"`             // /sys/class/net/<iface>/duplex
	Flags            *int64 `fileName:"flags"`              // /sys/class/net/<iface>/flags
	IfAlias          string `fileName:"ifalias"`            // /sys/class/net/<iface>/ifalias
	IfIndex          *int64 `fileName:"ifindex"`            // /sys/class/net/<iface>/ifindex
	IfLink           *int64 `fileName:"iflink"`             // /sys/class/net/<iface>/iflink
	LinkMode         *int64 `fileName:"link_mode"`          // /sys/class/net/<iface>/link_mode
	MTU              *int64 `fileName:"mtu"`                // /sys/class/net/<iface>/mtu
	NameAssignType   *int64 `fileName:"name_assign_type"`   // /sys/class/net/<iface>/name_assign_type
	NetDevGroup      *int64 `fileName:"netdev_group"`       // /sys/class/net/<iface>/netdev_group
	OperState        string `fileName:"operstate"`          // /sys/class/net/<iface>/operstate
	PhysPortID       string `fileName:"phys_port_id"`       // /sys/class/net/<iface>/phys_port_id
	PhysPortName     string `fileName:"phys_port_name"`     // /sys/class/net/<iface>/phys_port_name
	PhysSwitchID     string `fileName:"phys_switch_id"`     // /sys/class/net/<iface>/phys_switch_id
	Speed            *int64 `fileName:"speed"`              // /sys/class/net/<iface>/speed
	TxQueueLen       *int64 `fileName:"tx_queue_len"`       // /sys/class/net/<iface>/tx_queue_len
	Type             *int64 `fileName:"type"`               // /sys/class/net/<iface>/type
}

// NetClass is collection of info for every interface (iface) in /sys/class/net. The map keys
// are interface (iface) names.
type NetClass map[string]NetClassIface

// NewNetClass returns info for all net interfaces (iface) read from /sys/class/net/<iface>.
func NewNetClass() (NetClass, error) {
	fs, err := NewFS(DefaultMountPoint)
	if err != nil {
		return nil, err
	}

	return fs.NewNetClass()
}

// NewNetClass returns info for all net interfaces (iface) read from /sys/class/net/<iface>.
func (fs FS) NewNetClass() (NetClass, error) {
	path := fs.Path("class/net")

	devices, err := ioutil.ReadDir(path)
	if err != nil {
		return NetClass{}, fmt.Errorf("cannot access %s dir %s", path, err)
	}

	netClass := NetClass{}
	for _, deviceDir := range devices {
		interfaceClass, err := netClass.parseNetClassIface(path + "/" + deviceDir.Name())
		if err != nil {
			return nil, err
		}
		interfaceClass.Name = deviceDir.Name()
		netClass[deviceDir.Name()] = *interfaceClass
	}
	return netClass, nil
}

// parseNetClassIface scans predefined files in /sys/class/net/<iface>
// directory and gets their contents.
func (nc NetClass) parseNetClassIface(devicePath string) (*NetClassIface, error) {
	interfaceClass := NetClassIface{}
	interfaceElem := reflect.ValueOf(&interfaceClass).Elem()
	interfaceType := reflect.TypeOf(interfaceClass)

	//start from 1 - skip the Name field
	for i := 1; i < interfaceElem.NumField(); i++ {
		fieldType := interfaceType.Field(i)
		fieldValue := interfaceElem.Field(i)

		if fieldType.Tag.Get("fileName") == "" {
			panic(fmt.Errorf("field %s does not have a filename tag", fieldType.Name))
		}

		fileContents, err := sysReadFile(devicePath + "/" + fieldType.Tag.Get("fileName"))

		if err != nil {
			if os.IsNotExist(err) || err.Error() == "operation not supported" || err.Error() == "invalid argument" {
				continue
			}
			return nil, fmt.Errorf("could not access file %s: %s", fieldType.Tag.Get("fileName"), err)
		}
		value := strings.TrimSpace(string(fileContents))

		switch fieldValue.Kind() {
		case reflect.String:
			fieldValue.SetString(value)
		case reflect.Ptr:
			var int64ptr *int64
			switch fieldValue.Type() {
			case reflect.TypeOf(int64ptr):
				var intValue int64
				if strings.HasPrefix(value, "0x") {
					intValue, err = strconv.ParseInt(value[2:], 16, 64)
					if err != nil {
						return nil, fmt.Errorf("expected hex value for %s, got: %s", fieldType.Name, value)
					}
				} else {
					intValue, err = strconv.ParseInt(value, 10, 64)
					if err != nil {
						return nil, fmt.Errorf("expected Uint64 value for %s, got: %s", fieldType.Name, value)
					}
				}
				fieldValue.Set(reflect.ValueOf(&intValue))
			default:
				return nil, fmt.Errorf("unhandled pointer type %q", fieldValue.Type())
			}
		default:
			return nil, fmt.Errorf("unhandled type %q", fieldValue.Kind())
		}
	}

	return &interfaceClass, nil
}

// sysReadFile is a simplified ioutil.ReadFile that invokes syscall.Read directly.
// https://github.com/prometheus/node_exporter/pull/728/files
func sysReadFile(file string) ([]byte, error) {
	f, err := os.Open(file)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	// On some machines, hwmon drivers are broken and return EAGAIN.  This causes
	// Go's ioutil.ReadFile implementation to poll forever.
	//
	// Since we either want to read data or bail immediately, do the simplest
	// possible read using syscall directly.
	b := make([]byte, 128)
	n, err := syscall.Read(int(f.Fd()), b)
	if err != nil {
		return nil, err
	}

	return b[:n], nil
}
<commit_msg>sysfs/netclass: Parse only directories (#90)<commit_after>// Copyright 2018 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package sysfs

import (
	"fmt"
	"io/ioutil"
	"os"
	"reflect"
	"strconv"
	"strings"
	"syscall"
)

// NetClassIface contains info from files in /sys/class/net/<iface>
// for single interface (iface).
type NetClassIface struct {
	Name             string // Interface name
	AddrAssignType   *int64 `fileName:"addr_assign_type"`   // /sys/class/net/<iface>/addr_assign_type
	AddrLen          *int64 `fileName:"addr_len"`           // /sys/class/net/<iface>/addr_len
	Address          string `fileName:"address"`            // /sys/class/net/<iface>/address
	Broadcast        string `fileName:"broadcast"`          // /sys/class/net/<iface>/broadcast
	Carrier          *int64 `fileName:"carrier"`            // /sys/class/net/<iface>/carrier
	CarrierChanges   *int64 `fileName:"carrier_changes"`    // /sys/class/net/<iface>/carrier_changes
	CarrierUpCount   *int64 `fileName:"carrier_up_count"`   // /sys/class/net/<iface>/carrier_up_count
	CarrierDownCount *int64 `fileName:"carrier_down_count"` // /sys/class/net/<iface>/carrier_down_count
	DevID            *int64 `fileName:"dev_id"`             // /sys/class/net/<iface>/dev_id
	Dormant          *int64 `fileName:"dormant"`            // /sys/class/net/<iface>/dormant
	Duplex           string `fileName:"duplex"`             // /sys/class/net/<iface>/duplex
	Flags            *int64 `fileName:"flags"`              // /sys/class/net/<iface>/flags
	IfAlias          string `fileName:"ifalias"`            // /sys/class/net/<iface>/ifalias
	IfIndex          *int64 `fileName:"ifindex"`            // /sys/class/net/<iface>/ifindex
	IfLink           *int64 `fileName:"iflink"`             // /sys/class/net/<iface>/iflink
	LinkMode         *int64 `fileName:"link_mode"`          // /sys/class/net/<iface>/link_mode
	MTU              *int64 `fileName:"mtu"`                // /sys/class/net/<iface>/mtu
	NameAssignType   *int64 `fileName:"name_assign_type"`   // /sys/class/net/<iface>/name_assign_type
	NetDevGroup      *int64 `fileName:"netdev_group"`       // /sys/class/net/<iface>/netdev_group
	OperState        string `fileName:"operstate"`          // /sys/class/net/<iface>/operstate
	PhysPortID       string `fileName:"phys_port_id"`       // /sys/class/net/<iface>/phys_port_id
	PhysPortName     string `fileName:"phys_port_name"`     // /sys/class/net/<iface>/phys_port_name
	PhysSwitchID     string `fileName:"phys_switch_id"`     // /sys/class/net/<iface>/phys_switch_id
	Speed            *int64 `fileName:"speed"`              // /sys/class/net/<iface>/speed
	TxQueueLen       *int64 `fileName:"tx_queue_len"`       // /sys/class/net/<iface>/tx_queue_len
	Type             *int64 `fileName:"type"`               // /sys/class/net/<iface>/type
}

// NetClass is collection of info for every interface (iface) in /sys/class/net. The map keys
// are interface (iface) names.
type NetClass map[string]NetClassIface

// NewNetClass returns info for all net interfaces (iface) read from /sys/class/net/<iface>.
func NewNetClass() (NetClass, error) {
	fs, err := NewFS(DefaultMountPoint)
	if err != nil {
		return nil, err
	}

	return fs.NewNetClass()
}

// NewNetClass returns info for all net interfaces (iface) read from /sys/class/net/<iface>.
func (fs FS) NewNetClass() (NetClass, error) {
	path := fs.Path("class/net")

	devices, err := ioutil.ReadDir(path)
	if err != nil {
		return NetClass{}, fmt.Errorf("cannot access %s dir %s", path, err)
	}

	netClass := NetClass{}
	for _, deviceDir := range devices {
		if !deviceDir.IsDir() {
			continue
		}
		interfaceClass, err := netClass.parseNetClassIface(path + "/" + deviceDir.Name())
		if err != nil {
			return nil, err
		}
		interfaceClass.Name = deviceDir.Name()
		netClass[deviceDir.Name()] = *interfaceClass
	}
	return netClass, nil
}

// parseNetClassIface scans predefined files in /sys/class/net/<iface>
// directory and gets their contents.
func (nc NetClass) parseNetClassIface(devicePath string) (*NetClassIface, error) {
	interfaceClass := NetClassIface{}
	interfaceElem := reflect.ValueOf(&interfaceClass).Elem()
	interfaceType := reflect.TypeOf(interfaceClass)

	//start from 1 - skip the Name field
	for i := 1; i < interfaceElem.NumField(); i++ {
		fieldType := interfaceType.Field(i)
		fieldValue := interfaceElem.Field(i)

		if fieldType.Tag.Get("fileName") == "" {
			panic(fmt.Errorf("field %s does not have a filename tag", fieldType.Name))
		}

		fileContents, err := sysReadFile(devicePath + "/" + fieldType.Tag.Get("fileName"))

		if err != nil {
			if os.IsNotExist(err) || err.Error() == "operation not supported" || err.Error() == "invalid argument" {
				continue
			}
			return nil, fmt.Errorf("could not access file %s: %s", fieldType.Tag.Get("fileName"), err)
		}
		value := strings.TrimSpace(string(fileContents))

		switch fieldValue.Kind() {
		case reflect.String:
			fieldValue.SetString(value)
		case reflect.Ptr:
			var int64ptr *int64
			switch fieldValue.Type() {
			case reflect.TypeOf(int64ptr):
				var intValue int64
				if strings.HasPrefix(value, "0x") {
					intValue, err = strconv.ParseInt(value[2:], 16, 64)
					if err != nil {
						return nil, fmt.Errorf("expected hex value for %s, got: %s", fieldType.Name, value)
					}
				} else {
					intValue, err = strconv.ParseInt(value, 10, 64)
					if err != nil {
						return nil, fmt.Errorf("expected Uint64 value for %s, got: %s", fieldType.Name, value)
					}
				}
				fieldValue.Set(reflect.ValueOf(&intValue))
			default:
				return nil, fmt.Errorf("unhandled pointer type %q", fieldValue.Type())
			}
		default:
			return nil, fmt.Errorf("unhandled type %q", fieldValue.Kind())
		}
	}

	return &interfaceClass, nil
}

// sysReadFile is a simplified ioutil.ReadFile that invokes syscall.Read directly.
// https://github.com/prometheus/node_exporter/pull/728/files
func sysReadFile(file string) ([]byte, error) {
	f, err := os.Open(file)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	// On some machines, hwmon drivers are broken and return EAGAIN.  This causes
	// Go's ioutil.ReadFile implementation to poll forever.
	//
	// Since we either want to read data or bail immediately, do the simplest
	// possible read using syscall directly.
	b := make([]byte, 128)
	n, err := syscall.Read(int(f.Fd()), b)
	if err != nil {
		return nil, err
	}

	return b[:n], nil
}
<|endoftext|>


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

package main

func main() {
	println("aa")
	greeting()
}
<commit_msg>rsc: more edits<commit_after>// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

func main() {
	println("cc")
	greeting()
}
<|endoftext|>