<commit_before>package pingdom

import (
	"encoding/json"
	"io/ioutil"
	"strconv"
)

// CheckService provides an interface to Pingdom checks
type CheckService struct {
	client *Client
}

// Check is an interface representing a pingdom check.
// Specific check types should implement the methods of this interface
type Check interface {
	PutParams() map[string]string
	PostParams() map[string]string
	Valid() error
}

// Return a list of checks from Pingdom.
// This returns type CheckResponse rather than Check since the
// pingdom API does not return a complete representation of a check.
func (cs *CheckService) List() ([]CheckResponse, error) {
	req, err := cs.client.NewRequest("GET", "/api/2.0/checks", nil)
	if err != nil {
		return nil, err
	}

	resp, err := cs.client.client.Do(req)
	defer resp.Body.Close()
	if err != nil {
		return nil, err
	}

	if err := validateResponse(resp); err != nil {
		return nil, err
	}

	bodyBytes, _ := ioutil.ReadAll(resp.Body)
	bodyString := string(bodyBytes)
	m := &listChecksJsonResponse{}
	err = json.Unmarshal([]byte(bodyString), &m)

	return m.Checks, err
}

// Create a new check.  This function will validate the given check param
// to ensure that it contains correct values before submitting the request
// Returns a CheckResponse object representing the response from Pingdom.
// Note that Pingdom does not return a full check object so in the returned
// object you should only use the ID field.
func (cs *CheckService) Create(check Check) (*CheckResponse, error) {
	if err := check.Valid(); err != nil {
		return nil, err
	}

	req, err := cs.client.NewRequest("POST", "/api/2.0/checks", check.PostParams())
	if err != nil {
		return nil, err
	}

	m := &checkDetailsJsonResponse{}
	_, err = cs.client.Do(req, m)
	if err != nil {
		return nil, err
	}
	return m.Check, err
}

// ReadCheck returns detailed information about a pingdom check given its ID.
// This returns type CheckResponse rather than Check since the
// pingdom API does not return a complete representation of a check.
func (cs *CheckService) Read(id int) (*CheckResponse, error) {
	req, err := cs.client.NewRequest("GET", "/api/2.0/checks/"+strconv.Itoa(id), nil)
	if err != nil {
		return nil, err
	}

	m := &checkDetailsJsonResponse{}
	_, err = cs.client.Do(req, m)
	if err != nil {
		return nil, err
	}

	return m.Check, err
}

// UpdateCheck will update the check represented by the given ID with the values
// in the given check.  You should submit the complete list of values in
// the given check parameter, not just those that have changed.
func (cs *CheckService) Update(id int, check Check) (*PingdomResponse, error) {
	if err := check.Valid(); err != nil {
		return nil, err
	}

	req, err := cs.client.NewRequest("PUT", "/api/2.0/checks/"+strconv.Itoa(id), check.PutParams())
	if err != nil {
		return nil, err
	}

	m := &PingdomResponse{}
	_, err = cs.client.Do(req, m)
	if err != nil {
		return nil, err
	}
	return m, err
}

// DeleteCheck will delete the check for the given ID.
func (cs *CheckService) Delete(id int) (*PingdomResponse, error) {
	req, err := cs.client.NewRequest("DELETE", "/api/2.0/checks/"+strconv.Itoa(id), nil)
	if err != nil {
		return nil, err
	}

	m := &PingdomResponse{}
	_, err = cs.client.Do(req, m)
	if err != nil {
		return nil, err
	}
	return m, err
}
<commit_msg>close body only if body is not nil<commit_after>package pingdom

import (
	"encoding/json"
	"io/ioutil"
	"strconv"
)

// CheckService provides an interface to Pingdom checks
type CheckService struct {
	client *Client
}

// Check is an interface representing a pingdom check.
// Specific check types should implement the methods of this interface
type Check interface {
	PutParams() map[string]string
	PostParams() map[string]string
	Valid() error
}

// Return a list of checks from Pingdom.
// This returns type CheckResponse rather than Check since the
// pingdom API does not return a complete representation of a check.
func (cs *CheckService) List() ([]CheckResponse, error) {
	req, err := cs.client.NewRequest("GET", "/api/2.0/checks", nil)
	if err != nil {
		return nil, err
	}

	resp, err := cs.client.client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	if err := validateResponse(resp); err != nil {
		return nil, err
	}

	bodyBytes, _ := ioutil.ReadAll(resp.Body)
	bodyString := string(bodyBytes)
	m := &listChecksJsonResponse{}
	err = json.Unmarshal([]byte(bodyString), &m)

	return m.Checks, err
}

// Create a new check.  This function will validate the given check param
// to ensure that it contains correct values before submitting the request
// Returns a CheckResponse object representing the response from Pingdom.
// Note that Pingdom does not return a full check object so in the returned
// object you should only use the ID field.
func (cs *CheckService) Create(check Check) (*CheckResponse, error) {
	if err := check.Valid(); err != nil {
		return nil, err
	}

	req, err := cs.client.NewRequest("POST", "/api/2.0/checks", check.PostParams())
	if err != nil {
		return nil, err
	}

	m := &checkDetailsJsonResponse{}
	_, err = cs.client.Do(req, m)
	if err != nil {
		return nil, err
	}
	return m.Check, err
}

// ReadCheck returns detailed information about a pingdom check given its ID.
// This returns type CheckResponse rather than Check since the
// pingdom API does not return a complete representation of a check.
func (cs *CheckService) Read(id int) (*CheckResponse, error) {
	req, err := cs.client.NewRequest("GET", "/api/2.0/checks/"+strconv.Itoa(id), nil)
	if err != nil {
		return nil, err
	}

	m := &checkDetailsJsonResponse{}
	_, err = cs.client.Do(req, m)
	if err != nil {
		return nil, err
	}

	return m.Check, err
}

// UpdateCheck will update the check represented by the given ID with the values
// in the given check.  You should submit the complete list of values in
// the given check parameter, not just those that have changed.
func (cs *CheckService) Update(id int, check Check) (*PingdomResponse, error) {
	if err := check.Valid(); err != nil {
		return nil, err
	}

	req, err := cs.client.NewRequest("PUT", "/api/2.0/checks/"+strconv.Itoa(id), check.PutParams())
	if err != nil {
		return nil, err
	}

	m := &PingdomResponse{}
	_, err = cs.client.Do(req, m)
	if err != nil {
		return nil, err
	}
	return m, err
}

// DeleteCheck will delete the check for the given ID.
func (cs *CheckService) Delete(id int) (*PingdomResponse, error) {
	req, err := cs.client.NewRequest("DELETE", "/api/2.0/checks/"+strconv.Itoa(id), nil)
	if err != nil {
		return nil, err
	}

	m := &PingdomResponse{}
	_, err = cs.client.Do(req, m)
	if err != nil {
		return nil, err
	}
	return m, err
}
<|endoftext|>


<commit_before>package apps

import (
	"path"
	"strings"

	"github.com/cozy/cozy-stack/pkg/consts"
	"github.com/cozy/cozy-stack/pkg/couchdb"
	"github.com/cozy/cozy-stack/pkg/crypto"
	"github.com/cozy/cozy-stack/pkg/instance"
	"github.com/cozy/cozy-stack/pkg/permissions"
	"github.com/cozy/cozy-stack/web/jsonapi"
	jwt "gopkg.in/dgrijalva/jwt-go.v3"
)

const (
	// ManifestMaxSize is the manifest maximum size
	ManifestMaxSize = 2 << (2 * 10) // 2MB
	// ManifestFilename is the name of the manifest at the root of the
	// application directory
	ManifestFilename = "manifest.webapp"
)

// State is the state of the application
type State string

const (
	// Available state
	Available State = "available"
	// Installing state
	Installing = "installing"
	// Upgrading state
	Upgrading = "upgrading"
	// Uninstalling state
	Uninstalling = "uninstalling"
	// Errored state
	Errored = "errored"
	// Ready state
	Ready = "ready"
)

// Some well known slugs
const (
	OnboardingSlug = "onboarding"
	HomeSlug       = "home"
)

// Access is a string representing the access permission level. It can
// either be read, write or readwrite.
type Access string

// Permissions is a map of key, a description and an access level.
type Permissions map[string]struct {
	Description string `json:"description"`
	Access      Access `json:"access"`
}

// Route is a struct to serve a folder inside an app
type Route struct {
	Folder string `json:"folder"`
	Index  string `json:"index"`
	Public bool   `json:"public"`
}

// NotFound returns true for a blank route (ie not found by FindRoute)
func (c *Route) NotFound() bool { return c.Folder == "" }

// Routes are a map for routing inside an application.
type Routes map[string]Route

// Developer is the name and url of a developer.
type Developer struct {
	Name string `json:"name"`
	URL  string `json:"url,omitempty"`
}

// Manifest contains all the informations about an application.
type Manifest struct {
	ManRev string `json:"_rev,omitempty"` // Manifest revision

	Name        string     `json:"name"`
	Slug        string     `json:"slug"`
	Source      string     `json:"source"`
	State       State      `json:"state"`
	Error       string     `json:"error,omitempty"`
	Icon        string     `json:"icon"`
	Description string     `json:"description"`
	Developer   *Developer `json:"developer"`

	DefaultLocale string `json:"default_locale"`
	Locales       map[string]struct {
		Description string `json:"description"`
	} `json:"locales"`

	Version     string       `json:"version"`
	License     string       `json:"license"`
	Permissions *Permissions `json:"permissions"`
	Routes      Routes       `json:"routes"`
}

// ID returns the manifest identifier - see couchdb.Doc interface
func (m *Manifest) ID() string {
	return consts.Manifests + "/" + m.Slug
}

// Rev return the manifest revision - see couchdb.Doc interface
func (m *Manifest) Rev() string { return m.ManRev }

// DocType returns the manifest doctype - see couchdb.Doc interfaces
func (m *Manifest) DocType() string { return consts.Manifests }

// SetID is used to change the file identifier - see couchdb.Doc
// interface
func (m *Manifest) SetID(id string) {}

// SetRev is used to change the file revision - see couchdb.Doc
// interface
func (m *Manifest) SetRev(rev string) { m.ManRev = rev }

// SelfLink is used to generate a JSON-API link for the file - see
// jsonapi.Object interface
func (m *Manifest) SelfLink() string { return "/apps/" + m.Slug }

// Relationships is used to generate the parent relationship in JSON-API format
// - see jsonapi.Object interface
func (m *Manifest) Relationships() jsonapi.RelationshipMap {
	return jsonapi.RelationshipMap{}
}

// Included is part of the jsonapi.Object interface
func (m *Manifest) Included() []jsonapi.Object {
	return []jsonapi.Object{}
}

// List returns the list of installed applications.
//
// TODO: pagination
func List(db couchdb.Database) ([]*Manifest, error) {
	var docs []*Manifest
	req := &couchdb.AllDocsRequest{Limit: 100}
	err := couchdb.GetAllDocs(db, consts.Manifests, req, &docs)
	if err != nil {
		return nil, err
	}
	return docs, nil
}

// GetBySlug returns an app identified by its slug
func GetBySlug(db couchdb.Database, slug string) (*Manifest, error) {
	man := &Manifest{}
	err := couchdb.GetDoc(db, consts.Manifests, consts.Manifests+"/"+slug, man)
	if err != nil {
		return nil, err
	}
	return man, nil
}

// FindRoute takes a path, returns the route which matches the best,
// and the part that remains unmatched
func (m *Manifest) FindRoute(vpath string) (Route, string) {
	parts := strings.Split(vpath, "/")
	lenParts := len(parts)

	var best Route
	rest := ""
	specificity := 0
	for key, ctx := range m.Routes {
		var keys []string
		if key == "/" {
			keys = []string{""}
		} else {
			keys = strings.Split(key, "/")
		}
		count := len(keys)
		if count > lenParts || count < specificity {
			continue
		}
		if routeMatches(parts, keys) {
			specificity = count
			best = ctx
			rest = path.Join(parts[count:]...)
		}
	}

	return best, rest
}

func routeMatches(path, ctx []string) bool {
	for i, part := range ctx {
		if path[i] != part {
			return false
		}
	}
	return true
}

// BuildToken is used to build a token to identify the app for requests made to
// the stack
func (m *Manifest) BuildToken(i *instance.Instance) string {
	token, err := crypto.NewJWT(i.SessionSecret, permissions.Claims{
		StandardClaims: jwt.StandardClaims{
			Audience: permissions.AppAudience,
			Issuer:   i.Domain,
			IssuedAt: crypto.Timestamp(),
			Subject:  m.Slug,
		},
		Scope: "", // TODO scope
	})
	if err != nil {
		return ""
	}
	return token
}
<commit_msg>make tests pass while waiting for actual permissions<commit_after>package apps

import (
	"path"
	"strings"

	"github.com/cozy/cozy-stack/pkg/consts"
	"github.com/cozy/cozy-stack/pkg/couchdb"
	"github.com/cozy/cozy-stack/pkg/crypto"
	"github.com/cozy/cozy-stack/pkg/instance"
	"github.com/cozy/cozy-stack/pkg/permissions"
	"github.com/cozy/cozy-stack/web/jsonapi"
	jwt "gopkg.in/dgrijalva/jwt-go.v3"
)

const (
	// ManifestMaxSize is the manifest maximum size
	ManifestMaxSize = 2 << (2 * 10) // 2MB
	// ManifestFilename is the name of the manifest at the root of the
	// application directory
	ManifestFilename = "manifest.webapp"
)

// State is the state of the application
type State string

const (
	// Available state
	Available State = "available"
	// Installing state
	Installing = "installing"
	// Upgrading state
	Upgrading = "upgrading"
	// Uninstalling state
	Uninstalling = "uninstalling"
	// Errored state
	Errored = "errored"
	// Ready state
	Ready = "ready"
)

// Some well known slugs
const (
	OnboardingSlug = "onboarding"
	HomeSlug       = "home"
)

// Access is a string representing the access permission level. It can
// either be read, write or readwrite.
type Access string

// Permissions is a map of key, a description and an access level.
type Permissions map[string]struct {
	Description string `json:"description"`
	Access      Access `json:"access"`
}

// Route is a struct to serve a folder inside an app
type Route struct {
	Folder string `json:"folder"`
	Index  string `json:"index"`
	Public bool   `json:"public"`
}

// NotFound returns true for a blank route (ie not found by FindRoute)
func (c *Route) NotFound() bool { return c.Folder == "" }

// Routes are a map for routing inside an application.
type Routes map[string]Route

// Developer is the name and url of a developer.
type Developer struct {
	Name string `json:"name"`
	URL  string `json:"url,omitempty"`
}

// Manifest contains all the informations about an application.
type Manifest struct {
	ManRev string `json:"_rev,omitempty"` // Manifest revision

	Name        string     `json:"name"`
	Slug        string     `json:"slug"`
	Source      string     `json:"source"`
	State       State      `json:"state"`
	Error       string     `json:"error,omitempty"`
	Icon        string     `json:"icon"`
	Description string     `json:"description"`
	Developer   *Developer `json:"developer"`

	DefaultLocale string `json:"default_locale"`
	Locales       map[string]struct {
		Description string `json:"description"`
	} `json:"locales"`

	Version     string       `json:"version"`
	License     string       `json:"license"`
	Permissions *Permissions `json:"permissions"`
	Routes      Routes       `json:"routes"`
}

// ID returns the manifest identifier - see couchdb.Doc interface
func (m *Manifest) ID() string {
	return consts.Manifests + "/" + m.Slug
}

// Rev return the manifest revision - see couchdb.Doc interface
func (m *Manifest) Rev() string { return m.ManRev }

// DocType returns the manifest doctype - see couchdb.Doc interfaces
func (m *Manifest) DocType() string { return consts.Manifests }

// SetID is used to change the file identifier - see couchdb.Doc
// interface
func (m *Manifest) SetID(id string) {}

// SetRev is used to change the file revision - see couchdb.Doc
// interface
func (m *Manifest) SetRev(rev string) { m.ManRev = rev }

// SelfLink is used to generate a JSON-API link for the file - see
// jsonapi.Object interface
func (m *Manifest) SelfLink() string { return "/apps/" + m.Slug }

// Relationships is used to generate the parent relationship in JSON-API format
// - see jsonapi.Object interface
func (m *Manifest) Relationships() jsonapi.RelationshipMap {
	return jsonapi.RelationshipMap{}
}

// Included is part of the jsonapi.Object interface
func (m *Manifest) Included() []jsonapi.Object {
	return []jsonapi.Object{}
}

// List returns the list of installed applications.
//
// TODO: pagination
func List(db couchdb.Database) ([]*Manifest, error) {
	var docs []*Manifest
	req := &couchdb.AllDocsRequest{Limit: 100}
	err := couchdb.GetAllDocs(db, consts.Manifests, req, &docs)
	if err != nil {
		return nil, err
	}
	return docs, nil
}

// GetBySlug returns an app identified by its slug
func GetBySlug(db couchdb.Database, slug string) (*Manifest, error) {
	man := &Manifest{}
	err := couchdb.GetDoc(db, consts.Manifests, consts.Manifests+"/"+slug, man)
	if err != nil {
		return nil, err
	}
	return man, nil
}

// FindRoute takes a path, returns the route which matches the best,
// and the part that remains unmatched
func (m *Manifest) FindRoute(vpath string) (Route, string) {
	parts := strings.Split(vpath, "/")
	lenParts := len(parts)

	var best Route
	rest := ""
	specificity := 0
	for key, ctx := range m.Routes {
		var keys []string
		if key == "/" {
			keys = []string{""}
		} else {
			keys = strings.Split(key, "/")
		}
		count := len(keys)
		if count > lenParts || count < specificity {
			continue
		}
		if routeMatches(parts, keys) {
			specificity = count
			best = ctx
			rest = path.Join(parts[count:]...)
		}
	}

	return best, rest
}

func routeMatches(path, ctx []string) bool {
	for i, part := range ctx {
		if path[i] != part {
			return false
		}
	}
	return true
}

// BuildToken is used to build a token to identify the app for requests made to
// the stack
func (m *Manifest) BuildToken(i *instance.Instance) string {
	token, err := crypto.NewJWT(i.SessionSecret, permissions.Claims{
		StandardClaims: jwt.StandardClaims{
			Audience: permissions.AppAudience,
			Issuer:   i.Domain,
			IssuedAt: crypto.Timestamp(),
			Subject:  m.Slug,
		},
		Scope: "io.cozy._all", // TODO scope
	})
	if err != nil {
		return ""
	}
	return token
}
<|endoftext|>


<commit_before>package jobs

import (
	"bytes"
	"encoding/json"
	"fmt"
	"time"
)

const (
	// Queued state
	Queued State = "queued"
	// Running state
	Running = "running"
	// Errored state
	Errored = "errored"
)

const (
	// JSONEncoding is a JSON encoding message type
	JSONEncoding = "json"
)

type (
	// Queue interface is used to represent a asynchronous queue of jobs from
	// which it is possible to enqueue and consume jobs.
	Queue interface {
		Enqueue(*Job) error
		Consume() (*Job, error)
		Len() int
		Close()
	}

	// Broker interface is used to represent a job broker associated to a
	// particular domain. A broker can be used to create jobs that are pushed in
	// the job system.
	Broker interface {
		Domain() string
		PushJob(*JobRequest) (*Job, error)
	}

	// State represent the state of a job.
	State string

	// Message is a byte slice representing an encoded job message type.
	Message struct {
		Data []byte
		Type string
	}

	// Job struct encapsulates all the parameters of a job.
	Job struct {
		ID         string    `json:"id"`
		WorkerType string    `json:"worker_type"`
		Message    *Message  `json:"-"`
		State      State     `json:"state"`
		QueuedAt   time.Time `json:"queued_at"`
	}

	// JobRequest struct is used to represent a new job request.
	JobRequest struct {
		WorkerType string
		Message    *Message
	}
)

// NewMessage returns a new Message encoded in the specified format.
func NewMessage(enc string, data interface{}) (*Message, error) {
	var b []byte
	var err error
	switch enc {
	case JSONEncoding:
		b, err = json.Marshal(data)
	default:
		err = ErrUnknownMessageType
	}
	if err != nil {
		return nil, err
	}
	return &Message{
		Type: enc,
		Data: b,
	}, nil
}

// Unmarshal can be used to unmarshal the encoded message value in the
// specified interface's type.
func (m *Message) Unmarshal(msg interface{}) error {
	switch m.Type {
	case JSONEncoding:
		return json.NewDecoder(bytes.NewReader(m.Data)).Decode(msg)
	default:
		return ErrUnknownMessageType
	}
}

func makeQueueName(domain, workerType string) string {
	return fmt.Sprintf("%s/%s", domain, workerType)
}
<commit_msg>Remove dead code<commit_after>package jobs

import (
	"bytes"
	"encoding/json"
	"time"
)

const (
	// Queued state
	Queued State = "queued"
	// Running state
	Running = "running"
	// Errored state
	Errored = "errored"
)

const (
	// JSONEncoding is a JSON encoding message type
	JSONEncoding = "json"
)

type (
	// Queue interface is used to represent a asynchronous queue of jobs from
	// which it is possible to enqueue and consume jobs.
	Queue interface {
		Enqueue(*Job) error
		Consume() (*Job, error)
		Len() int
		Close()
	}

	// Broker interface is used to represent a job broker associated to a
	// particular domain. A broker can be used to create jobs that are pushed in
	// the job system.
	Broker interface {
		Domain() string
		PushJob(*JobRequest) (*Job, error)
	}

	// State represent the state of a job.
	State string

	// Message is a byte slice representing an encoded job message type.
	Message struct {
		Data []byte
		Type string
	}

	// Job struct encapsulates all the parameters of a job.
	Job struct {
		ID         string    `json:"id"`
		WorkerType string    `json:"worker_type"`
		Message    *Message  `json:"-"`
		State      State     `json:"state"`
		QueuedAt   time.Time `json:"queued_at"`
	}

	// JobRequest struct is used to represent a new job request.
	JobRequest struct {
		WorkerType string
		Message    *Message
	}
)

// NewMessage returns a new Message encoded in the specified format.
func NewMessage(enc string, data interface{}) (*Message, error) {
	var b []byte
	var err error
	switch enc {
	case JSONEncoding:
		b, err = json.Marshal(data)
	default:
		err = ErrUnknownMessageType
	}
	if err != nil {
		return nil, err
	}
	return &Message{
		Type: enc,
		Data: b,
	}, nil
}

// Unmarshal can be used to unmarshal the encoded message value in the
// specified interface's type.
func (m *Message) Unmarshal(msg interface{}) error {
	switch m.Type {
	case JSONEncoding:
		return json.NewDecoder(bytes.NewReader(m.Data)).Decode(msg)
	default:
		return ErrUnknownMessageType
	}
}
<|endoftext|>


<commit_before>package pkg

import (
	"encoding/json"
	"net/http"
)

func WriteJSON(rw http.ResponseWriter, data interface{}) {
	writeJSON(rw, data, http.StatusOK)
}

func WriteCreatedJSON(rw http.ResponseWriter, url string, data interface{}) {
	rw.Header().Add("Location", url)
	writeJSON(rw, data, http.StatusCreated)
}

func writeJSON(rw http.ResponseWriter, data interface{}, code int) {
	js, err := json.Marshal(data)

	if err != nil {
		http.Error(rw, err.Error(), http.StatusInternalServerError)
		return
	}

	rw.Header().Set("Content-Type", "application/json")
	rw.WriteHeader(code)
	rw.Write(js)

}
<commit_msg>pkg: added support for indent json<commit_after>package pkg

import (
	"encoding/json"
	"net/http"
)

func WriteIndentJSON(rw http.ResponseWriter, data interface{}) {
	js, err := json.MarshalIndent(data, "", "\t")
	if err != nil {
		http.Error(rw, err.Error(), http.StatusInternalServerError)
		return
	}

	writeJSON(rw, js, http.StatusOK)
}

func WriteJSON(rw http.ResponseWriter, data interface{}) {
	js, err := json.Marshal(data)
	if err != nil {
		http.Error(rw, err.Error(), http.StatusInternalServerError)
		return
	}

	writeJSON(rw, js, http.StatusOK)
}

func WriteCreatedJSON(rw http.ResponseWriter, url string, data interface{}) {
	js, err := json.Marshal(data)
	if err != nil {
		http.Error(rw, err.Error(), http.StatusInternalServerError)
		return
	}

	rw.Header().Add("Location", url)
	writeJSON(rw, js, http.StatusCreated)
}

func writeJSON(rw http.ResponseWriter, js []byte, code int) {

	rw.Header().Set("Content-Type", "application/json")
	rw.WriteHeader(code)
	rw.Write(js)
}
<|endoftext|>


<commit_before>// Copyright 2009 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.

// +build darwin dragonfly freebsd linux netbsd openbsd solaris

package unix

import (
	"bytes"
	"runtime"
	"sync"
	"syscall"
	"unsafe"
)

var (
	Stdin  = 0
	Stdout = 1
	Stderr = 2
)

const (
	darwin64Bit    = runtime.GOOS == "darwin" && sizeofPtr == 8
	dragonfly64Bit = runtime.GOOS == "dragonfly" && sizeofPtr == 8
	netbsd32Bit    = runtime.GOOS == "netbsd" && sizeofPtr == 4
	solaris64Bit   = runtime.GOOS == "solaris" && sizeofPtr == 8
)

// Do the interface allocations only once for common
// Errno values.
var (
	errEAGAIN error = syscall.EAGAIN
	errEINVAL error = syscall.EINVAL
	errENOENT error = syscall.ENOENT
)

// errnoErr returns common boxed Errno values, to prevent
// allocations at runtime.
func errnoErr(e syscall.Errno) error {
	switch e {
	case 0:
		return nil
	case EAGAIN:
		return errEAGAIN
	case EINVAL:
		return errEINVAL
	case ENOENT:
		return errENOENT
	}
	return e
}

// clen returns the index of the first NULL byte in n or len(n) if n contains no NULL byte.
func clen(n []byte) int {
	i := bytes.IndexByte(n, 0)
	if i == -1 {
		i = len(n)
	}
	return i
}

// Mmap manager, for use by operating system-specific implementations.

type mmapper struct {
	sync.Mutex
	active map[*byte][]byte // active mappings; key is last byte in mapping
	mmap   func(addr, length uintptr, prot, flags, fd int, offset int64) (uintptr, error)
	munmap func(addr uintptr, length uintptr) error
}

func (m *mmapper) Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, err error) {
	if length <= 0 {
		return nil, EINVAL
	}

	// Map the requested memory.
	addr, errno := m.mmap(0, uintptr(length), prot, flags, fd, offset)
	if errno != nil {
		return nil, errno
	}

	// Slice memory layout
	var sl = struct {
		addr uintptr
		len  int
		cap  int
	}{addr, length, length}

	// Use unsafe to turn sl into a []byte.
	b := *(*[]byte)(unsafe.Pointer(&sl))

	// Register mapping in m and return it.
	p := &b[cap(b)-1]
	m.Lock()
	defer m.Unlock()
	m.active[p] = b
	return b, nil
}

func (m *mmapper) Munmap(data []byte) (err error) {
	if len(data) == 0 || len(data) != cap(data) {
		return EINVAL
	}

	// Find the base of the mapping.
	p := &data[cap(data)-1]
	m.Lock()
	defer m.Unlock()
	b := m.active[p]
	if b == nil || &b[0] != &data[0] {
		return EINVAL
	}

	// Unmap the memory and update m.
	if errno := m.munmap(uintptr(unsafe.Pointer(&b[0])), uintptr(len(b))); errno != nil {
		return errno
	}
	delete(m.active, p)
	return nil
}

func Read(fd int, p []byte) (n int, err error) {
	n, err = read(fd, p)
	if raceenabled {
		if n > 0 {
			raceWriteRange(unsafe.Pointer(&p[0]), n)
		}
		if err == nil {
			raceAcquire(unsafe.Pointer(&ioSync))
		}
	}
	return
}

func Write(fd int, p []byte) (n int, err error) {
	if raceenabled {
		raceReleaseMerge(unsafe.Pointer(&ioSync))
	}
	n, err = write(fd, p)
	if raceenabled && n > 0 {
		raceReadRange(unsafe.Pointer(&p[0]), n)
	}
	return
}

// For testing: clients can set this flag to force
// creation of IPv6 sockets to return EAFNOSUPPORT.
var SocketDisableIPv6 bool

// Sockaddr represents a socket address.
type Sockaddr interface {
	sockaddr() (ptr unsafe.Pointer, len _Socklen, err error) // lowercase; only we can define Sockaddrs
}

// SockaddrInet4 implements the Sockaddr interface for AF_INET type sockets.
type SockaddrInet4 struct {
	Port int
	Addr [4]byte
	raw  RawSockaddrInet4
}

// SockaddrInet6 implements the Sockaddr interface for AF_INET6 type sockets.
type SockaddrInet6 struct {
	Port   int
	ZoneId uint32
	Addr   [16]byte
	raw    RawSockaddrInet6
}

// SockaddrUnix implements the Sockaddr interface for AF_UNIX type sockets.
type SockaddrUnix struct {
	Name string
	raw  RawSockaddrUnix
}

func Bind(fd int, sa Sockaddr) (err error) {
	ptr, n, err := sa.sockaddr()
	if err != nil {
		return err
	}
	return bind(fd, ptr, n)
}

func Connect(fd int, sa Sockaddr) (err error) {
	ptr, n, err := sa.sockaddr()
	if err != nil {
		return err
	}
	return connect(fd, ptr, n)
}

func Getpeername(fd int) (sa Sockaddr, err error) {
	var rsa RawSockaddrAny
	var len _Socklen = SizeofSockaddrAny
	if err = getpeername(fd, &rsa, &len); err != nil {
		return
	}
	return anyToSockaddr(&rsa)
}

func GetsockoptInt(fd, level, opt int) (value int, err error) {
	var n int32
	vallen := _Socklen(4)
	err = getsockopt(fd, level, opt, unsafe.Pointer(&n), &vallen)
	return int(n), err
}

func Recvfrom(fd int, p []byte, flags int) (n int, from Sockaddr, err error) {
	var rsa RawSockaddrAny
	var len _Socklen = SizeofSockaddrAny
	if n, err = recvfrom(fd, p, flags, &rsa, &len); err != nil {
		return
	}
	if rsa.Addr.Family != AF_UNSPEC {
		from, err = anyToSockaddr(&rsa)
	}
	return
}

func Sendto(fd int, p []byte, flags int, to Sockaddr) (err error) {
	ptr, n, err := to.sockaddr()
	if err != nil {
		return err
	}
	return sendto(fd, p, flags, ptr, n)
}

func SetsockoptByte(fd, level, opt int, value byte) (err error) {
	return setsockopt(fd, level, opt, unsafe.Pointer(&value), 1)
}

func SetsockoptInt(fd, level, opt int, value int) (err error) {
	var n = int32(value)
	return setsockopt(fd, level, opt, unsafe.Pointer(&n), 4)
}

func SetsockoptInet4Addr(fd, level, opt int, value [4]byte) (err error) {
	return setsockopt(fd, level, opt, unsafe.Pointer(&value[0]), 4)
}

func SetsockoptIPMreq(fd, level, opt int, mreq *IPMreq) (err error) {
	return setsockopt(fd, level, opt, unsafe.Pointer(mreq), SizeofIPMreq)
}

func SetsockoptIPv6Mreq(fd, level, opt int, mreq *IPv6Mreq) (err error) {
	return setsockopt(fd, level, opt, unsafe.Pointer(mreq), SizeofIPv6Mreq)
}

func SetsockoptICMPv6Filter(fd, level, opt int, filter *ICMPv6Filter) error {
	return setsockopt(fd, level, opt, unsafe.Pointer(filter), SizeofICMPv6Filter)
}

func SetsockoptLinger(fd, level, opt int, l *Linger) (err error) {
	return setsockopt(fd, level, opt, unsafe.Pointer(l), SizeofLinger)
}

func SetsockoptString(fd, level, opt int, s string) (err error) {
	return setsockopt(fd, level, opt, unsafe.Pointer(&[]byte(s)[0]), uintptr(len(s)))
}

func SetsockoptTimeval(fd, level, opt int, tv *Timeval) (err error) {
	return setsockopt(fd, level, opt, unsafe.Pointer(tv), unsafe.Sizeof(*tv))
}

func Socket(domain, typ, proto int) (fd int, err error) {
	if domain == AF_INET6 && SocketDisableIPv6 {
		return -1, EAFNOSUPPORT
	}
	fd, err = socket(domain, typ, proto)
	return
}

func Socketpair(domain, typ, proto int) (fd [2]int, err error) {
	var fdx [2]int32
	err = socketpair(domain, typ, proto, &fdx)
	if err == nil {
		fd[0] = int(fdx[0])
		fd[1] = int(fdx[1])
	}
	return
}

func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
	if raceenabled {
		raceReleaseMerge(unsafe.Pointer(&ioSync))
	}
	return sendfile(outfd, infd, offset, count)
}

var ioSync int64

func CloseOnExec(fd int) { fcntl(fd, F_SETFD, FD_CLOEXEC) }

func SetNonblock(fd int, nonblocking bool) (err error) {
	flag, err := fcntl(fd, F_GETFL, 0)
	if err != nil {
		return err
	}
	if nonblocking {
		flag |= O_NONBLOCK
	} else {
		flag &= ^O_NONBLOCK
	}
	_, err = fcntl(fd, F_SETFL, flag)
	return err
}

// Exec calls execve(2), which replaces the calling executable in the process
// tree. argv0 should be the full path to an executable ("/bin/ls") and the
// executable name should also be the first argument in argv (["ls", "-l"]).
// envv are the environment variables that should be passed to the new
// process (["USER=go", "PWD=/tmp"]).
func Exec(argv0 string, argv []string, envv []string) error {
	return syscall.Exec(argv0, argv, envv)
}
<commit_msg>unix: add GetsockoptLinger and GetsockoptTimeval<commit_after>// Copyright 2009 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.

// +build darwin dragonfly freebsd linux netbsd openbsd solaris

package unix

import (
	"bytes"
	"runtime"
	"sync"
	"syscall"
	"unsafe"
)

var (
	Stdin  = 0
	Stdout = 1
	Stderr = 2
)

const (
	darwin64Bit    = runtime.GOOS == "darwin" && sizeofPtr == 8
	dragonfly64Bit = runtime.GOOS == "dragonfly" && sizeofPtr == 8
	netbsd32Bit    = runtime.GOOS == "netbsd" && sizeofPtr == 4
	solaris64Bit   = runtime.GOOS == "solaris" && sizeofPtr == 8
)

// Do the interface allocations only once for common
// Errno values.
var (
	errEAGAIN error = syscall.EAGAIN
	errEINVAL error = syscall.EINVAL
	errENOENT error = syscall.ENOENT
)

// errnoErr returns common boxed Errno values, to prevent
// allocations at runtime.
func errnoErr(e syscall.Errno) error {
	switch e {
	case 0:
		return nil
	case EAGAIN:
		return errEAGAIN
	case EINVAL:
		return errEINVAL
	case ENOENT:
		return errENOENT
	}
	return e
}

// clen returns the index of the first NULL byte in n or len(n) if n contains no NULL byte.
func clen(n []byte) int {
	i := bytes.IndexByte(n, 0)
	if i == -1 {
		i = len(n)
	}
	return i
}

// Mmap manager, for use by operating system-specific implementations.

type mmapper struct {
	sync.Mutex
	active map[*byte][]byte // active mappings; key is last byte in mapping
	mmap   func(addr, length uintptr, prot, flags, fd int, offset int64) (uintptr, error)
	munmap func(addr uintptr, length uintptr) error
}

func (m *mmapper) Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, err error) {
	if length <= 0 {
		return nil, EINVAL
	}

	// Map the requested memory.
	addr, errno := m.mmap(0, uintptr(length), prot, flags, fd, offset)
	if errno != nil {
		return nil, errno
	}

	// Slice memory layout
	var sl = struct {
		addr uintptr
		len  int
		cap  int
	}{addr, length, length}

	// Use unsafe to turn sl into a []byte.
	b := *(*[]byte)(unsafe.Pointer(&sl))

	// Register mapping in m and return it.
	p := &b[cap(b)-1]
	m.Lock()
	defer m.Unlock()
	m.active[p] = b
	return b, nil
}

func (m *mmapper) Munmap(data []byte) (err error) {
	if len(data) == 0 || len(data) != cap(data) {
		return EINVAL
	}

	// Find the base of the mapping.
	p := &data[cap(data)-1]
	m.Lock()
	defer m.Unlock()
	b := m.active[p]
	if b == nil || &b[0] != &data[0] {
		return EINVAL
	}

	// Unmap the memory and update m.
	if errno := m.munmap(uintptr(unsafe.Pointer(&b[0])), uintptr(len(b))); errno != nil {
		return errno
	}
	delete(m.active, p)
	return nil
}

func Read(fd int, p []byte) (n int, err error) {
	n, err = read(fd, p)
	if raceenabled {
		if n > 0 {
			raceWriteRange(unsafe.Pointer(&p[0]), n)
		}
		if err == nil {
			raceAcquire(unsafe.Pointer(&ioSync))
		}
	}
	return
}

func Write(fd int, p []byte) (n int, err error) {
	if raceenabled {
		raceReleaseMerge(unsafe.Pointer(&ioSync))
	}
	n, err = write(fd, p)
	if raceenabled && n > 0 {
		raceReadRange(unsafe.Pointer(&p[0]), n)
	}
	return
}

// For testing: clients can set this flag to force
// creation of IPv6 sockets to return EAFNOSUPPORT.
var SocketDisableIPv6 bool

// Sockaddr represents a socket address.
type Sockaddr interface {
	sockaddr() (ptr unsafe.Pointer, len _Socklen, err error) // lowercase; only we can define Sockaddrs
}

// SockaddrInet4 implements the Sockaddr interface for AF_INET type sockets.
type SockaddrInet4 struct {
	Port int
	Addr [4]byte
	raw  RawSockaddrInet4
}

// SockaddrInet6 implements the Sockaddr interface for AF_INET6 type sockets.
type SockaddrInet6 struct {
	Port   int
	ZoneId uint32
	Addr   [16]byte
	raw    RawSockaddrInet6
}

// SockaddrUnix implements the Sockaddr interface for AF_UNIX type sockets.
type SockaddrUnix struct {
	Name string
	raw  RawSockaddrUnix
}

func Bind(fd int, sa Sockaddr) (err error) {
	ptr, n, err := sa.sockaddr()
	if err != nil {
		return err
	}
	return bind(fd, ptr, n)
}

func Connect(fd int, sa Sockaddr) (err error) {
	ptr, n, err := sa.sockaddr()
	if err != nil {
		return err
	}
	return connect(fd, ptr, n)
}

func Getpeername(fd int) (sa Sockaddr, err error) {
	var rsa RawSockaddrAny
	var len _Socklen = SizeofSockaddrAny
	if err = getpeername(fd, &rsa, &len); err != nil {
		return
	}
	return anyToSockaddr(&rsa)
}

func GetsockoptInt(fd, level, opt int) (value int, err error) {
	var n int32
	vallen := _Socklen(4)
	err = getsockopt(fd, level, opt, unsafe.Pointer(&n), &vallen)
	return int(n), err
}

func GetsockoptLinger(fd, level, opt int) (*Linger, error) {
	var linger Linger
	vallen := _Socklen(SizeofLinger)
	err := getsockopt(fd, level, opt, unsafe.Pointer(&linger), &vallen)
	return &linger, err
}

func GetsockoptTimeval(fd, level, opt int) (*Timeval, error) {
	var tv Timeval
	vallen := _Socklen(unsafe.Sizeof(tv))
	err := getsockopt(fd, level, opt, unsafe.Pointer(&tv), &vallen)
	return &tv, err
}

func Recvfrom(fd int, p []byte, flags int) (n int, from Sockaddr, err error) {
	var rsa RawSockaddrAny
	var len _Socklen = SizeofSockaddrAny
	if n, err = recvfrom(fd, p, flags, &rsa, &len); err != nil {
		return
	}
	if rsa.Addr.Family != AF_UNSPEC {
		from, err = anyToSockaddr(&rsa)
	}
	return
}

func Sendto(fd int, p []byte, flags int, to Sockaddr) (err error) {
	ptr, n, err := to.sockaddr()
	if err != nil {
		return err
	}
	return sendto(fd, p, flags, ptr, n)
}

func SetsockoptByte(fd, level, opt int, value byte) (err error) {
	return setsockopt(fd, level, opt, unsafe.Pointer(&value), 1)
}

func SetsockoptInt(fd, level, opt int, value int) (err error) {
	var n = int32(value)
	return setsockopt(fd, level, opt, unsafe.Pointer(&n), 4)
}

func SetsockoptInet4Addr(fd, level, opt int, value [4]byte) (err error) {
	return setsockopt(fd, level, opt, unsafe.Pointer(&value[0]), 4)
}

func SetsockoptIPMreq(fd, level, opt int, mreq *IPMreq) (err error) {
	return setsockopt(fd, level, opt, unsafe.Pointer(mreq), SizeofIPMreq)
}

func SetsockoptIPv6Mreq(fd, level, opt int, mreq *IPv6Mreq) (err error) {
	return setsockopt(fd, level, opt, unsafe.Pointer(mreq), SizeofIPv6Mreq)
}

func SetsockoptICMPv6Filter(fd, level, opt int, filter *ICMPv6Filter) error {
	return setsockopt(fd, level, opt, unsafe.Pointer(filter), SizeofICMPv6Filter)
}

func SetsockoptLinger(fd, level, opt int, l *Linger) (err error) {
	return setsockopt(fd, level, opt, unsafe.Pointer(l), SizeofLinger)
}

func SetsockoptString(fd, level, opt int, s string) (err error) {
	return setsockopt(fd, level, opt, unsafe.Pointer(&[]byte(s)[0]), uintptr(len(s)))
}

func SetsockoptTimeval(fd, level, opt int, tv *Timeval) (err error) {
	return setsockopt(fd, level, opt, unsafe.Pointer(tv), unsafe.Sizeof(*tv))
}

func Socket(domain, typ, proto int) (fd int, err error) {
	if domain == AF_INET6 && SocketDisableIPv6 {
		return -1, EAFNOSUPPORT
	}
	fd, err = socket(domain, typ, proto)
	return
}

func Socketpair(domain, typ, proto int) (fd [2]int, err error) {
	var fdx [2]int32
	err = socketpair(domain, typ, proto, &fdx)
	if err == nil {
		fd[0] = int(fdx[0])
		fd[1] = int(fdx[1])
	}
	return
}

func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
	if raceenabled {
		raceReleaseMerge(unsafe.Pointer(&ioSync))
	}
	return sendfile(outfd, infd, offset, count)
}

var ioSync int64

func CloseOnExec(fd int) { fcntl(fd, F_SETFD, FD_CLOEXEC) }

func SetNonblock(fd int, nonblocking bool) (err error) {
	flag, err := fcntl(fd, F_GETFL, 0)
	if err != nil {
		return err
	}
	if nonblocking {
		flag |= O_NONBLOCK
	} else {
		flag &= ^O_NONBLOCK
	}
	_, err = fcntl(fd, F_SETFL, flag)
	return err
}

// Exec calls execve(2), which replaces the calling executable in the process
// tree. argv0 should be the full path to an executable ("/bin/ls") and the
// executable name should also be the first argument in argv (["ls", "-l"]).
// envv are the environment variables that should be passed to the new
// process (["USER=go", "PWD=/tmp"]).
func Exec(argv0 string, argv []string, envv []string) error {
	return syscall.Exec(argv0, argv, envv)
}
<|endoftext|>


<commit_before>package structs

import (
	"reflect"
	"strings"
)

// 将结构体转换为map[string]string{}，仅支持组合和普通一层结构体，对第二层结构体会直接忽略
func Struct2MapString(v interface{}, useTag string) (map[string]string, error) {
	pointer := reflect.Indirect(reflect.ValueOf(v))
	typer := pointer.Type()

	fieldNum := pointer.NumField()
	m := map[string]string{}

	for i := 0; i < fieldNum; i++ {
		field := pointer.Field(i)

		if !field.CanInterface() {
			continue
		}
		fieldT := typer.Field(i)

		// 如果是匿名 则需要扁平化
		if fieldT.Anonymous {
			mn, err := Struct2MapString(field.Interface(), useTag)
			if err != nil {
				return nil, err
			}
			for k, v := range mn {
				m[k] = v
			}
			continue
		}

		fieldName := fieldT.Name
		if useTag != "" {
			fieldName = fieldT.Tag.Get(useTag)
			if fieldName == "" {
				// 如果指定了tag 但是tag为空，则不处理这个字段
				continue
			}

			fieldName = strings.Split(fieldName, ",")[0]
		}

		switch field.Kind() {
		case reflect.Interface, reflect.Ptr, reflect.Array, reflect.Map, reflect.Slice:
		default:
			m[fieldName], _ = Interface2String(field.Interface(), false)
		}

	}
	return m, nil
}

func MapString2Struct(mapper map[string]string, obj interface{}, useTag string) (err error) {
	mapper2 := map[string]interface{}{}
	for k, v := range mapper {
		mapper2[k] = v
	}
	return Map2Struct(mapper2, obj, useTag)
}

// 将map将转换为struct，支持组合与嵌套
func Map2Struct(m map[string]interface{}, v interface{}, useTag string) (error) {
	pointer := indirect(reflect.ValueOf(v), false)
	typer := pointer.Type()

	fieldNum := pointer.NumField()

	for i := 0; i < fieldNum; i++ {
		field := pointer.Field(i)
		fieldT := typer.Field(i)
		// 如果是匿名 则需要扁平化
		if fieldT.Anonymous {
			// 本来开始是直接把field.interface甩进去的, 但是得到的field是!CanSet的,
			// 所以这里直接新建一个 直接赋值整个结构体
			value := reflect.New(field.Type())
			t := value.Interface()
			e := Map2Struct(m, t, useTag)
			if e != nil {
				return e
			}
			field.Set(value.Elem())
			continue
		}

		fieldName := fieldT.Name
		if useTag != "" {
			fieldName = fieldT.Tag.Get(useTag)
			if fieldName == "" {
				// 如果指定了tag 但是tag为空，则不处理这个字段
				continue
			}

			fieldName = strings.Split(fieldName, ",")[0]
		}

		if _, ok := m[fieldName]; !ok {
			continue
		}

		if !field.CanSet() {
			continue
		}

		switch field.Kind() {
		case reflect.Struct:
			// 嵌套结构体
			if m2, ok := m[fieldName].(map[string]interface{}); ok {
				vv := reflect.New(field.Type())
				err := Map2Struct(m2, vv.Interface(), useTag)
				if err != nil {
					return err
				}
				err = setValue(field, vv.Elem().Interface())
				if err != nil {
					return err
				}
			}
		case reflect.Slice, reflect.Array:
			// 数组
			vv := reflect.ValueOf(v)
			if vv.Kind() == reflect.Array || vv.Kind() == reflect.Slice {
				l := vv.Len()
				newV := reflect.MakeSlice(vv.Elem().Type(), l, l)
				for i := 0; i < l; i++ {
					// 这里只支持设置普通类型的setValue, 后面优化
					err := setValue(newV.Index(i), vv.Index(i).Interface())
					if err != nil {
						return err
					}
				}
				err := setValue(field, newV.Elem().Interface())
				if err != nil {
					return err
				}
			}
		}
		setValue(field, m[fieldName])
	}

	return nil
}
<commit_msg>fix bug<commit_after>package structs

import (
	"reflect"
	"strings"
)

// 将结构体转换为map[string]string{}，仅支持组合和普通一层结构体，对第二层结构体会直接忽略
func Struct2MapString(v interface{}, useTag string) (map[string]string, error) {
	pointer := reflect.Indirect(reflect.ValueOf(v))
	typer := pointer.Type()

	fieldNum := pointer.NumField()
	m := map[string]string{}

	for i := 0; i < fieldNum; i++ {
		field := pointer.Field(i)

		if !field.CanInterface() {
			continue
		}
		fieldT := typer.Field(i)

		// 如果是匿名 则需要扁平化
		if fieldT.Anonymous {
			mn, err := Struct2MapString(field.Interface(), useTag)
			if err != nil {
				return nil, err
			}
			for k, v := range mn {
				m[k] = v
			}
			continue
		}

		fieldName := fieldT.Name
		if useTag != "" {
			fieldName = fieldT.Tag.Get(useTag)
			if fieldName == "" {
				// 如果指定了tag 但是tag为空，则不处理这个字段
				continue
			}

			fieldName = strings.Split(fieldName, ",")[0]
		}

		switch field.Kind() {
		case reflect.Interface, reflect.Ptr, reflect.Array, reflect.Map, reflect.Slice:
		default:
			m[fieldName], _ = Interface2String(field.Interface(), false)
		}

	}
	return m, nil
}

func MapString2Struct(mapper map[string]string, obj interface{}, useTag string) (err error) {
	mapper2 := map[string]interface{}{}
	for k, v := range mapper {
		mapper2[k] = v
	}
	return Map2Struct(mapper2, obj, useTag)
}

// 将map将转换为struct，支持组合与嵌套
func Map2Struct(m map[string]interface{}, v interface{}, useTag string) (error) {
	return Map2StructValue(m, reflect.ValueOf(v), useTag)
}

func Map2StructValue(m map[string]interface{}, v reflect.Value, useTag string) (error) {
	pointer := indirect(v, false)
	typer := pointer.Type()

	fieldNum := pointer.NumField()

	for i := 0; i < fieldNum; i++ {
		field := pointer.Field(i)
		fieldT := typer.Field(i)
		// 如果是匿名 则需要扁平化
		if fieldT.Anonymous {
			e := Map2StructValue(m, field, useTag)
			if e != nil {
				return e
			}
			continue
		}

		fieldName := fieldT.Name
		if useTag != "" {
			fieldName = fieldT.Tag.Get(useTag)
			if fieldName == "" {
				// 如果指定了tag 但是tag为空，则不处理这个字段
				continue
			}

			fieldName = strings.Split(fieldName, ",")[0]
		}

		if _, ok := m[fieldName]; !ok {
			continue
		}

		if !field.CanSet() {
			continue
		}

		switch field.Kind() {
		case reflect.Struct:
			// 嵌套结构体
			if m2, ok := m[fieldName].(map[string]interface{}); ok {
				err := Map2StructValue(m2, field, useTag)
				if err != nil {
					return err
				}
			}
		case reflect.Slice:
			// 数组
			vv := reflect.ValueOf(m[fieldName])
			if vv.Kind() == reflect.Slice {
				l := vv.Len()

				newV := reflect.MakeSlice(field.Type(), l, l)
				for i := 0; i < l; i++ {
					// 这里只支持设置普通类型, 不支持结构体
					err := setValue(newV.Index(i), vv.Index(i).Interface())
					if err != nil {
						return err
					}
				}
				err := setValue(field, newV.Interface())
				if err != nil {
					return err
				}
			}
		default:
			setValue(field, m[fieldName])
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package utils

import (
	"encoding/json"
	"fmt"
	"github.com/dotcloud/docker/term"
	"io"
	"strings"
	"time"
)

type JSONError struct {
	Code    int    `json:"code,omitempty"`
	Message string `json:"message,omitempty"`
}

func (e *JSONError) Error() string {
	return e.Message
}

type JSONProgress struct {
	terminalFd uintptr
	Current    int   `json:"current,omitempty"`
	Total      int   `json:"total,omitempty"`
	Start      int64 `json:"start,omitempty"`
}

func (p *JSONProgress) String() string {
	var (
		width       = 200
		pbBox       string
		numbersBox  string
		timeLeftBox string
	)

	ws, err := term.GetWinsize(p.terminalFd)
	if err == nil {
		width = int(ws.Width)
	}

	if p.Current == 0 && p.Total == 0 {
		return ""
	}
	current := HumanSize(int64(p.Current))
	if p.Total == 0 {
		return fmt.Sprintf("%8v", current)
	}
	total := HumanSize(int64(p.Total))
	percentage := int(float64(p.Current)/float64(p.Total)*100) / 2
	if width > 110 {
		pbBox = fmt.Sprintf("[%s>%s] ", strings.Repeat("=", percentage), strings.Repeat(" ", 50-percentage))
	}
	numbersBox = fmt.Sprintf("%8v/%v", current, total)

	if p.Start > 0 {
		fromStart := time.Now().UTC().Sub(time.Unix(int64(p.Start), 0))
		perEntry := fromStart / time.Duration(p.Current)
		left := time.Duration(p.Total-p.Current) * perEntry
		left = (left / time.Second) * time.Second

		if width > 50 {
			timeLeftBox = " " + left.String()
		}
	}
	return pbBox + numbersBox + timeLeftBox
}

type JSONMessage struct {
	Status          string        `json:"status,omitempty"`
	Progress        *JSONProgress `json:"progressDetail,omitempty"`
	ProgressMessage string        `json:"progress,omitempty"` //deprecated
	ID              string        `json:"id,omitempty"`
	From            string        `json:"from,omitempty"`
	Time            int64         `json:"time,omitempty"`
	Error           *JSONError    `json:"errorDetail,omitempty"`
	ErrorMessage    string        `json:"error,omitempty"` //deprecated
}

func (jm *JSONMessage) Display(out io.Writer, isTerminal bool) error {
	if jm.Error != nil {
		if jm.Error.Code == 401 {
			return fmt.Errorf("Authentication is required.")
		}
		return jm.Error
	}
	var endl string
	if isTerminal {
		// <ESC>[2K = erase entire current line
		fmt.Fprintf(out, "%c[2K\r", 27)
		endl = "\r\n"
	}
	if jm.Time != 0 {
		fmt.Fprintf(out, "[%s] ", time.Unix(jm.Time, 0))
	}
	if jm.ID != "" {
		fmt.Fprintf(out, "%s: ", jm.ID)
	}
	if jm.From != "" {
		fmt.Fprintf(out, "(from %s) ", jm.From)
	}
	if jm.Progress != nil {
		fmt.Fprintf(out, "%s %s%s", jm.Status, jm.Progress.String(), endl)
	} else if jm.ProgressMessage != "" { //deprecated
		fmt.Fprintf(out, "%s %s%s", jm.Status, jm.ProgressMessage, endl)
	} else {
		fmt.Fprintf(out, "%s%s", jm.Status, endl)
	}
	return nil
}

func DisplayJSONMessagesStream(in io.Reader, out io.Writer, terminalFd uintptr, isTerminal bool) error {
	var (
		dec  = json.NewDecoder(in)
		ids  = make(map[string]int)
		diff = 0
	)
	for {
		var jm JSONMessage
		if err := dec.Decode(&jm); err != nil {
			if err == io.EOF {
				break
			}
			return err
		}

		if jm.Progress != nil {
			jm.Progress.terminalFd = terminalFd
		}
		if (jm.Progress != nil || jm.ProgressMessage != "") && jm.ID != "" {
			line, ok := ids[jm.ID]
			if !ok {
				line = len(ids)
				ids[jm.ID] = line
				fmt.Fprintf(out, "\n")
				diff = 0
			} else {
				diff = len(ids) - line
			}
			if isTerminal {
				// <ESC>[{diff}A = move cursor up diff rows
				fmt.Fprintf(out, "%c[%dA", 27, diff)
			}
		}
		err := jm.Display(out, isTerminal)
		if jm.ID != "" {
			if isTerminal {
				// <ESC>[{diff}B = move cursor down diff rows
				fmt.Fprintf(out, "%c[%dB", 27, diff)
			}
		}
		if err != nil {
			return err
		}
	}
	return nil
}
<commit_msg>fix jsonmessage<commit_after>package utils

import (
	"encoding/json"
	"fmt"
	"github.com/dotcloud/docker/term"
	"io"
	"strings"
	"time"
)

type JSONError struct {
	Code    int    `json:"code,omitempty"`
	Message string `json:"message,omitempty"`
}

func (e *JSONError) Error() string {
	return e.Message
}

type JSONProgress struct {
	terminalFd uintptr
	Current    int   `json:"current,omitempty"`
	Total      int   `json:"total,omitempty"`
	Start      int64 `json:"start,omitempty"`
}

func (p *JSONProgress) String() string {
	var (
		width       = 200
		pbBox       string
		numbersBox  string
		timeLeftBox string
	)

	ws, err := term.GetWinsize(p.terminalFd)
	if err == nil {
		width = int(ws.Width)
	}

	if p.Current <= 0 && p.Total <= 0 {
		return ""
	}
	current := HumanSize(int64(p.Current))
	if p.Total <= 0 {
		return fmt.Sprintf("%8v", current)
	}
	total := HumanSize(int64(p.Total))
	percentage := int(float64(p.Current)/float64(p.Total)*100) / 2
	if width > 110 {
		pbBox = fmt.Sprintf("[%s>%s] ", strings.Repeat("=", percentage), strings.Repeat(" ", 50-percentage))
	}
	numbersBox = fmt.Sprintf("%8v/%v", current, total)

	if p.Start > 0 {
		fromStart := time.Now().UTC().Sub(time.Unix(int64(p.Start), 0))
		perEntry := fromStart / time.Duration(p.Current)
		left := time.Duration(p.Total-p.Current) * perEntry
		left = (left / time.Second) * time.Second

		if width > 50 {
			timeLeftBox = " " + left.String()
		}
	}
	return pbBox + numbersBox + timeLeftBox
}

type JSONMessage struct {
	Status          string        `json:"status,omitempty"`
	Progress        *JSONProgress `json:"progressDetail,omitempty"`
	ProgressMessage string        `json:"progress,omitempty"` //deprecated
	ID              string        `json:"id,omitempty"`
	From            string        `json:"from,omitempty"`
	Time            int64         `json:"time,omitempty"`
	Error           *JSONError    `json:"errorDetail,omitempty"`
	ErrorMessage    string        `json:"error,omitempty"` //deprecated
}

func (jm *JSONMessage) Display(out io.Writer, isTerminal bool) error {
	if jm.Error != nil {
		if jm.Error.Code == 401 {
			return fmt.Errorf("Authentication is required.")
		}
		return jm.Error
	}
	var endl string
	if isTerminal {
		// <ESC>[2K = erase entire current line
		fmt.Fprintf(out, "%c[2K\r", 27)
		endl = "\r\n"
	}
	if jm.Time != 0 {
		fmt.Fprintf(out, "[%s] ", time.Unix(jm.Time, 0))
	}
	if jm.ID != "" {
		fmt.Fprintf(out, "%s: ", jm.ID)
	}
	if jm.From != "" {
		fmt.Fprintf(out, "(from %s) ", jm.From)
	}
	if jm.Progress != nil {
		fmt.Fprintf(out, "%s %s%s", jm.Status, jm.Progress.String(), endl)
	} else if jm.ProgressMessage != "" { //deprecated
		fmt.Fprintf(out, "%s %s%s", jm.Status, jm.ProgressMessage, endl)
	} else {
		fmt.Fprintf(out, "%s%s", jm.Status, endl)
	}
	return nil
}

func DisplayJSONMessagesStream(in io.Reader, out io.Writer, terminalFd uintptr, isTerminal bool) error {
	var (
		dec  = json.NewDecoder(in)
		ids  = make(map[string]int)
		diff = 0
	)
	for {
		var jm JSONMessage
		if err := dec.Decode(&jm); err != nil {
			if err == io.EOF {
				break
			}
			return err
		}

		if jm.Progress != nil {
			jm.Progress.terminalFd = terminalFd
		}
		if jm.Progress != nil || jm.ProgressMessage != "" {
			line, ok := ids[jm.ID]
			if !ok {
				line = len(ids)
				ids[jm.ID] = line
				fmt.Fprintf(out, "\n")
				diff = 0
			} else {
				diff = len(ids) - line
			}
			if isTerminal {
				// <ESC>[{diff}A = move cursor up diff rows
				fmt.Fprintf(out, "%c[%dA", 27, diff)
			}
		}
		err := jm.Display(out, isTerminal)
		if jm.ID != "" {
			if isTerminal {
				// <ESC>[{diff}B = move cursor down diff rows
				fmt.Fprintf(out, "%c[%dB", 27, diff)
			}
		}
		if err != nil {
			return err
		}
	}
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// 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 main

import (
	"fmt"
	"github.com/getkin/kin-openapi/openapi3"
	"io/ioutil"
	"log"
	"net/http"
	"strconv"
	"strings"
)

var identityToken string

// validateEndpoints tests all paths (represented by openapi3.Paths) with all HTTP methods and given response bodies
// and make sure they respond with the expected status code. Returns a success bool based on whether all the tests
// passed.
func validateEndpoints(paths *openapi3.Paths, identTok string) bool {
	identityToken = identTok

	success := true
	for endpoint, pathItem := range *paths {
		log.Printf("Testing %s endpoint\n", endpoint)
		success = success && validateEndpointOperation(pathItem.Connect, endpoint, http.MethodConnect)
		success = success && validateEndpointOperation(pathItem.Delete, endpoint, http.MethodDelete)
		success = success && validateEndpointOperation(pathItem.Get, endpoint, http.MethodGet)
		success = success && validateEndpointOperation(pathItem.Head, endpoint, http.MethodHead)
		success = success && validateEndpointOperation(pathItem.Options, endpoint, http.MethodOptions)
		success = success && validateEndpointOperation(pathItem.Patch, endpoint, http.MethodPatch)
		success = success && validateEndpointOperation(pathItem.Post, endpoint, http.MethodPost)
		success = success && validateEndpointOperation(pathItem.Put, endpoint, http.MethodPut)
		success = success && validateEndpointOperation(pathItem.Trace, endpoint, http.MethodTrace)
	}

	return success
}

// validateEndpointOperation validates a single endpoint and a single HTTP method, and ensures that the request --
// including the provided sample request body -- elicits the expected status code.
func validateEndpointOperation(operation *openapi3.Operation, endpoint string, httpMethod string) bool {
	if operation == nil {
		return true
	}
	log.Printf("%s %s\n", httpMethod, endpoint)

	if operation.RequestBody == nil {
		log.Println("Empty request body")
		reqBodyReader := strings.NewReader("")

		return makeTestRequest(httpMethod, endpoint, "", reqBodyReader, operation)
	}

	reqBodies := operation.RequestBody.Value.Content
	allTestsPassed := true
	for mimeType, mediaType := range reqBodies {
		reqBodyStr := mediaType.Example.(string)
		log.Printf("%s: %s", mimeType, reqBodyStr)

		reqBodyReader := strings.NewReader(reqBodyStr)
		allTestsPassed = allTestsPassed && makeTestRequest(httpMethod, endpoint, mimeType, reqBodyReader, operation)
	}

	return allTestsPassed
}

// makeTestRequest makes a request based on the . It returns a success bool based on whether the returned status code
// was included in the provided openapi3.Operation expected responses.
func makeTestRequest(httpMethod, endpoint, mimeType string, reqBodyReader *strings.Reader, operation *openapi3.Operation) bool {
	client := &http.DefaultClient

	req, err := http.NewRequest(httpMethod, s.cloudRunService.getURL()+endpoint, reqBodyReader)
	if err != nil {
		log.Panicf("Error creating http request: %v\n", err)
	}

	req.Header.Add("Authorization", "Bearer "+identityToken)
	req.Header.Add("content-type", mimeType)

	resp, err := (*client).Do(req)
	if err != nil {
		log.Panicf("Error executing http request: %v\n", err)
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Panicf("Error reading http response body: %v\n", err)
	}
	defer resp.Body.Close()

	statusCode := strconv.Itoa(resp.StatusCode)
	log.Printf("Status code: %s\n", statusCode)

	if val, ok := operation.Responses[statusCode]; ok {
		log.Printf("Response description: %s\n", *val.Value.Description)
		return true
	} else {
		log.Println("Unknown response description: FAIL")
		log.Println("Dumping response body")
		fmt.Println(string(body))
		return false
	}
}
<commit_msg>Update validateendpoints.go<commit_after>// Copyright 2020 Google LLC
//
// 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 main

import (
	"fmt"
	"github.com/getkin/kin-openapi/openapi3"
	"io/ioutil"
	"log"
	"net/http"
	"strconv"
	"strings"
)

var identityToken string

// validateEndpoints tests all paths (represented by openapi3.Paths) with all HTTP methods and given response bodies
// and make sure they respond with the expected status code. Returns a success bool based on whether all the tests
// passed.
func validateEndpoints(paths *openapi3.Paths, identTok string) bool {
	identityToken = identTok

	success := true
	for endpoint, pathItem := range *paths {
		log.Printf("Testing %s endpoint\n", endpoint)
		success = success && validateEndpointOperation(pathItem.Connect, endpoint, http.MethodConnect)
		success = success && validateEndpointOperation(pathItem.Delete, endpoint, http.MethodDelete)
		success = success && validateEndpointOperation(pathItem.Get, endpoint, http.MethodGet)
		success = success && validateEndpointOperation(pathItem.Head, endpoint, http.MethodHead)
		success = success && validateEndpointOperation(pathItem.Options, endpoint, http.MethodOptions)
		success = success && validateEndpointOperation(pathItem.Patch, endpoint, http.MethodPatch)
		success = success && validateEndpointOperation(pathItem.Post, endpoint, http.MethodPost)
		success = success && validateEndpointOperation(pathItem.Put, endpoint, http.MethodPut)
		success = success && validateEndpointOperation(pathItem.Trace, endpoint, http.MethodTrace)
	}

	return success
}

// validateEndpointOperation validates a single endpoint and a single HTTP method, and ensures that the request --
// including the provided sample request body -- elicits the expected status code.
func validateEndpointOperation(operation *openapi3.Operation, endpoint string, httpMethod string) bool {
	if operation == nil {
		return true
	}
	log.Printf("%s %s\n", httpMethod, endpoint)

	if operation.RequestBody == nil {
		log.Println("Empty request body")
		reqBodyReader := strings.NewReader("")

		return makeTestRequest(httpMethod, endpoint, "", reqBodyReader, operation)
	}

	reqBodies := operation.RequestBody.Value.Content
	allTestsPassed := true
	for mimeType, mediaType := range reqBodies {
		reqBodyStr := mediaType.Example.(string)
		log.Printf("%s: %s", mimeType, reqBodyStr)

		reqBodyReader := strings.NewReader(reqBodyStr)
		allTestsPassed = allTestsPassed && makeTestRequest(httpMethod, endpoint, mimeType, reqBodyReader, operation)
	}

	return allTestsPassed
}

// makeTestRequest returns a success bool based on whether the returned status code
// was included in the provided openapi3.Operation expected responses.
func makeTestRequest(httpMethod, endpoint, mimeType string, reqBodyReader *strings.Reader, operation *openapi3.Operation) bool {
	client := &http.DefaultClient

	req, err := http.NewRequest(httpMethod, s.cloudRunService.getURL()+endpoint, reqBodyReader)
	if err != nil {
		log.Panicf("Error creating http request: %v\n", err)
	}

	req.Header.Add("Authorization", "Bearer "+identityToken)
	req.Header.Add("content-type", mimeType)

	resp, err := (*client).Do(req)
	if err != nil {
		log.Panicf("Error executing http request: %v\n", err)
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Panicf("Error reading http response body: %v\n", err)
	}
	defer resp.Body.Close()

	statusCode := strconv.Itoa(resp.StatusCode)
	log.Printf("Status code: %s\n", statusCode)

	if val, ok := operation.Responses[statusCode]; ok {
		log.Printf("Response description: %s\n", *val.Value.Description)
		return true
	} else {
		log.Println("Unknown response description: FAIL")
		log.Println("Dumping response body")
		fmt.Println(string(body))
		return false
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 ThoughtWorks, Inc.

// This file is part of Gauge.

// Gauge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Gauge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Gauge.  If not, see <http://www.gnu.org/licenses/>.

package main

import (
	"fmt"
	"os"

	"github.com/getgauge/common"
	"github.com/getgauge/gauge/api"
	"github.com/getgauge/gauge/cmd"
	"github.com/getgauge/gauge/config"
	"github.com/getgauge/gauge/env"
	"github.com/getgauge/gauge/execution"
	"github.com/getgauge/gauge/execution/stream"
	"github.com/getgauge/gauge/filter"
	"github.com/getgauge/gauge/formatter"
	"github.com/getgauge/gauge/logger"
	"github.com/getgauge/gauge/order"
	"github.com/getgauge/gauge/plugin"
	"github.com/getgauge/gauge/plugin/install"
	"github.com/getgauge/gauge/projectInit"
	"github.com/getgauge/gauge/refactor"
	"github.com/getgauge/gauge/reporter"
	"github.com/getgauge/gauge/skel"
	"github.com/getgauge/gauge/track"
	"github.com/getgauge/gauge/util"
	"github.com/getgauge/gauge/validation"
	flag "github.com/getgauge/mflag"
)

// Command line flags
var daemonize = flag.Bool([]string{"-daemonize"}, false, "[DEPRECATED] Use gauge daemon.")
var gaugeVersion = flag.Bool([]string{"v", "-version", "version"}, false, "[DEPRECATED] Use gauge version")
var verbosity = flag.Bool([]string{"-verbose"}, false, "[DEPRECATED] Use gauge run -v")
var logLevel = flag.String([]string{"-log-level"}, "", "Set level of logging to debug, info, warning, error or critical")
var simpleConsoleOutput = flag.Bool([]string{"-simple-console"}, false, "[DEPRECATED] gauge run --simple-console")
var initialize = flag.String([]string{"-init"}, "", "[DEPRECATED] gauge init <template name>")
var installPlugin = flag.String([]string{"-install"}, "", "[DEPRECATED] Use gauge install <plugin name>")
var uninstallPlugin = flag.String([]string{"-uninstall"}, "", "[DEPRECATED] Use gauge uninstall <plugin name>")
var installAll = flag.Bool([]string{"-install-all"}, false, "[DEPRECATED] Use gauge install --all")
var update = flag.String([]string{"-update"}, "", "[DEPRECATED] Use gauge update <plugin name>")
var pluginVersion = flag.String([]string{"-plugin-version"}, "", "[DEPRECATED] Use gauge [install|uninstall] <plugin name> -v <version>")
var installZip = flag.String([]string{"-file", "f"}, "", "[DEPRECATED] Use gauge install <plugin name> -f <zip file>")
var currentEnv = flag.String([]string{"-env"}, "default", "[DEPRECATED] Use gauge run -e <env name>")
var addPlugin = flag.String([]string{"-add-plugin"}, "", "[DEPRECATED] Use gauge add <plugin name>")
var pluginArgs = flag.String([]string{"-plugin-args"}, "", "[DEPRECATED] Use gauge add <plugin name> --args <args>")
var specFilesToFormat = flag.String([]string{"-format"}, "", "[DEPRECATED] Use gauge format specs/")
var executeTags = flag.String([]string{"-tags"}, "", "[DEPRECATED] Use gauge run --tags tag1,tag2 specs")
var tableRows = flag.String([]string{"-table-rows"}, "", "[DEPRECATED] gauge run --table-rows <rows>")
var apiPort = flag.String([]string{"-api-port"}, "", "[DEPRECATED] Use gauge daemon 7777")
var refactorSteps = flag.String([]string{"-refactor"}, "", "[DEPRECATED] Use gauge refactor <old step> <new step>")
var parallel = flag.Bool([]string{"-parallel", "p"}, false, "[DEPRECATED] guage run -p specs/")
var numberOfExecutionStreams = flag.Int([]string{"n"}, util.NumberOfCores(), "[DEPRECATED] Use guage run -p -n specs/")
var distribute = flag.Int([]string{"g", "-group"}, -1, "[DEPRECATED] Use gauge -n 5 -g 1 specs/")
var workingDir = flag.String([]string{"-dir"}, ".", "Set the working directory for the current command, accepts a path relative to current directory.")
var strategy = flag.String([]string{"-strategy"}, "lazy", "[DEPRECATED] This usage will be removed soon. Parallel execution uses lazy strategy.")
var sort = flag.Bool([]string{"-sort", "s"}, false, "[DEPRECATED] Use gauge run -s specs")
var validate = flag.Bool([]string{"-validate", "-check"}, false, "[DEPRECATED] Use gauge validate specs")
var updateAll = flag.Bool([]string{"-update-all"}, false, "[DEPRECATED] Use gauge update -a")
var checkUpdates = flag.Bool([]string{"-check-updates"}, false, "[DEPRECATED] Use gauge update -c")
var listTemplates = flag.Bool([]string{"-list-templates"}, false, "[DEPRECATED] Use gauge list-templates")
var machineReadable = flag.Bool([]string{"-machine-readable"}, false, "[DEPRECATED] Use gauge version -m")
var runFailed = flag.Bool([]string{"-failed"}, false, "[DEPRECATED] Use gauge run --failed")
var docs = flag.String([]string{"-docs"}, "", "[DEPRECATED] Use gauge docs <plugin name> specs/")

func main() {
	if os.Getenv("GAUGE_ROOT") != "" {
		fmt.Println("[DEPRECATED] GAUGE_ROOT will be removed soon. Use GAUGE_HOME instead. Refer to documentation: https://docs.getgauge.io/faqs.html#what-is-gauge-home")
	}
	skel.CreateSkelFilesIfRequired()
	track.Init()
	exit, err := cmd.Parse()
	if err == nil {
		os.Exit(exit)
	}
	fmt.Println("[DEPRECATED] This usage will be removed soon. Run `gauge help --legacy` for more info.")
	flag.Parse()
	logger.Initialize(*logLevel)
	util.SetWorkingDir(*workingDir)
	initPackageFlags()
	validGaugeProject := true
	err = config.SetProjectRoot(flag.Args())
	if err != nil {
		validGaugeProject = false
	}
	if *runFailed {
		logger.Fatalf("Rerun is not supported via the old usage. Use 'gauge run -f'")
	}
	if e := env.LoadEnv(*currentEnv); e != nil {
		logger.Fatalf(e.Error())
	}
	logger.Debugf("Gauge Install ID: %s", config.UniqueID())
	if *gaugeVersion && *machineReadable {
		printJSONVersion()
	} else if *machineReadable {
		fmt.Println("flag '--machine-readable' can only be used with 'version' subcommand")
		os.Exit(1)
	} else if *gaugeVersion {
		printVersion()
	} else if *initialize != "" {
		track.ProjectInit(*initialize)
		projectInit.InitializeProject(*initialize)
	} else if *installZip != "" && *installPlugin != "" {
		track.Install(*installPlugin, true)
		install.HandleInstallResult(install.InstallPluginFromZipFile(*installZip, *installPlugin), *installPlugin, true)
	} else if *installPlugin != "" {
		track.Install(*installPlugin, false)
		install.HandleInstallResult(install.Plugin(*installPlugin, *pluginVersion), *installPlugin, true)
	} else if *uninstallPlugin != "" {
		track.UninstallPlugin(*uninstallPlugin)
		install.UninstallPlugin(*uninstallPlugin, *pluginVersion)
	} else if *installAll {
		track.InstallAll()
		install.AllPlugins()
	} else if *update != "" {
		track.Update(*update)
		install.HandleUpdateResult(install.Plugin(*update, *pluginVersion), *update, true)
	} else if *updateAll {
		track.UpdateAll()
		install.UpdatePlugins()
	} else if *checkUpdates {
		track.CheckUpdates()
		install.PrintUpdateInfoWithDetails()
	} else if *addPlugin != "" {
		track.AddPlugins(*addPlugin)
		install.AddPlugin(*addPlugin, *pluginArgs)
	} else if *listTemplates {
		track.ListTemplates()
		projectInit.ListTemplates()
	} else if validGaugeProject {
		var specDirs = []string{common.SpecsDirectoryName}
		if len(flag.Args()) > 0 {
			specDirs = flag.Args()
		}
		if *refactorSteps != "" {
			track.Refactor()
			refactorInit(flag.Args())
		} else if *daemonize {
			track.Daemon()
			stream.Start()
			api.RunInBackground(*apiPort, specDirs)
		} else if *specFilesToFormat != "" {
			track.Format()
			formatter.FormatSpecFilesIn(*specFilesToFormat)
		} else if *validate {
			track.Validation()
			validation.Validate(flag.Args())
		} else if *docs != "" {
			track.Docs(*docs)
			gaugeConnectionHandler := api.Start(specDirs)
			plugin.GenerateDoc(*docs, specDirs, gaugeConnectionHandler.ConnectionPortNumber())
		} else {
			track.Execution(*parallel, *executeTags != "", *sort, *simpleConsoleOutput, *verbosity, *strategy)
			exitCode := execution.ExecuteSpecs(specDirs)
			os.Exit(exitCode)
		}
	} else {
		logger.Fatalf(err.Error())
	}
}

func refactorInit(args []string) {
	if len(args) < 1 {
		logger.Fatalf("Flag needs at least two arguments: refactor\nUsage : gauge refactor <old step> <new step> [[spec directories]]")
	}
	var specDirs = []string{common.SpecsDirectoryName}
	if len(args) > 1 {
		specDirs = args[1:]
	}
	startChan := api.StartAPI(false)
	refactor.RefactorSteps(*refactorSteps, args[0], startChan, specDirs)
}

func printJSONVersion() {
	cmd.PrintJSONVersion()
}

func printVersion() {
	cmd.PrintVersion()
}

func initPackageFlags() {
	if *parallel {
		*simpleConsoleOutput = true
		reporter.IsParallel = true
	}
	reporter.SimpleConsoleOutput = *simpleConsoleOutput
	reporter.Verbose = *verbosity
	execution.ExecuteTags = *executeTags
	execution.SetTableRows(*tableRows)
	validation.TableRows = *tableRows
	execution.NumberOfExecutionStreams = *numberOfExecutionStreams
	execution.InParallel = *parallel
	execution.Strategy = *strategy
	filter.ExecuteTags = *executeTags
	order.Sorted = *sort
	filter.Distribute = *distribute
	filter.NumberOfExecutionStreams = *numberOfExecutionStreams
	reporter.NumberOfExecutionStreams = *numberOfExecutionStreams
	if *distribute != -1 {
		execution.Strategy = execution.Eager
	}
}
<commit_msg>changed legecy message for install-all flag. #768<commit_after>// Copyright 2015 ThoughtWorks, Inc.

// This file is part of Gauge.

// Gauge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Gauge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Gauge.  If not, see <http://www.gnu.org/licenses/>.

package main

import (
	"fmt"
	"os"

	"github.com/getgauge/common"
	"github.com/getgauge/gauge/api"
	"github.com/getgauge/gauge/cmd"
	"github.com/getgauge/gauge/config"
	"github.com/getgauge/gauge/env"
	"github.com/getgauge/gauge/execution"
	"github.com/getgauge/gauge/execution/stream"
	"github.com/getgauge/gauge/filter"
	"github.com/getgauge/gauge/formatter"
	"github.com/getgauge/gauge/logger"
	"github.com/getgauge/gauge/order"
	"github.com/getgauge/gauge/plugin"
	"github.com/getgauge/gauge/plugin/install"
	"github.com/getgauge/gauge/projectInit"
	"github.com/getgauge/gauge/refactor"
	"github.com/getgauge/gauge/reporter"
	"github.com/getgauge/gauge/skel"
	"github.com/getgauge/gauge/track"
	"github.com/getgauge/gauge/util"
	"github.com/getgauge/gauge/validation"
	flag "github.com/getgauge/mflag"
)

// Command line flags
var daemonize = flag.Bool([]string{"-daemonize"}, false, "[DEPRECATED] Use gauge daemon.")
var gaugeVersion = flag.Bool([]string{"v", "-version", "version"}, false, "[DEPRECATED] Use gauge version")
var verbosity = flag.Bool([]string{"-verbose"}, false, "[DEPRECATED] Use gauge run -v")
var logLevel = flag.String([]string{"-log-level"}, "", "Set level of logging to debug, info, warning, error or critical")
var simpleConsoleOutput = flag.Bool([]string{"-simple-console"}, false, "[DEPRECATED] gauge run --simple-console")
var initialize = flag.String([]string{"-init"}, "", "[DEPRECATED] gauge init <template name>")
var installPlugin = flag.String([]string{"-install"}, "", "[DEPRECATED] Use gauge install <plugin name>")
var uninstallPlugin = flag.String([]string{"-uninstall"}, "", "[DEPRECATED] Use gauge uninstall <plugin name>")
var installAll = flag.Bool([]string{"-install-all"}, false, "[DEPRECATED] Use gauge install")
var update = flag.String([]string{"-update"}, "", "[DEPRECATED] Use gauge update <plugin name>")
var pluginVersion = flag.String([]string{"-plugin-version"}, "", "[DEPRECATED] Use gauge [install|uninstall] <plugin name> -v <version>")
var installZip = flag.String([]string{"-file", "f"}, "", "[DEPRECATED] Use gauge install <plugin name> -f <zip file>")
var currentEnv = flag.String([]string{"-env"}, "default", "[DEPRECATED] Use gauge run -e <env name>")
var addPlugin = flag.String([]string{"-add-plugin"}, "", "[DEPRECATED] Use gauge add <plugin name>")
var pluginArgs = flag.String([]string{"-plugin-args"}, "", "[DEPRECATED] Use gauge add <plugin name> --args <args>")
var specFilesToFormat = flag.String([]string{"-format"}, "", "[DEPRECATED] Use gauge format specs/")
var executeTags = flag.String([]string{"-tags"}, "", "[DEPRECATED] Use gauge run --tags tag1,tag2 specs")
var tableRows = flag.String([]string{"-table-rows"}, "", "[DEPRECATED] gauge run --table-rows <rows>")
var apiPort = flag.String([]string{"-api-port"}, "", "[DEPRECATED] Use gauge daemon 7777")
var refactorSteps = flag.String([]string{"-refactor"}, "", "[DEPRECATED] Use gauge refactor <old step> <new step>")
var parallel = flag.Bool([]string{"-parallel", "p"}, false, "[DEPRECATED] guage run -p specs/")
var numberOfExecutionStreams = flag.Int([]string{"n"}, util.NumberOfCores(), "[DEPRECATED] Use guage run -p -n specs/")
var distribute = flag.Int([]string{"g", "-group"}, -1, "[DEPRECATED] Use gauge -n 5 -g 1 specs/")
var workingDir = flag.String([]string{"-dir"}, ".", "Set the working directory for the current command, accepts a path relative to current directory.")
var strategy = flag.String([]string{"-strategy"}, "lazy", "[DEPRECATED] This usage will be removed soon. Parallel execution uses lazy strategy.")
var sort = flag.Bool([]string{"-sort", "s"}, false, "[DEPRECATED] Use gauge run -s specs")
var validate = flag.Bool([]string{"-validate", "-check"}, false, "[DEPRECATED] Use gauge validate specs")
var updateAll = flag.Bool([]string{"-update-all"}, false, "[DEPRECATED] Use gauge update -a")
var checkUpdates = flag.Bool([]string{"-check-updates"}, false, "[DEPRECATED] Use gauge update -c")
var listTemplates = flag.Bool([]string{"-list-templates"}, false, "[DEPRECATED] Use gauge list-templates")
var machineReadable = flag.Bool([]string{"-machine-readable"}, false, "[DEPRECATED] Use gauge version -m")
var runFailed = flag.Bool([]string{"-failed"}, false, "[DEPRECATED] Use gauge run --failed")
var docs = flag.String([]string{"-docs"}, "", "[DEPRECATED] Use gauge docs <plugin name> specs/")

func main() {
	if os.Getenv("GAUGE_ROOT") != "" {
		fmt.Println("[DEPRECATED] GAUGE_ROOT will be removed soon. Use GAUGE_HOME instead. Refer to documentation: https://docs.getgauge.io/faqs.html#what-is-gauge-home")
	}
	skel.CreateSkelFilesIfRequired()
	track.Init()
	exit, err := cmd.Parse()
	if err == nil {
		os.Exit(exit)
	}
	fmt.Println("[DEPRECATED] This usage will be removed soon. Run `gauge help --legacy` for more info.")
	flag.Parse()
	logger.Initialize(*logLevel)
	util.SetWorkingDir(*workingDir)
	initPackageFlags()
	validGaugeProject := true
	err = config.SetProjectRoot(flag.Args())
	if err != nil {
		validGaugeProject = false
	}
	if *runFailed {
		logger.Fatalf("Rerun is not supported via the old usage. Use 'gauge run -f'")
	}
	if e := env.LoadEnv(*currentEnv); e != nil {
		logger.Fatalf(e.Error())
	}
	logger.Debugf("Gauge Install ID: %s", config.UniqueID())
	if *gaugeVersion && *machineReadable {
		printJSONVersion()
	} else if *machineReadable {
		fmt.Println("flag '--machine-readable' can only be used with 'version' subcommand")
		os.Exit(1)
	} else if *gaugeVersion {
		printVersion()
	} else if *initialize != "" {
		track.ProjectInit(*initialize)
		projectInit.InitializeProject(*initialize)
	} else if *installZip != "" && *installPlugin != "" {
		track.Install(*installPlugin, true)
		install.HandleInstallResult(install.InstallPluginFromZipFile(*installZip, *installPlugin), *installPlugin, true)
	} else if *installPlugin != "" {
		track.Install(*installPlugin, false)
		install.HandleInstallResult(install.Plugin(*installPlugin, *pluginVersion), *installPlugin, true)
	} else if *uninstallPlugin != "" {
		track.UninstallPlugin(*uninstallPlugin)
		install.UninstallPlugin(*uninstallPlugin, *pluginVersion)
	} else if *installAll {
		track.InstallAll()
		install.AllPlugins()
	} else if *update != "" {
		track.Update(*update)
		install.HandleUpdateResult(install.Plugin(*update, *pluginVersion), *update, true)
	} else if *updateAll {
		track.UpdateAll()
		install.UpdatePlugins()
	} else if *checkUpdates {
		track.CheckUpdates()
		install.PrintUpdateInfoWithDetails()
	} else if *addPlugin != "" {
		track.AddPlugins(*addPlugin)
		install.AddPlugin(*addPlugin, *pluginArgs)
	} else if *listTemplates {
		track.ListTemplates()
		projectInit.ListTemplates()
	} else if validGaugeProject {
		var specDirs = []string{common.SpecsDirectoryName}
		if len(flag.Args()) > 0 {
			specDirs = flag.Args()
		}
		if *refactorSteps != "" {
			track.Refactor()
			refactorInit(flag.Args())
		} else if *daemonize {
			track.Daemon()
			stream.Start()
			api.RunInBackground(*apiPort, specDirs)
		} else if *specFilesToFormat != "" {
			track.Format()
			formatter.FormatSpecFilesIn(*specFilesToFormat)
		} else if *validate {
			track.Validation()
			validation.Validate(flag.Args())
		} else if *docs != "" {
			track.Docs(*docs)
			gaugeConnectionHandler := api.Start(specDirs)
			plugin.GenerateDoc(*docs, specDirs, gaugeConnectionHandler.ConnectionPortNumber())
		} else {
			track.Execution(*parallel, *executeTags != "", *sort, *simpleConsoleOutput, *verbosity, *strategy)
			exitCode := execution.ExecuteSpecs(specDirs)
			os.Exit(exitCode)
		}
	} else {
		logger.Fatalf(err.Error())
	}
}

func refactorInit(args []string) {
	if len(args) < 1 {
		logger.Fatalf("Flag needs at least two arguments: refactor\nUsage : gauge refactor <old step> <new step> [[spec directories]]")
	}
	var specDirs = []string{common.SpecsDirectoryName}
	if len(args) > 1 {
		specDirs = args[1:]
	}
	startChan := api.StartAPI(false)
	refactor.RefactorSteps(*refactorSteps, args[0], startChan, specDirs)
}

func printJSONVersion() {
	cmd.PrintJSONVersion()
}

func printVersion() {
	cmd.PrintVersion()
}

func initPackageFlags() {
	if *parallel {
		*simpleConsoleOutput = true
		reporter.IsParallel = true
	}
	reporter.SimpleConsoleOutput = *simpleConsoleOutput
	reporter.Verbose = *verbosity
	execution.ExecuteTags = *executeTags
	execution.SetTableRows(*tableRows)
	validation.TableRows = *tableRows
	execution.NumberOfExecutionStreams = *numberOfExecutionStreams
	execution.InParallel = *parallel
	execution.Strategy = *strategy
	filter.ExecuteTags = *executeTags
	order.Sorted = *sort
	filter.Distribute = *distribute
	filter.NumberOfExecutionStreams = *numberOfExecutionStreams
	reporter.NumberOfExecutionStreams = *numberOfExecutionStreams
	if *distribute != -1 {
		execution.Strategy = execution.Eager
	}
}
<|endoftext|>


<commit_before>// Copyright 2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package version

import (
	"fmt"
	"io/ioutil"
	"regexp"
	"strconv"
	"strings"

	"github.com/juju/loggo"
	"github.com/juju/utils/exec"
)

var logger = loggo.GetLogger("juju.version")

func readSeries(releaseFile string) string {
	data, err := ioutil.ReadFile(releaseFile)
	if err != nil {
		return "unknown"
	}
	for _, line := range strings.Split(string(data), "\n") {
		const prefix = "DISTRIB_CODENAME="
		if strings.HasPrefix(line, prefix) {
			return strings.Trim(line[len(prefix):], "\t '\"")
		}
	}
	return "unknown"
}

type kernelVersionFunc func() (string, error)

// kernelToMajor takes a dotted version and returns just the Major portion
func kernelToMajor(getKernelVersion kernelVersionFunc) (int, error) {
	fullVersion, err := getKernelVersion()
	if err != nil {
		return 0, err
	}
	parts := strings.SplitN(fullVersion, ".", 2)
	majorVersion, err := strconv.ParseInt(parts[0], 10, 32)
	if err != nil {
		return 0, err
	}
	return int(majorVersion), nil
}

func macOSXSeriesFromKernelVersion(getKernelVersion kernelVersionFunc) string {
	majorVersion, err := kernelToMajor(getKernelVersion)
	if err != nil {
		logger.Infof("unable to determine OS version: %v", err)
		return "unknown"
	}
	return macOSXSeriesFromMajorVersion(majorVersion)
}

// TODO(jam): 2014-05-06 https://launchpad.net/bugs/1316593
// we should have a system file that we can read so this can be updated without
// recompiling Juju. For now, this is a lot easier, and also solves the fact
// that we want to populate version.Current.Series during init() time, before
// we've potentially read that information from anywhere else
// macOSXSeries maps from the Darwin Kernel Major Version to the Mac OSX
// series.
var macOSXSeries = map[int]string{
	13: "mavericks",
	12: "mountainlion",
	11: "lion",
	10: "snowleopard",
	9:  "leopard",
	8:  "tiger",
	7:  "panther",
	6:  "jaguar",
	5:  "puma",
}

func macOSXSeriesFromMajorVersion(majorVersion int) string {
	if series, ok := macOSXSeries[majorVersion]; ok {
		return series
	}
	return "unknown"
}

func getWinVersion() string {
	var com exec.RunParams
	com.Commands = `(gwmi Win32_OperatingSystem).Name.Split('|')[0]`
	out, _ := exec.RunCommands(com)
	if out.Code != 0 {
		return "unknown"
	}
	serie := strings.TrimSpace(string(out.Stdout))
	if val, ok := WindowsVersions[serie]; ok {
		return val
	}
	for key, value := range WindowsVersions {
		reg := regexp.MustCompile(fmt.Sprintf("^%s", key))
		match := reg.MatchString(serie)
		if match {
			return value
		}
	}
	return "unknown"
}
<commit_msg>missed 2 instances of windowsVersions<commit_after>// Copyright 2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package version

import (
	"fmt"
	"io/ioutil"
	"regexp"
	"strconv"
	"strings"

	"github.com/juju/loggo"
	"github.com/juju/utils/exec"
)

var logger = loggo.GetLogger("juju.version")

func readSeries(releaseFile string) string {
	data, err := ioutil.ReadFile(releaseFile)
	if err != nil {
		return "unknown"
	}
	for _, line := range strings.Split(string(data), "\n") {
		const prefix = "DISTRIB_CODENAME="
		if strings.HasPrefix(line, prefix) {
			return strings.Trim(line[len(prefix):], "\t '\"")
		}
	}
	return "unknown"
}

type kernelVersionFunc func() (string, error)

// kernelToMajor takes a dotted version and returns just the Major portion
func kernelToMajor(getKernelVersion kernelVersionFunc) (int, error) {
	fullVersion, err := getKernelVersion()
	if err != nil {
		return 0, err
	}
	parts := strings.SplitN(fullVersion, ".", 2)
	majorVersion, err := strconv.ParseInt(parts[0], 10, 32)
	if err != nil {
		return 0, err
	}
	return int(majorVersion), nil
}

func macOSXSeriesFromKernelVersion(getKernelVersion kernelVersionFunc) string {
	majorVersion, err := kernelToMajor(getKernelVersion)
	if err != nil {
		logger.Infof("unable to determine OS version: %v", err)
		return "unknown"
	}
	return macOSXSeriesFromMajorVersion(majorVersion)
}

// TODO(jam): 2014-05-06 https://launchpad.net/bugs/1316593
// we should have a system file that we can read so this can be updated without
// recompiling Juju. For now, this is a lot easier, and also solves the fact
// that we want to populate version.Current.Series during init() time, before
// we've potentially read that information from anywhere else
// macOSXSeries maps from the Darwin Kernel Major Version to the Mac OSX
// series.
var macOSXSeries = map[int]string{
	13: "mavericks",
	12: "mountainlion",
	11: "lion",
	10: "snowleopard",
	9:  "leopard",
	8:  "tiger",
	7:  "panther",
	6:  "jaguar",
	5:  "puma",
}

func macOSXSeriesFromMajorVersion(majorVersion int) string {
	if series, ok := macOSXSeries[majorVersion]; ok {
		return series
	}
	return "unknown"
}

func getWinVersion() string {
	var com exec.RunParams
	com.Commands = `(gwmi Win32_OperatingSystem).Name.Split('|')[0]`
	out, _ := exec.RunCommands(com)
	if out.Code != 0 {
		return "unknown"
	}
	serie := strings.TrimSpace(string(out.Stdout))
	if val, ok := windowsVersions[serie]; ok {
		return val
	}
	for key, value := range windowsVersions {
		reg := regexp.MustCompile(fmt.Sprintf("^%s", key))
		match := reg.MatchString(serie)
		if match {
			return value
		}
	}
	return "unknown"
}
<|endoftext|>


<commit_before>// Copyright 2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package version

import (
	"bufio"
	"os"
	"strconv"
	"strings"

	"github.com/juju/errors"
	"github.com/juju/loggo"
)

var logger = loggo.GetLogger("juju.version")

// mustOsVersion will panic if the osVersion is "unknown" due
// to an error.
//
// If you want to avoid the panic, either call osVersion and handle
// the error.
func mustOsVersion() string {
	version, err := osVersion()
	if err != nil {
		panic("osVersion reported an error: " + err.Error())
	}
	return version
}

func readSeries(releaseFile string) (string, error) {
	f, err := os.Open(releaseFile)
	if err != nil {
		return "unknown", err
	}
	defer f.Close()

	s := bufio.NewScanner(f)
	for s.Scan() {
		line := s.Text()
		const prefix = "DISTRIB_CODENAME="
		if strings.HasPrefix(line, prefix) {
			return strings.Trim(line[len(prefix):], "\t '\""), s.Err()
		}
	}
	return "unknown", s.Err()
}

// kernelToMajor takes a dotted version and returns just the Major portion
func kernelToMajor(getKernelVersion func() (string, error)) (int, error) {
	fullVersion, err := getKernelVersion()
	if err != nil {
		return 0, err
	}
	parts := strings.SplitN(fullVersion, ".", 2)
	majorVersion, err := strconv.ParseInt(parts[0], 10, 32)
	if err != nil {
		return 0, err
	}
	return int(majorVersion), nil
}

func macOSXSeriesFromKernelVersion(getKernelVersion func() (string, error)) (string, error) {
	majorVersion, err := kernelToMajor(getKernelVersion)
	if err != nil {
		logger.Infof("unable to determine OS version: %v", err)
		return "unknown", err
	}
	return macOSXSeriesFromMajorVersion(majorVersion)
}

// TODO(jam): 2014-05-06 https://launchpad.net/bugs/1316593
// we should have a system file that we can read so this can be updated without
// recompiling Juju. For now, this is a lot easier, and also solves the fact
// that we want to populate version.Current.Series during init() time, before
// we've potentially read that information from anywhere else
// macOSXSeries maps from the Darwin Kernel Major Version to the Mac OSX
// series.
var macOSXSeries = map[int]string{
	13: "mavericks",
	12: "mountainlion",
	11: "lion",
	10: "snowleopard",
	9:  "leopard",
	8:  "tiger",
	7:  "panther",
	6:  "jaguar",
	5:  "puma",
}

func macOSXSeriesFromMajorVersion(majorVersion int) (string, error) {
	series, ok := macOSXSeries[majorVersion]
	if !ok {
		return "unknown", errors.Errorf("unknown series %q", series)
	}
	return series, nil
}
<commit_msg>wording<commit_after>// Copyright 2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package version

import (
	"bufio"
	"os"
	"strconv"
	"strings"

	"github.com/juju/errors"
	"github.com/juju/loggo"
)

var logger = loggo.GetLogger("juju.version")

// mustOsVersion will panic if the osVersion is "unknown" due
// to an error.
//
// If you want to avoid the panic, call osVersion and handle
// the error.
func mustOsVersion() string {
	version, err := osVersion()
	if err != nil {
		panic("osVersion reported an error: " + err.Error())
	}
	return version
}

func readSeries(releaseFile string) (string, error) {
	f, err := os.Open(releaseFile)
	if err != nil {
		return "unknown", err
	}
	defer f.Close()

	s := bufio.NewScanner(f)
	for s.Scan() {
		line := s.Text()
		const prefix = "DISTRIB_CODENAME="
		if strings.HasPrefix(line, prefix) {
			return strings.Trim(line[len(prefix):], "\t '\""), s.Err()
		}
	}
	return "unknown", s.Err()
}

// kernelToMajor takes a dotted version and returns just the Major portion
func kernelToMajor(getKernelVersion func() (string, error)) (int, error) {
	fullVersion, err := getKernelVersion()
	if err != nil {
		return 0, err
	}
	parts := strings.SplitN(fullVersion, ".", 2)
	majorVersion, err := strconv.ParseInt(parts[0], 10, 32)
	if err != nil {
		return 0, err
	}
	return int(majorVersion), nil
}

func macOSXSeriesFromKernelVersion(getKernelVersion func() (string, error)) (string, error) {
	majorVersion, err := kernelToMajor(getKernelVersion)
	if err != nil {
		logger.Infof("unable to determine OS version: %v", err)
		return "unknown", err
	}
	return macOSXSeriesFromMajorVersion(majorVersion)
}

// TODO(jam): 2014-05-06 https://launchpad.net/bugs/1316593
// we should have a system file that we can read so this can be updated without
// recompiling Juju. For now, this is a lot easier, and also solves the fact
// that we want to populate version.Current.Series during init() time, before
// we've potentially read that information from anywhere else
// macOSXSeries maps from the Darwin Kernel Major Version to the Mac OSX
// series.
var macOSXSeries = map[int]string{
	13: "mavericks",
	12: "mountainlion",
	11: "lion",
	10: "snowleopard",
	9:  "leopard",
	8:  "tiger",
	7:  "panther",
	6:  "jaguar",
	5:  "puma",
}

func macOSXSeriesFromMajorVersion(majorVersion int) (string, error) {
	series, ok := macOSXSeries[majorVersion]
	if !ok {
		return "unknown", errors.Errorf("unknown series %q", series)
	}
	return series, nil
}
<|endoftext|>