<commit_before>package main

import (
	"errors"
	"fmt"

	"github.com/mendersoftware/artifacts/Godeps/_workspace/src/github.com/codegangsta/cli"
)

const (
	TLSCertificateFlag        = "certificate"
	TLSCertificateDescription = "HTTPS certificate filename."
	TLSCertificateVar         = "MENDER_ARTIFACT_CERT"

	TLSKeyFlag        = "key"
	TLSKeyDescription = "HTTPS private key filename."
	TLSKeyVar         = "MENDER_ARTIFACT_CERT_KEY"

	HTTPSFlag        = "https"
	HTTPSDescription = "Serve under HTTPS. Requires key and cerfiticate."
	HTTPSVar         = "MENDER_ARTIFACT_HTTPS"

	ListenFlag        = "listen"
	ListenDescription = "TCP network address."
	ListenDefault     = "localhost:8080"
	ListenVar         = "MENDER_ARTIFACT_LISTEN"

	EnvFlag        = "env"
	EnvDescription = "Environment " + EnvProd + "|" + EnvDev
	EnvDefault     = EnvDev
	EnvVar         = "MENDER_ARTIFACT_ENV"

	AwsAccessKeyIdFlag        = "aws-id"
	AwsAccessKeyIdDescription = "AWS access id key with S3 read/write permissions for specified bucket (required)."
	AwsAccessKeyIdVar         = "AWS_ACCESS_KEY_ID"

	AwsAccessKeySecretFlag        = "aws_secret"
	AwsAccessKeySecretDescription = "AWS secret key with S3 read/write permissions for specified bucket (required)."
	AwsAccessKeySecretVar         = "AWS_SECRET_ACCESS_KEY"

	AwsS3RegionFlag        = "aws-region"
	AwsS3RegionDescription = "AWS region."
	AwsS3RegionDefault     = "eu-west-1"
	AwsS3RegionVar         = "AWS_REGION"

	S3BucketFlag        = "bucket"
	S3BucketDescription = "S3 bucket name for image storage."
	S3BucketDefault     = "mender-file-storage"
	S3BucketVar         = "MENDER_S3_BUCKET"
)

var (
	// This variable value can be overwritten during compile time by a build system.
	// For example: go build -ldflags "-X main.Version `echo $BUILD_NUMBER`"
	Version = "0.0.1"
)

func SetupGlobalFlags(app *cli.App) {

	app.Name = "artifacts"
	app.Usage = "Archifact management service for mender.io"
	app.Authors = []cli.Author{
		{"Maciej Mrowiec", "maciej.mrowiec@mender.io"},
	}
	app.Email = "contact@mender.io"
	app.Version = Version

	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:   TLSCertificateFlag,
			Usage:  TLSCertificateDescription,
			EnvVar: TLSCertificateVar,
		},
		cli.StringFlag{
			Name:   TLSKeyFlag,
			Usage:  TLSKeyDescription,
			EnvVar: TLSKeyVar,
		},
		cli.BoolFlag{
			Name:   HTTPSFlag,
			Usage:  HTTPSDescription,
			EnvVar: HTTPSVar,
		},
		cli.StringFlag{
			Name:   ListenFlag,
			Usage:  ListenDescription,
			Value:  ListenDefault,
			EnvVar: ListenVar,
		},
		cli.StringFlag{
			Name:   EnvFlag,
			Usage:  EnvDescription,
			Value:  EnvDefault,
			EnvVar: EnvVar,
		},

		cli.StringFlag{
			Name:   AwsAccessKeyIdFlag,
			Usage:  AwsAccessKeyIdDescription,
			EnvVar: AwsAccessKeyIdVar,
		},
		cli.StringFlag{
			Name:   AwsAccessKeySecretFlag,
			Usage:  AwsAccessKeySecretDescription,
			EnvVar: AwsAccessKeySecretVar,
		},
		cli.StringFlag{
			Name:   S3BucketFlag,
			Usage:  S3BucketDescription,
			Value:  S3BucketDefault,
			EnvVar: S3BucketVar,
		},
		cli.StringFlag{
			Name:   AwsS3RegionFlag,
			Usage:  AwsS3RegionDescription,
			Value:  AwsS3RegionDefault,
			EnvVar: AwsS3RegionVar,
		},
	}
}

func ValidateGlobalFlags(c *cli.Context) error {

	fns := []func(c *cli.Context) error{
		validateAWSFlags,
		validateEnvFlags,
		validateHttpFlags,
	}

	for _, validateFn := range fns {
		err := validateFn(c)
		if err != nil {
			cli.ShowAppHelp(c)
			return err
		}
	}

	return nil
}

func validateAWSFlags(c *cli.Context) error {

	key := c.String(AwsAccessKeyIdFlag)
	secret := c.String(AwsAccessKeySecretFlag)
	region := c.String(AwsS3RegionFlag)

	if key == "" {
		return MissingOptionError(AwsAccessKeyIdFlag)
	}

	if secret == "" {
		return MissingOptionError(AwsAccessKeySecretFlag)
	}

	if region == "" {
		return MissingOptionError(AwsS3RegionFlag)
	}

	return nil
}

func validateEnvFlags(c *cli.Context) error {

	env := c.String(EnvFlag)

	switch env {
	case EnvProd:
		return nil
	case EnvDev:
		return nil

	default:
		return InvalidValueError(EnvFlag, env)
	}
}

func validateHttpFlags(c *cli.Context) error {

	isHttps := c.Bool(HTTPSFlag)
	cert := c.String(TLSCertificateFlag)
	key := c.String(TLSKeyFlag)

	if isHttps {
		if cert == "" {
			return MissingOptionError(TLSCertificateFlag)
		}

		if key == "" {
			return MissingOptionError(TLSKeyFlag)
		}
	}

	return nil
}

func InvalidValueError(option string, value interface{}) error {
	return errors.New(fmt.Sprintf("Invalid value '%s' = '%v'.", option, value))
}

func MissingOptionError(option string) error {
	return errors.New(fmt.Sprintf("Required option: '%s'", option))
}
<commit_msg>Use version from build system.<commit_after>package main

import (
	"errors"
	"fmt"

	"github.com/mendersoftware/artifacts/Godeps/_workspace/src/github.com/codegangsta/cli"
)

const (
	TLSCertificateFlag        = "certificate"
	TLSCertificateDescription = "HTTPS certificate filename."
	TLSCertificateVar         = "MENDER_ARTIFACT_CERT"

	TLSKeyFlag        = "key"
	TLSKeyDescription = "HTTPS private key filename."
	TLSKeyVar         = "MENDER_ARTIFACT_CERT_KEY"

	HTTPSFlag        = "https"
	HTTPSDescription = "Serve under HTTPS. Requires key and cerfiticate."
	HTTPSVar         = "MENDER_ARTIFACT_HTTPS"

	ListenFlag        = "listen"
	ListenDescription = "TCP network address."
	ListenDefault     = "localhost:8080"
	ListenVar         = "MENDER_ARTIFACT_LISTEN"

	EnvFlag        = "env"
	EnvDescription = "Environment " + EnvProd + "|" + EnvDev
	EnvDefault     = EnvDev
	EnvVar         = "MENDER_ARTIFACT_ENV"

	AwsAccessKeyIdFlag        = "aws-id"
	AwsAccessKeyIdDescription = "AWS access id key with S3 read/write permissions for specified bucket (required)."
	AwsAccessKeyIdVar         = "AWS_ACCESS_KEY_ID"

	AwsAccessKeySecretFlag        = "aws_secret"
	AwsAccessKeySecretDescription = "AWS secret key with S3 read/write permissions for specified bucket (required)."
	AwsAccessKeySecretVar         = "AWS_SECRET_ACCESS_KEY"

	AwsS3RegionFlag        = "aws-region"
	AwsS3RegionDescription = "AWS region."
	AwsS3RegionDefault     = "eu-west-1"
	AwsS3RegionVar         = "AWS_REGION"

	S3BucketFlag        = "bucket"
	S3BucketDescription = "S3 bucket name for image storage."
	S3BucketDefault     = "mender-file-storage"
	S3BucketVar         = "MENDER_S3_BUCKET"
)

func SetupGlobalFlags(app *cli.App) {

	app.Name = "artifacts"
	app.Usage = "Archifact management service for mender.io"
	app.Authors = []cli.Author{
		{"Maciej Mrowiec", "maciej.mrowiec@mender.io"},
	}
	app.Email = "contact@mender.io"

	if Tag != "" {
		app.Version = Tag
	} else {
		app.Version = BuildNumber
	}

	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:   TLSCertificateFlag,
			Usage:  TLSCertificateDescription,
			EnvVar: TLSCertificateVar,
		},
		cli.StringFlag{
			Name:   TLSKeyFlag,
			Usage:  TLSKeyDescription,
			EnvVar: TLSKeyVar,
		},
		cli.BoolFlag{
			Name:   HTTPSFlag,
			Usage:  HTTPSDescription,
			EnvVar: HTTPSVar,
		},
		cli.StringFlag{
			Name:   ListenFlag,
			Usage:  ListenDescription,
			Value:  ListenDefault,
			EnvVar: ListenVar,
		},
		cli.StringFlag{
			Name:   EnvFlag,
			Usage:  EnvDescription,
			Value:  EnvDefault,
			EnvVar: EnvVar,
		},

		cli.StringFlag{
			Name:   AwsAccessKeyIdFlag,
			Usage:  AwsAccessKeyIdDescription,
			EnvVar: AwsAccessKeyIdVar,
		},
		cli.StringFlag{
			Name:   AwsAccessKeySecretFlag,
			Usage:  AwsAccessKeySecretDescription,
			EnvVar: AwsAccessKeySecretVar,
		},
		cli.StringFlag{
			Name:   S3BucketFlag,
			Usage:  S3BucketDescription,
			Value:  S3BucketDefault,
			EnvVar: S3BucketVar,
		},
		cli.StringFlag{
			Name:   AwsS3RegionFlag,
			Usage:  AwsS3RegionDescription,
			Value:  AwsS3RegionDefault,
			EnvVar: AwsS3RegionVar,
		},
	}
}

func ValidateGlobalFlags(c *cli.Context) error {

	fns := []func(c *cli.Context) error{
		validateAWSFlags,
		validateEnvFlags,
		validateHttpFlags,
	}

	for _, validateFn := range fns {
		err := validateFn(c)
		if err != nil {
			cli.ShowAppHelp(c)
			return err
		}
	}

	return nil
}

func validateAWSFlags(c *cli.Context) error {

	key := c.String(AwsAccessKeyIdFlag)
	secret := c.String(AwsAccessKeySecretFlag)
	region := c.String(AwsS3RegionFlag)

	if key == "" {
		return MissingOptionError(AwsAccessKeyIdFlag)
	}

	if secret == "" {
		return MissingOptionError(AwsAccessKeySecretFlag)
	}

	if region == "" {
		return MissingOptionError(AwsS3RegionFlag)
	}

	return nil
}

func validateEnvFlags(c *cli.Context) error {

	env := c.String(EnvFlag)

	switch env {
	case EnvProd:
		return nil
	case EnvDev:
		return nil

	default:
		return InvalidValueError(EnvFlag, env)
	}
}

func validateHttpFlags(c *cli.Context) error {

	isHttps := c.Bool(HTTPSFlag)
	cert := c.String(TLSCertificateFlag)
	key := c.String(TLSKeyFlag)

	if isHttps {
		if cert == "" {
			return MissingOptionError(TLSCertificateFlag)
		}

		if key == "" {
			return MissingOptionError(TLSKeyFlag)
		}
	}

	return nil
}

func InvalidValueError(option string, value interface{}) error {
	return errors.New(fmt.Sprintf("Invalid value '%s' = '%v'.", option, value))
}

func MissingOptionError(option string) error {
	return errors.New(fmt.Sprintf("Required option: '%s'", option))
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"mime"
	"os"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
	"sync"

	"github.com/mitchellh/goamz/aws"
	"github.com/mitchellh/goamz/s3"
)

const (
	NAME    = "PipelineDeals S3 asset uploader"
	LICENSE = "Licensed under the MIT license"
	VERSION = "0.1"
)

var (
	bucket       = flag.String("b", "assets.pipelinedeals.com", "AWS S3 bucket to upload assets to")
	directory    = flag.String("d", "./public", "Local assets directory to upload to S3")
	key          = flag.String("k", "", "Key to preface to asset")
	maxWorkers   = flag.Int("w", 4, "Max number of workers to start")
	maxQueueSize = flag.Int("q", 100, "Max size of upload queue")
	help         = flag.Bool("help", false, "You're looking at it")
	h            = flag.Bool("h", false, "You're looking at it")
	version      = flag.Bool("v", false, "Show version")
)

type Upload struct {
	Path      string
	Dir       string
	Bucket    string
	PrefixKey string
	WaitGroup *sync.WaitGroup
}

func (u *Upload) RelativePath() string {
	relativePath := strings.TrimPrefix(u.Path, u.Dir+"/")

	if u.PrefixKey != "" {
		relativePath = "/" + u.PrefixKey + "/" + relativePath
	}
	return relativePath
}

func (u *Upload) FileType() string {
	ext := filepath.Ext(u.Path)
	fileType := mime.TypeByExtension(ext)
	return fileType
}

func (u *Upload) Put() {
	auth, err := aws.EnvAuth()

	if err != nil {
		panic(err)
	}

	client := s3.New(auth, aws.USEast)
	b := client.Bucket(u.Bucket)

	file, err := os.Open(u.Path)
	if err != nil {
		panic(err)
	}

	stat, err := file.Stat()
	if err != nil {
		panic(err)
	}

	headers := map[string][]string{
		"Content-Length": {strconv.FormatInt(stat.Size(), 10)},
		"Content-Type":   {u.FileType()},
		"Cache-Control":  {"max-age=31104000"},
	}

	relativePath := u.RelativePath()

	err = b.PutReaderHeader(relativePath, file, stat.Size(), headers, s3.ACL("public-read"))

	if err != nil {
		panic(err)
	}

}

type Worker struct {
	id          int
	uploadQueue chan *Upload
}

func NewWorker(id int, uploadQueue chan *Upload) Worker {
	return Worker{
		id:          id,
		uploadQueue: uploadQueue,
	}
}

func (w Worker) start() {
	go func() {
		for {
			select {
			case upload := <-w.uploadQueue:
				// Dispatcher has added a upload to my upload.
				fmt.Printf("worker%d started: uploading %s to %s/%s/%s\n", w.id, upload.Path, upload.Bucket, upload.PrefixKey, upload.Path)
				upload.Put()

				upload.WaitGroup.Done()

				fmt.Printf("worker%d finished uploading %s!\n", w.id, upload.Path)
			}
		}
	}()
}

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())

	log.SetOutput(os.Stdout)
	log.SetFlags(0)

	startupInfo()

	flag.Usage = printHelp

	flag.Parse()

	if *help || *h {
		printHelp()
		os.Exit(0)
	}

	if *version {
		os.Exit(0)
	}

	fileList, err := GetFileList(*directory)

	if err != nil {
		panic(err)
	}

	uploadQueue := make(chan *Upload, *maxQueueSize)
	var wg sync.WaitGroup

	for i := 0; i < *maxWorkers; i++ {
		worker := NewWorker(i, uploadQueue)
		worker.start()
	}

	for _, path := range fileList {
		upload := &Upload{
			Path:      path,
			Dir:       *directory,
			Bucket:    *bucket,
			PrefixKey: *key,
			WaitGroup: &wg,
		}

		wg.Add(1)
		go func() {
			uploadQueue <- upload
		}()
	}

	wg.Wait()
}

func GetFileList(dir string) (fileList []string, err error) {
	err = filepath.Walk(dir, func(path string, f os.FileInfo, err error) error {
		if !f.IsDir() {
			fileList = append(fileList, path)
		}
		return nil
	})

	return fileList, err
}

func printHelp() {
	log.Println("-b\t\tAWS S3 target bucket, default: assets.pipelinedeals.com")
	log.Println("-d\t\tLocal assets directory to upload to S3, default: ./public")
	log.Println("-k\t\tKey to preface the asset with, default: ''")
	log.Println("-w\t\tMax number of workers to start, default: 4")
	log.Println("-q\t\tKey Max size of upload queue, default: 100")
	log.Println("-v\t\tShow version and license information")
	log.Println("-h\t\tThis help screen")
}

func startupInfo() {
	log.Println(NAME, VERSION)
	log.Println("")
	log.Println("Copyright © 2015 PipelineDeals")
	log.Println(LICENSE)
	log.Println("")
}
<commit_msg>Only show relative path<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"mime"
	"os"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/mitchellh/goamz/aws"
	"github.com/mitchellh/goamz/s3"
)

const (
	NAME    = "PipelineDeals S3 asset uploader"
	LICENSE = "Licensed under the MIT license"
	VERSION = "0.1"
)

var (
	bucket       = flag.String("b", "assets.pipelinedeals.com", "AWS S3 bucket to upload assets to")
	directory    = flag.String("d", "./public", "Local assets directory to upload to S3")
	key          = flag.String("k", "", "Key to preface to asset")
	maxWorkers   = flag.Int("w", 4, "Max number of workers to start")
	maxQueueSize = flag.Int("q", 100, "Max size of upload queue")
	help         = flag.Bool("help", false, "You're looking at it")
	h            = flag.Bool("h", false, "You're looking at it")
	version      = flag.Bool("v", false, "Show version")
)

type Upload struct {
	Path      string
	Dir       string
	Bucket    string
	PrefixKey string
	WaitGroup *sync.WaitGroup
}

func (u *Upload) RelativePath() string {
	relativePath := strings.TrimPrefix(u.Path, u.Dir+"/")

	if u.PrefixKey != "" {
		relativePath = "/" + u.PrefixKey + "/" + relativePath
	}
	return relativePath
}

func (u *Upload) FileType() string {
	ext := filepath.Ext(u.Path)
	fileType := mime.TypeByExtension(ext)
	return fileType
}

func (u *Upload) Put() {
	auth, err := aws.EnvAuth()

	if err != nil {
		panic(err)
	}

	client := s3.New(auth, aws.USEast)
	b := client.Bucket(u.Bucket)

	file, err := os.Open(u.Path)
	if err != nil {
		panic(err)
	}

	stat, err := file.Stat()
	if err != nil {
		panic(err)
	}

	headers := map[string][]string{
		"Content-Length": {strconv.FormatInt(stat.Size(), 10)},
		"Content-Type":   {u.FileType()},
		"Cache-Control":  {"max-age=31104000"},
	}

	relativePath := u.RelativePath()

	fmt.Printf("Path: %s\n", relativePath)

	err = b.PutReaderHeader(relativePath, file, stat.Size(), headers, s3.ACL("public-read"))

	if err != nil {
		panic(err)
	}

}

type Worker struct {
	id          int
	uploadQueue chan *Upload
}

func NewWorker(id int, uploadQueue chan *Upload) Worker {
	return Worker{
		id:          id,
		uploadQueue: uploadQueue,
	}
}

func (w Worker) start() {
	go func() {
		for {
			select {
			case upload := <-w.uploadQueue:
				// Dispatcher has added a upload to my upload.
				// fmt.Printf("worker%d started: uploading %s to %s/%s/%s\n", w.id, upload.Path, upload.Bucket, upload.PrefixKey, upload.Path)
				upload.Put()

				upload.WaitGroup.Done()

				// fmt.Printf("worker%d finished uploading %s!\n", w.id, upload.Path)
			}
		}
	}()
}

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())

	log.SetOutput(os.Stdout)
	log.SetFlags(0)

	startupInfo()

	flag.Usage = printHelp

	flag.Parse()

	if *help || *h {
		printHelp()
		os.Exit(0)
	}

	if *version {
		os.Exit(0)
	}

	fileList, err := GetFileList(*directory)

	if err != nil {
		panic(err)
	}

	uploadQueue := make(chan *Upload, *maxQueueSize)
	var wg sync.WaitGroup

	for i := 0; i < *maxWorkers; i++ {
		worker := NewWorker(i, uploadQueue)
		worker.start()
	}

	for _, path := range fileList {
		upload := &Upload{
			Path:      path,
			Dir:       *directory,
			Bucket:    *bucket,
			PrefixKey: *key,
			WaitGroup: &wg,
		}

		wg.Add(1)
		go func() {
			uploadQueue <- upload
		}()
	}

	wg.Wait()

	time.Sleep(10000 * time.Millisecond)
}

func GetFileList(dir string) (fileList []string, err error) {
	err = filepath.Walk(dir, func(path string, f os.FileInfo, err error) error {
		if !f.IsDir() {
			fileList = append(fileList, path)
		}
		return nil
	})

	return fileList, err
}

func printHelp() {
	log.Println("-b\t\tAWS S3 target bucket, default: assets.pipelinedeals.com")
	log.Println("-d\t\tLocal assets directory to upload to S3, default: ./public")
	log.Println("-k\t\tKey to preface the asset with, default: ''")
	log.Println("-w\t\tMax number of workers to start, default: 4")
	log.Println("-q\t\tKey Max size of upload queue, default: 100")
	log.Println("-v\t\tShow version and license information")
	log.Println("-h\t\tThis help screen")
}

func startupInfo() {
	log.Println(NAME, VERSION)
	log.Println("")
	log.Println("Copyright © 2015 PipelineDeals")
	log.Println(LICENSE)
	log.Println("")
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"

	"go/build"
	"io"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"reflect"
	"strings"

	"github.com/jessevdk/go-flags"
	"github.com/sourcegraph/srclib/unit"
)

var (
	parser = flags.NewNamedParser("srclib-go", flags.Default)
	cwd    string
)

func init() {
	parser.LongDescription = "srclib-go performs Go package, dependency, and source analysis."

	var err error
	cwd, err = os.Getwd()
	if err != nil {
		log.Fatal(err)
	}
}

func main() {
	log.SetFlags(0)
	if _, err := parser.Parse(); err != nil {
		os.Exit(1)
	}
}

func init() {
	_, err := parser.AddCommand("scan",
		"scan for Go packages",
		"Scan the directory tree rooted at the current directory for Go packages.",
		&scanCmd,
	)
	if err != nil {
		log.Fatal(err)
	}
}

type ScanCmd struct {
	Repo   string `long:"repo" description:"repository URI" value-name:"URI"`
	Subdir string `long:"subdir" description:"subdirectory in repository" value-name:"DIR"`
}

var scanCmd ScanCmd

func (c *ScanCmd) Execute(args []string) error {
	if c.Repo == "" && os.Getenv("IN_DOCKER_CONTAINER") != "" {
		log.Println("Warning: no --repo specified, and tool is running in a Docker container (i.e., without awareness of host's GOPATH). Go import paths in source units produced by the scanner may be inaccurate. To fix this, ensure that the --repo URI is specified. Report this issue if you are seeing it unexpectedly.")
	}

	cmd := exec.Command("go", "list", "-e", "-json", "./...")
	cmd.Stderr = os.Stderr
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		return err
	}
	if err := cmd.Start(); err != nil {
		return err
	}

	dec := json.NewDecoder(stdout)
	var units []*unit.SourceUnit
	for {
		var pkg *build.Package
		if err := dec.Decode(&pkg); err == io.EOF {
			break
		} else if err != nil {
			return err
		}

		pv, pt := reflect.ValueOf(pkg).Elem(), reflect.TypeOf(*pkg)

		// collect all files
		var files []string
		for i := 0; i < pt.NumField(); i++ {
			f := pt.Field(i)
			if strings.HasSuffix(f.Name, "Files") {
				fv := pv.Field(i).Interface()
				files = append(files, fv.([]string)...)
			}
		}

		// make all dirs relative to the current dir
		for i := 0; i < pt.NumField(); i++ {
			f := pt.Field(i)
			if strings.HasSuffix(f.Name, "Dir") {
				fv := pv.Field(i)
				dir := fv.Interface().(string)
				if dir != "" {
					dir, err := filepath.Rel(cwd, dir)
					if err != nil {
						return err
					}
					fv.Set(reflect.ValueOf(dir))
				}
			}
		}

		// fix up import path to be consistent when running as a program and as
		// a Docker container.
		pkg.ImportPath = filepath.Join(c.Repo, c.Subdir, pkg.Dir)

		units = append(units, &unit.SourceUnit{
			Name:  pkg.ImportPath,
			Type:  "GoPackage",
			Files: files,
			Data:  pkg,
		})
	}
	if err := cmd.Wait(); err != nil {
		return err
	}

	if err := json.NewEncoder(os.Stdout).Encode(units); err != nil {
		return err
	}
	return nil
}
<commit_msg>produce Dependencies in source unit<commit_after>package main

import (
	"encoding/json"

	"go/build"
	"io"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"reflect"
	"sort"
	"strings"

	"github.com/jessevdk/go-flags"
	"github.com/sourcegraph/srclib/unit"
)

var (
	parser = flags.NewNamedParser("srclib-go", flags.Default)
	cwd    string
)

func init() {
	parser.LongDescription = "srclib-go performs Go package, dependency, and source analysis."

	var err error
	cwd, err = os.Getwd()
	if err != nil {
		log.Fatal(err)
	}
}

func main() {
	log.SetFlags(0)
	if _, err := parser.Parse(); err != nil {
		os.Exit(1)
	}
}

func init() {
	_, err := parser.AddCommand("scan",
		"scan for Go packages",
		"Scan the directory tree rooted at the current directory for Go packages.",
		&scanCmd,
	)
	if err != nil {
		log.Fatal(err)
	}
}

type ScanCmd struct {
	Repo   string `long:"repo" description:"repository URI" value-name:"URI"`
	Subdir string `long:"subdir" description:"subdirectory in repository" value-name:"DIR"`
}

var scanCmd ScanCmd

func (c *ScanCmd) Execute(args []string) error {
	if c.Repo == "" && os.Getenv("IN_DOCKER_CONTAINER") != "" {
		log.Println("Warning: no --repo specified, and tool is running in a Docker container (i.e., without awareness of host's GOPATH). Go import paths in source units produced by the scanner may be inaccurate. To fix this, ensure that the --repo URI is specified. Report this issue if you are seeing it unexpectedly.")
	}

	cmd := exec.Command("go", "list", "-e", "-json", "./...")
	cmd.Stderr = os.Stderr
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		return err
	}
	if err := cmd.Start(); err != nil {
		return err
	}

	dec := json.NewDecoder(stdout)
	var units []*unit.SourceUnit
	for {
		var pkg *build.Package
		if err := dec.Decode(&pkg); err == io.EOF {
			break
		} else if err != nil {
			return err
		}

		pv, pt := reflect.ValueOf(pkg).Elem(), reflect.TypeOf(*pkg)

		// collect all files
		var files []string
		for i := 0; i < pt.NumField(); i++ {
			f := pt.Field(i)
			if strings.HasSuffix(f.Name, "Files") {
				fv := pv.Field(i).Interface()
				files = append(files, fv.([]string)...)
			}
		}

		// collect all imports
		depsMap := map[string]struct{}{}
		for i := 0; i < pt.NumField(); i++ {
			f := pt.Field(i)
			if strings.HasSuffix(f.Name, "Imports") {
				fv := pv.Field(i).Interface()
				imports := fv.([]string)
				for _, imp := range imports {
					depsMap[imp] = struct{}{}
				}
			}
		}
		deps0 := make([]string, len(depsMap))
		i := 0
		for imp := range depsMap {
			deps0[i] = imp
			i++
		}
		sort.Strings(deps0)
		deps := make([]interface{}, len(deps0))
		for i, imp := range deps0 {
			deps[i] = imp
		}

		// make all dirs relative to the current dir
		for i := 0; i < pt.NumField(); i++ {
			f := pt.Field(i)
			if strings.HasSuffix(f.Name, "Dir") {
				fv := pv.Field(i)
				dir := fv.Interface().(string)
				if dir != "" {
					dir, err := filepath.Rel(cwd, dir)
					if err != nil {
						return err
					}
					fv.Set(reflect.ValueOf(dir))
				}
			}
		}

		// fix up import path to be consistent when running as a program and as
		// a Docker container.
		pkg.ImportPath = filepath.Join(c.Repo, c.Subdir, pkg.Dir)

		units = append(units, &unit.SourceUnit{
			Name:         pkg.ImportPath,
			Type:         "GoPackage",
			Files:        files,
			Data:         pkg,
			Dependencies: deps,
		})
	}
	if err := cmd.Wait(); err != nil {
		return err
	}

	if err := json.NewEncoder(os.Stdout).Encode(units); err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>// +build solaris,cgo

package system

import (
	"fmt"
	"unsafe"
)

// #cgo LDFLAGS: -lkstat
// #include <unistd.h>
// #include <stdlib.h>
// #include <stdio.h>
// #include <kstat.h>
// #include <sys/swap.h>
// #include <sys/param.h>
// struct swaptable *allocSwaptable(int num) {
//	struct swaptable *st;
//	struct swapent *swapent;
// 	st = (struct swaptable *)malloc(num * sizeof(swapent_t) + sizeof (int));
//	swapent = st->swt_ent;
//	for (int i = 0; i < num; i++,swapent++) {
//		swapent->ste_path = (char *)malloc(MAXPATHLEN * sizeof (char));
//	}
//	st->swt_n = num;
//	return st;
//}
// void freeSwaptable (struct swaptable *st) {
//	struct swapent *swapent = st->swt_ent;
//	for (int i = 0; i < st->swt_n; i++,swapent++) {
//		free(swapent->ste_path);
//	}
//	free(st);
// }
// swapent_t getSwapEnt(swapent_t *ent, int i) {
//	return ent[i];
// }
// int64_t getPpKernel() {
//	int64_t pp_kernel = 0;
//	kstat_ctl_t *ksc;
//	kstat_t *ks;
//	kstat_named_t *knp;
//	kid_t kid;
//
//	if ((ksc = kstat_open()) == NULL) {
//		return -1;
//	}
//	if ((ks = kstat_lookup(ksc, "unix", 0, "system_pages")) == NULL) {
//		return -1;
//	}
//	if (((kid = kstat_read(ksc, ks, NULL)) == -1) ||
//	    ((knp = kstat_data_lookup(ks, "pp_kernel")) == NULL)) {
//		return -1;
//	}
//	switch (knp->data_type) {
//	case KSTAT_DATA_UINT64:
//		pp_kernel = knp->value.ui64;
//		break;
//	case KSTAT_DATA_UINT32:
//		pp_kernel = knp->value.ui32;
//		break;
//	}
//	pp_kernel *= sysconf(_SC_PAGESIZE);
//	return (pp_kernel > 0 ? pp_kernel : -1);
// }
import "C"

// Get the system memory info using sysconf same as prtconf
func getTotalMem() int64 {
	pagesize := C.sysconf(C._SC_PAGESIZE)
	npages := C.sysconf(C._SC_PHYS_PAGES)
	return int64(pagesize * npages)
}

func getFreeMem() int64 {
	pagesize := C.sysconf(C._SC_PAGESIZE)
	npages := C.sysconf(C._SC_AVPHYS_PAGES)
	return int64(pagesize * npages)
}

// ReadMemInfo retrieves memory statistics of the host system and returns a
//  MemInfo type.
func ReadMemInfo() (*MemInfo, error) {

	ppKernel := C.getPpKernel()
	MemTotal := getTotalMem()
	MemFree := getFreeMem()
	SwapTotal, SwapFree, err := getSysSwap()

	if ppKernel < 0 || MemTotal < 0 || MemFree < 0 || SwapTotal < 0 ||
		SwapFree < 0 {
		return nil, fmt.Errorf("Error getting system memory info %v\n", err)
	}

	meminfo := &MemInfo{}
	// Total memory is total physical memory less than memory locked by kernel
	meminfo.MemTotal = MemTotal - int64(ppKernel)
	meminfo.MemFree = MemFree
	meminfo.SwapTotal = SwapTotal
	meminfo.SwapFree = SwapFree

	return meminfo, nil
}

func getSysSwap() (int64, int64, error) {
	var tSwap int64
	var fSwap int64
	var diskblksPerPage int64
	num, err := C.swapctl(C.SC_GETNSWP, nil)
	if err != nil {
		return -1, -1, err
	}
	st := C.allocSwaptable(num)
	_, err = C.swapctl(C.SC_LIST, unsafe.Pointer(st))
	if err != nil {
		C.freeSwaptable(st)
		return -1, -1, err
	}

	diskblksPerPage = int64(C.sysconf(C._SC_PAGESIZE) >> C.DEV_BSHIFT)
	for i := 0; i < int(num); i++ {
		swapent := C.getSwapEnt(&st.swt_ent[0], C.int(i))
		tSwap += int64(swapent.ste_pages) * diskblksPerPage
		fSwap += int64(swapent.ste_free) * diskblksPerPage
	}
	C.freeSwaptable(st)
	return tSwap, fSwap, nil
}
<commit_msg>Add the minimal fix to restore being able to compile on Illumos.<commit_after>// +build solaris,cgo

package system

import (
	"fmt"
	"unsafe"
)

// #cgo CFLAGS: -std=c99
// #cgo LDFLAGS: -lkstat
// #include <unistd.h>
// #include <stdlib.h>
// #include <stdio.h>
// #include <kstat.h>
// #include <sys/swap.h>
// #include <sys/param.h>
// struct swaptable *allocSwaptable(int num) {
//	struct swaptable *st;
//	struct swapent *swapent;
// 	st = (struct swaptable *)malloc(num * sizeof(swapent_t) + sizeof (int));
//	swapent = st->swt_ent;
//	for (int i = 0; i < num; i++,swapent++) {
//		swapent->ste_path = (char *)malloc(MAXPATHLEN * sizeof (char));
//	}
//	st->swt_n = num;
//	return st;
//}
// void freeSwaptable (struct swaptable *st) {
//	struct swapent *swapent = st->swt_ent;
//	for (int i = 0; i < st->swt_n; i++,swapent++) {
//		free(swapent->ste_path);
//	}
//	free(st);
// }
// swapent_t getSwapEnt(swapent_t *ent, int i) {
//	return ent[i];
// }
// int64_t getPpKernel() {
//	int64_t pp_kernel = 0;
//	kstat_ctl_t *ksc;
//	kstat_t *ks;
//	kstat_named_t *knp;
//	kid_t kid;
//
//	if ((ksc = kstat_open()) == NULL) {
//		return -1;
//	}
//	if ((ks = kstat_lookup(ksc, "unix", 0, "system_pages")) == NULL) {
//		return -1;
//	}
//	if (((kid = kstat_read(ksc, ks, NULL)) == -1) ||
//	    ((knp = kstat_data_lookup(ks, "pp_kernel")) == NULL)) {
//		return -1;
//	}
//	switch (knp->data_type) {
//	case KSTAT_DATA_UINT64:
//		pp_kernel = knp->value.ui64;
//		break;
//	case KSTAT_DATA_UINT32:
//		pp_kernel = knp->value.ui32;
//		break;
//	}
//	pp_kernel *= sysconf(_SC_PAGESIZE);
//	return (pp_kernel > 0 ? pp_kernel : -1);
// }
import "C"

// Get the system memory info using sysconf same as prtconf
func getTotalMem() int64 {
	pagesize := C.sysconf(C._SC_PAGESIZE)
	npages := C.sysconf(C._SC_PHYS_PAGES)
	return int64(pagesize * npages)
}

func getFreeMem() int64 {
	pagesize := C.sysconf(C._SC_PAGESIZE)
	npages := C.sysconf(C._SC_AVPHYS_PAGES)
	return int64(pagesize * npages)
}

// ReadMemInfo retrieves memory statistics of the host system and returns a
//  MemInfo type.
func ReadMemInfo() (*MemInfo, error) {

	ppKernel := C.getPpKernel()
	MemTotal := getTotalMem()
	MemFree := getFreeMem()
	SwapTotal, SwapFree, err := getSysSwap()

	if ppKernel < 0 || MemTotal < 0 || MemFree < 0 || SwapTotal < 0 ||
		SwapFree < 0 {
		return nil, fmt.Errorf("Error getting system memory info %v\n", err)
	}

	meminfo := &MemInfo{}
	// Total memory is total physical memory less than memory locked by kernel
	meminfo.MemTotal = MemTotal - int64(ppKernel)
	meminfo.MemFree = MemFree
	meminfo.SwapTotal = SwapTotal
	meminfo.SwapFree = SwapFree

	return meminfo, nil
}

func getSysSwap() (int64, int64, error) {
	var tSwap int64
	var fSwap int64
	var diskblksPerPage int64
	num, err := C.swapctl(C.SC_GETNSWP, nil)
	if err != nil {
		return -1, -1, err
	}
	st := C.allocSwaptable(num)
	_, err = C.swapctl(C.SC_LIST, unsafe.Pointer(st))
	if err != nil {
		C.freeSwaptable(st)
		return -1, -1, err
	}

	diskblksPerPage = int64(C.sysconf(C._SC_PAGESIZE) >> C.DEV_BSHIFT)
	for i := 0; i < int(num); i++ {
		swapent := C.getSwapEnt(&st.swt_ent[0], C.int(i))
		tSwap += int64(swapent.ste_pages) * diskblksPerPage
		fSwap += int64(swapent.ste_free) * diskblksPerPage
	}
	C.freeSwaptable(st)
	return tSwap, fSwap, nil
}
<|endoftext|>


<commit_before>package sysinfo

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

const (
	cpuStatPath    = "/proc/stat"
	cpuInfoPath    = "/proc/cpuinfo"
	cpuMinFreqPath = "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_min_freq"
	cpuMaxFreqPath = "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq"
)

type CPUInfo struct {
	Name        string
	Model       uint64
	Family      uint64
	VendorID    string
	Stepping    string
	Cache       uint64
	Flags       []string
	MinFreq     uint64
	MaxFreq     uint64
	CoreCount   uint64
	ThreadCount uint64
	SocketCount uint64
}

type CPUStatInfo struct {
	Total     uint64
	User      uint64
	Nice      uint64
	System    uint64
	Idle      uint64
	IOWait    uint64
	IRQ       uint64
	SoftIRQ   uint64
	Steal     uint64
	Guest     uint64
	GuestNice uint64
}

func CPU() (*CPUInfo, error) {
	var cpu = &CPUInfo{}

	// read CPU max frequency
	minFreq, err := readSingleValueFile(cpuMinFreqPath)
	if err != nil {
		return nil, err
	}

	cpu.MinFreq, err = strconv.ParseUint(minFreq, 10, 64)
	if err != nil {
		return nil, err
	}

	// read CPU min frequency
	maxFreq, err := readSingleValueFile(cpuMaxFreqPath)
	if err != nil {
		return nil, err
	}

	cpu.MaxFreq, err = strconv.ParseUint(maxFreq, 10, 64)
	if err != nil {
		return nil, err
	}

	// parse cpuinfo file
	file, err := os.Open(cpuInfoPath)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	cores := map[uint64]struct{}{}
	sockets := map[uint64]struct{}{}

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		line := strings.TrimSpace(scanner.Text())
		if line == "" {
			continue
		}

		fields := strings.Split(line, ":")
		if len(fields) != 2 {
			return nil, ErrInvalidFileFormat
		}

		value := strings.TrimSpace(fields[1])
		key := strings.ToLower(strings.TrimSpace(fields[0]))
		switch key {
		case "processor":
			cpu.ThreadCount++

		case "model name":
			if cpu.Name == "" {
				cpu.Name = value
			}

		case "model":
			if cpu.Model != 0 {
				continue
			}

			cpu.Model, err = strconv.ParseUint(value, 10, 64)
			if err != nil {
				return nil, err
			}

		case "cpu family":
			if cpu.Family != 0 {
				continue
			}

			cpu.Family, err = strconv.ParseUint(value, 10, 64)
			if err != nil {
				return nil, err
			}

		case "vendor_id":
			if cpu.VendorID == "" {
				cpu.VendorID = value
			}

		case "stepping":
			if cpu.Stepping == "" {
				cpu.Stepping = value
			}

		case "cache size":
			if cpu.Cache != 0 {
				continue
			}

			cacheFields := strings.Fields(value)
			if len(cacheFields) != 2 {
				return nil, ErrInvalidFileFormat
			}

			cpu.Cache, err = strconv.ParseUint(cacheFields[0], 10, 64)
			if err != nil {
				return nil, err
			}

		case "physical id":
			socket, err := strconv.ParseUint(value, 10, 64)
			if err != nil {
				return nil, err
			}

			if _, ok := sockets[socket]; !ok {
				sockets[socket] = struct{}{}
			}

		case "core id":
			core, err := strconv.ParseUint(value, 10, 64)
			if err != nil {
				return nil, err
			}

			if _, ok := cores[core]; !ok {
				cores[core] = struct{}{}
			}

		case "flags":
			if len(cpu.Flags) > 0 {
				continue
			}

			cpu.Flags = strings.Fields(value)
		}
	}

	if err = scanner.Err(); err != nil {
		return nil, err
	}

	cpu.CoreCount = uint64(len(cores))
	cpu.SocketCount = uint64(len(sockets))

	return cpu, nil
}

func CPUStat() (statTotal *CPUStatInfo, statCores []*CPUStatInfo, err error) {
	file, err := os.Open(cpuStatPath)
	if err != nil {
		return nil, nil, err
	}
	defer file.Close()

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		line := strings.TrimSpace(scanner.Text())
		if !strings.HasPrefix(line, "cpu") {
			continue
		}

		fields := strings.Fields(line)
		if len(fields) != 11 {
			return nil, nil, err
		}

		stat := &CPUStatInfo{}
		stat.User, err = strconv.ParseUint(fields[1], 10, 64)
		if err != nil {
			return nil, nil, err
		}
		stat.Nice, err = strconv.ParseUint(fields[2], 10, 64)
		if err != nil {
			return nil, nil, err
		}
		stat.System, err = strconv.ParseUint(fields[3], 10, 64)
		if err != nil {
			return nil, nil, err
		}
		stat.Idle, err = strconv.ParseUint(fields[4], 10, 64)
		if err != nil {
			return nil, nil, err
		}
		stat.IOWait, err = strconv.ParseUint(fields[5], 10, 64)
		if err != nil {
			return nil, nil, err
		}
		stat.IRQ, err = strconv.ParseUint(fields[6], 10, 64)
		if err != nil {
			return nil, nil, err
		}
		stat.SoftIRQ, err = strconv.ParseUint(fields[7], 10, 64)
		if err != nil {
			return nil, nil, err
		}
		stat.Steal, err = strconv.ParseUint(fields[8], 10, 64)
		if err != nil {
			return nil, nil, err
		}
		stat.Guest, err = strconv.ParseUint(fields[9], 10, 64)
		if err != nil {
			return nil, nil, err
		}
		stat.GuestNice, err = strconv.ParseUint(fields[10], 10, 64)
		if err != nil {
			return nil, nil, err
		}

		stat.Total = stat.User + stat.Nice + stat.System + stat.Idle +
			stat.IOWait + stat.IRQ + stat.SoftIRQ + stat.Steal
		stat.User -= stat.Guest
		stat.Nice -= stat.GuestNice

		if fields[0] == "cpu" {
			statTotal = stat
			continue
		}

		statCores = append(statCores, stat)
	}

	if err = scanner.Err(); err != nil {
		return nil, nil, err
	}

	return
}

func CPUUsagePercent(firstSample, secondSample *CPUStatInfo) float64 {
	if firstSample == nil || secondSample == nil {
		return 0.0
	}
	if firstSample.Total == 0 && secondSample.Total == 0 {
		return 0.0
	}

	if firstSample.Total > secondSample.Total {
		firstSample, secondSample = secondSample, firstSample
	}

	deltaTotal := secondSample.Total - firstSample.Total
	if deltaTotal == 0 {
		deltaTotal = secondSample.Total
	}

	deltaIdle := (secondSample.Idle + secondSample.IOWait) -
		(firstSample.Idle + firstSample.IOWait)
	if deltaIdle == 0 {
		deltaIdle = secondSample.Idle
	}

	return float64(deltaTotal-deltaIdle) / float64(deltaTotal) * 100
}
<commit_msg>Add CPUTotalUsage function<commit_after>package sysinfo

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

const (
	cpuStatPath    = "/proc/stat"
	cpuInfoPath    = "/proc/cpuinfo"
	cpuMinFreqPath = "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_min_freq"
	cpuMaxFreqPath = "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq"
)

type CPUInfo struct {
	Name        string
	Model       uint64
	Family      uint64
	VendorID    string
	Stepping    string
	Cache       uint64
	Flags       []string
	MinFreq     uint64
	MaxFreq     uint64
	CoreCount   uint64
	ThreadCount uint64
	SocketCount uint64
}

type CPUStatInfo struct {
	Total     uint64
	User      uint64
	Nice      uint64
	System    uint64
	Idle      uint64
	IOWait    uint64
	IRQ       uint64
	SoftIRQ   uint64
	Steal     uint64
	Guest     uint64
	GuestNice uint64
}

func CPU() (*CPUInfo, error) {
	var cpu = &CPUInfo{}

	// read CPU max frequency
	minFreq, err := readSingleValueFile(cpuMinFreqPath)
	if err != nil {
		return nil, err
	}

	cpu.MinFreq, err = strconv.ParseUint(minFreq, 10, 64)
	if err != nil {
		return nil, err
	}

	// read CPU min frequency
	maxFreq, err := readSingleValueFile(cpuMaxFreqPath)
	if err != nil {
		return nil, err
	}

	cpu.MaxFreq, err = strconv.ParseUint(maxFreq, 10, 64)
	if err != nil {
		return nil, err
	}

	// parse cpuinfo file
	file, err := os.Open(cpuInfoPath)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	cores := map[uint64]struct{}{}
	sockets := map[uint64]struct{}{}

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		line := strings.TrimSpace(scanner.Text())
		if line == "" {
			continue
		}

		fields := strings.Split(line, ":")
		if len(fields) != 2 {
			return nil, ErrInvalidFileFormat
		}

		value := strings.TrimSpace(fields[1])
		key := strings.ToLower(strings.TrimSpace(fields[0]))
		switch key {
		case "processor":
			cpu.ThreadCount++

		case "model name":
			if cpu.Name == "" {
				cpu.Name = value
			}

		case "model":
			if cpu.Model != 0 {
				continue
			}

			cpu.Model, err = strconv.ParseUint(value, 10, 64)
			if err != nil {
				return nil, err
			}

		case "cpu family":
			if cpu.Family != 0 {
				continue
			}

			cpu.Family, err = strconv.ParseUint(value, 10, 64)
			if err != nil {
				return nil, err
			}

		case "vendor_id":
			if cpu.VendorID == "" {
				cpu.VendorID = value
			}

		case "stepping":
			if cpu.Stepping == "" {
				cpu.Stepping = value
			}

		case "cache size":
			if cpu.Cache != 0 {
				continue
			}

			cacheFields := strings.Fields(value)
			if len(cacheFields) != 2 {
				return nil, ErrInvalidFileFormat
			}

			cpu.Cache, err = strconv.ParseUint(cacheFields[0], 10, 64)
			if err != nil {
				return nil, err
			}

		case "physical id":
			socket, err := strconv.ParseUint(value, 10, 64)
			if err != nil {
				return nil, err
			}

			if _, ok := sockets[socket]; !ok {
				sockets[socket] = struct{}{}
			}

		case "core id":
			core, err := strconv.ParseUint(value, 10, 64)
			if err != nil {
				return nil, err
			}

			if _, ok := cores[core]; !ok {
				cores[core] = struct{}{}
			}

		case "flags":
			if len(cpu.Flags) > 0 {
				continue
			}

			cpu.Flags = strings.Fields(value)
		}
	}

	if err = scanner.Err(); err != nil {
		return nil, err
	}

	cpu.CoreCount = uint64(len(cores))
	cpu.SocketCount = uint64(len(sockets))

	return cpu, nil
}

func CPUStat() (statTotal *CPUStatInfo, statCores []*CPUStatInfo, err error) {
	file, err := os.Open(cpuStatPath)
	if err != nil {
		return nil, nil, err
	}
	defer file.Close()

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		line := strings.TrimSpace(scanner.Text())
		if !strings.HasPrefix(line, "cpu") {
			continue
		}

		fields := strings.Fields(line)
		if len(fields) != 11 {
			return nil, nil, ErrInvalidFileFormat
		}

		stat := &CPUStatInfo{}
		stat.User, err = strconv.ParseUint(fields[1], 10, 64)
		if err != nil {
			return nil, nil, err
		}
		stat.Nice, err = strconv.ParseUint(fields[2], 10, 64)
		if err != nil {
			return nil, nil, err
		}
		stat.System, err = strconv.ParseUint(fields[3], 10, 64)
		if err != nil {
			return nil, nil, err
		}
		stat.Idle, err = strconv.ParseUint(fields[4], 10, 64)
		if err != nil {
			return nil, nil, err
		}
		stat.IOWait, err = strconv.ParseUint(fields[5], 10, 64)
		if err != nil {
			return nil, nil, err
		}
		stat.IRQ, err = strconv.ParseUint(fields[6], 10, 64)
		if err != nil {
			return nil, nil, err
		}
		stat.SoftIRQ, err = strconv.ParseUint(fields[7], 10, 64)
		if err != nil {
			return nil, nil, err
		}
		stat.Steal, err = strconv.ParseUint(fields[8], 10, 64)
		if err != nil {
			return nil, nil, err
		}
		stat.Guest, err = strconv.ParseUint(fields[9], 10, 64)
		if err != nil {
			return nil, nil, err
		}
		stat.GuestNice, err = strconv.ParseUint(fields[10], 10, 64)
		if err != nil {
			return nil, nil, err
		}

		stat.Total = stat.User + stat.Nice + stat.System + stat.Idle +
			stat.IOWait + stat.IRQ + stat.SoftIRQ + stat.Steal
		stat.User -= stat.Guest
		stat.Nice -= stat.GuestNice

		if fields[0] == "cpu" {
			statTotal = stat
			continue
		}

		statCores = append(statCores, stat)
	}

	if err = scanner.Err(); err != nil {
		return nil, nil, err
	}

	return
}

func CPUTotalUsage() (uint64, error) {
	var usage uint64

	file, err := os.Open(cpuStatPath)
	if err != nil {
		return 0, err
	}
	defer file.Close()

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		line := strings.TrimSpace(scanner.Text())
		if !strings.HasPrefix(line, "cpu") {
			continue
		}

		fields := strings.Fields(line)
		if len(fields) != 11 {
			return 0, ErrInvalidFileFormat
		}

		if fields[0] != "cpu" {
			continue
		}

		for _, field := range fields[1:] {
			val, err := strconv.ParseUint(field, 10, 64)
			if err != nil {
				return 0, err
			}

			usage += val
		}
	}

	if err = scanner.Err(); err != nil {
		return 0, err
	}

	return usage, nil
}

func CPUUsagePercent(firstSample, secondSample *CPUStatInfo) float64 {
	if firstSample == nil || secondSample == nil {
		return 0.0
	}
	if firstSample.Total == 0 && secondSample.Total == 0 {
		return 0.0
	}

	if firstSample.Total > secondSample.Total {
		firstSample, secondSample = secondSample, firstSample
	}

	deltaTotal := secondSample.Total - firstSample.Total
	if deltaTotal == 0 {
		deltaTotal = secondSample.Total
	}

	deltaIdle := (secondSample.Idle + secondSample.IOWait) -
		(firstSample.Idle + firstSample.IOWait)
	if deltaIdle == 0 {
		deltaIdle = secondSample.Idle
	}

	return float64(deltaTotal-deltaIdle) / float64(deltaTotal) * 100
}
<|endoftext|>


<commit_before>package goproc

import (
	"io/ioutil"
	"strconv"
	"strings"
)

type Stat struct {
	CPUStatAll CPUStat
	CPUStats   []CPUStat
}

type CPUStat struct {
	Id        string
	User      uint64
	Nice      uint64
	System    uint64
	Idle      uint64
	IOWait    uint64
	IRQ       uint64
	SoftIRQ   uint64
	Steal     uint64
	Guest     uint64
	GuestNice uint64
}

func parseCPUStat(line string) *CPUStat {
	fields := strings.Fields(line)
	s := CPUStat{}
	s.User, _ = strconv.ParseUint(fields[1], 10, 32)
	s.Nice, _ = strconv.ParseUint(fields[2], 10, 32)
	s.System, _ = strconv.ParseUint(fields[3], 10, 32)
	s.Idle, _ = strconv.ParseUint(fields[4], 10, 32)
	s.IOWait, _ = strconv.ParseUint(fields[5], 10, 32)
	s.IRQ, _ = strconv.ParseUint(fields[6], 10, 32)
	s.SoftIRQ, _ = strconv.ParseUint(fields[7], 10, 32)
	s.Steal, _ = strconv.ParseUint(fields[8], 10, 32)
	s.Guest, _ = strconv.ParseUint(fields[9], 10, 32)
	s.GuestNice, _ = strconv.ParseUint(fields[10], 10, 32)
	return &s
}

func ReadStat(path string) (*Stat, error) {
	b, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, err
	}
	content := string(b)
	lines := strings.Split(content, "\n")

	var stat Stat = Stat{}

	for i, line := range lines {
		if strings.HasPrefix(line, "cpu") {
			if cpuStat := parseCPUStat(line); cpuStat != nil {
				if i == 0 {
					stat.CPUStatAll = *cpuStat
				} else {
					stat.CPUStats = append(stat.CPUStats, *cpuStat)
				}
			}
		}
	}
	return &stat, nil
}
<commit_msg>parse intr, ctxt, btime<commit_after>package goproc

import (
	"io/ioutil"
	"strconv"
	"strings"
	"time"
)

type Stat struct {
	CPUStatAll      CPUStat
	CPUStats        []CPUStat
	Processes       uint64
	Interrupts      uint64
	ContextSwitches uint64
	BootTime        time.Time
}

type CPUStat struct {
	Id        string
	User      uint64
	Nice      uint64
	System    uint64
	Idle      uint64
	IOWait    uint64
	IRQ       uint64
	SoftIRQ   uint64
	Steal     uint64
	Guest     uint64
	GuestNice uint64
}

func parseCPUStat(line string) *CPUStat {
	fields := strings.Fields(line)
	s := CPUStat{}
	s.User, _ = strconv.ParseUint(fields[1], 10, 32)
	s.Nice, _ = strconv.ParseUint(fields[2], 10, 32)
	s.System, _ = strconv.ParseUint(fields[3], 10, 32)
	s.Idle, _ = strconv.ParseUint(fields[4], 10, 32)
	s.IOWait, _ = strconv.ParseUint(fields[5], 10, 32)
	s.IRQ, _ = strconv.ParseUint(fields[6], 10, 32)
	s.SoftIRQ, _ = strconv.ParseUint(fields[7], 10, 32)
	s.Steal, _ = strconv.ParseUint(fields[8], 10, 32)
	s.Guest, _ = strconv.ParseUint(fields[9], 10, 32)
	s.GuestNice, _ = strconv.ParseUint(fields[10], 10, 32)
	return &s
}

func ReadStat(path string) (*Stat, error) {
	b, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, err
	}
	content := string(b)
	lines := strings.Split(content, "\n")

	var stat Stat = Stat{}

	for i, line := range lines {
		if strings.HasPrefix(line, "cpu") {
			if cpuStat := parseCPUStat(line); cpuStat != nil {
				if i == 0 {
					stat.CPUStatAll = *cpuStat
				} else {
					stat.CPUStats = append(stat.CPUStats, *cpuStat)
				}
			}
		} else if strings.HasPrefix(line, "intr") {
			fields := strings.Fields(line)
			stat.Interrupts, _ = strconv.ParseUint(fields[1], 10, 64)
		} else if strings.HasPrefix(line, "ctxt") {
			fields := strings.Fields(line)
			stat.ContextSwitches, _ = strconv.ParseUint(fields[1], 10, 64)
		} else if strings.HasPrefix(line, "btime") {
			fields := strings.Fields(line)
			seconds, _ := strconv.ParseInt(fields[1], 10, 64)
			stat.BootTime = time.Unix(seconds, 0)
		} else if strings.HasPrefix(line, "processes") {
			fields := strings.Fields(line)
			stat.Processes, _ = strconv.ParseUint(fields[1], 10, 64)
		}
	}
	return &stat, nil
}
<|endoftext|>


<commit_before>package goproxy

import (
	"github.com/elazarl/goproxy/transport"
	"net/http"
	"regexp"
)

// ProxyCtx is the Proxy context, contains useful information about every request. It is passed to
// every user function. Also used as a logger.
type ProxyCtx struct {
	// Will contain the client request from the proxy
	Req *http.Request
	// Will contain the remote server's response (if available. nil if the request wasn't send yet)
	Resp  *http.Response
	RoundTrip *transport.RoundTripDetails
	sess  int32
	proxy *ProxyHttpServer
}

func (ctx *ProxyCtx) printf(msg string, argv ...interface{}) {
	ctx.proxy.Logger.Printf("[%03d] "+msg+"\n", append([]interface{}{ctx.sess & 0xFF}, argv...)...)
}

// Logf prints a message to the proxy's log. Should be used in a ProxyHttpServer's filter
// This message will be printed only if the Verbose field of the ProxyHttpServer is set to true
//
//	proxy.OnRequest().DoFunc(func(r *http.Request,ctx *goproxy.ProxyCtx) *http.Request{
//		nr := atomic.AddInt32(&counter,1)
//		ctx.Printf("So far %d requests",nr)
//		return r
//	})
func (ctx *ProxyCtx) Logf(msg string, argv ...interface{}) {
	if ctx.proxy.Verbose {
		ctx.printf("INFO: "+msg, argv...)
	}
}

// Warnf prints a message to the proxy's log. Should be used in a ProxyHttpServer's filter
// This message will always be printed.
//
//	proxy.OnRequest().DoFunc(func(r *http.Request,ctx *goproxy.ProxyCtx) *http.Request{
//		f,err := os.OpenFile(cachedContent)
//		if err != nil {
//			ctx.Warnf("error open file %v: %v",cachedContent,err)
//			return r
//		}
//		return r
//	})
func (ctx *ProxyCtx) Warnf(msg string, argv ...interface{}) {
	ctx.printf("WARN: "+msg, argv...)
}

var charsetFinder = regexp.MustCompile("charset=([^ ]*)")

// Will try to infer the character set of the request from the headers.
// Returns the empty string if we don't know which character set it used.
// Currently it will look for charset=<charset> in the Content-Type header of the request.
func (ctx *ProxyCtx) Charset() string {
	charsets := charsetFinder.FindStringSubmatch(ctx.Resp.Header.Get("Content-Type"))
	if charsets == nil {
		return ""
	}
	return charsets[1]
}
<commit_msg>add ctx.UserData<commit_after>package goproxy

import (
	"github.com/elazarl/goproxy/transport"
	"net/http"
	"regexp"
)

// ProxyCtx is the Proxy context, contains useful information about every request. It is passed to
// every user function. Also used as a logger.
type ProxyCtx struct {
	// Will contain the client request from the proxy
	Req *http.Request
	// Will contain the remote server's response (if available. nil if the request wasn't send yet)
	Resp  *http.Response
	RoundTrip *transport.RoundTripDetails
	// A handle for the user to keep data in the context, from the call of ReqHandler to the
	// call of RespHandler
	UserData interface{}
	sess  int32
	proxy *ProxyHttpServer
}

func (ctx *ProxyCtx) printf(msg string, argv ...interface{}) {
	ctx.proxy.Logger.Printf("[%03d] "+msg+"\n", append([]interface{}{ctx.sess & 0xFF}, argv...)...)
}

// Logf prints a message to the proxy's log. Should be used in a ProxyHttpServer's filter
// This message will be printed only if the Verbose field of the ProxyHttpServer is set to true
//
//	proxy.OnRequest().DoFunc(func(r *http.Request,ctx *goproxy.ProxyCtx) *http.Request{
//		nr := atomic.AddInt32(&counter,1)
//		ctx.Printf("So far %d requests",nr)
//		return r
//	})
func (ctx *ProxyCtx) Logf(msg string, argv ...interface{}) {
	if ctx.proxy.Verbose {
		ctx.printf("INFO: "+msg, argv...)
	}
}

// Warnf prints a message to the proxy's log. Should be used in a ProxyHttpServer's filter
// This message will always be printed.
//
//	proxy.OnRequest().DoFunc(func(r *http.Request,ctx *goproxy.ProxyCtx) *http.Request{
//		f,err := os.OpenFile(cachedContent)
//		if err != nil {
//			ctx.Warnf("error open file %v: %v",cachedContent,err)
//			return r
//		}
//		return r
//	})
func (ctx *ProxyCtx) Warnf(msg string, argv ...interface{}) {
	ctx.printf("WARN: "+msg, argv...)
}

var charsetFinder = regexp.MustCompile("charset=([^ ]*)")

// Will try to infer the character set of the request from the headers.
// Returns the empty string if we don't know which character set it used.
// Currently it will look for charset=<charset> in the Content-Type header of the request.
func (ctx *ProxyCtx) Charset() string {
	charsets := charsetFinder.FindStringSubmatch(ctx.Resp.Header.Get("Content-Type"))
	if charsets == nil {
		return ""
	}
	return charsets[1]
}
<|endoftext|>


<commit_before>package logging

import (
	"os"

	log "github.com/Sirupsen/logrus"
	prefixed "github.com/x-cray/logrus-prefixed-formatter"
)

var needsInit = true
var verboseMode = false

// InitLogger initializes the logging system
func InitLogger() {
	log.SetOutput(os.Stdout)
	prefixedFormatter := &prefixed.TextFormatter{ForceColors: true, TimestampFormat: "15:04:05.000"}

	log.SetFormatter(prefixedFormatter)
	log.SetLevel(log.InfoLevel)

	needsInit = false
}

// VerboseMode activates the verbose mode, allowing more traces to be outputted
func VerboseMode() {
	if needsInit {
		InitLogger()
	}
	verboseMode = true
}

// DebugMode activate the debug mode, lowering the log level to print out debug traces
func DebugMode() {
	if needsInit {
		InitLogger()
	}
	log.SetLevel(log.DebugLevel)

}

// Info prints out a Info level message
func Info(message string) {
	if needsInit {
		InitLogger()
	}
	log.Info(message)
}

// Step prints out a Info level message but only when in Verbose mode
func Step(message string) {
	if needsInit {
		InitLogger()
	}
	if verboseMode == true {
		log.Info(message)
	}
}

// Debug prints out a Debug level message
func Debug(message string) {
	if needsInit {
		InitLogger()
	}
	log.Debug(message)
} // Debug prints out a Debug level message

// Trace prints out more Debug level messages if Verbose activated
func Trace(message string) {
	if needsInit {
		InitLogger()
	}
	if verboseMode {
		log.Debug(message)
	}
}

// Fatal exits after printing out critical error
func Fatal(message string) {
	if needsInit {
		InitLogger()
	}
	log.Fatal(message)
}

// Die will exit after printing system error
func Die(message string) {
	if needsInit {
		InitLogger()
	}
	log.Panic(message)
}
<commit_msg>Add logger library<commit_after>package logging

import (
	"os"

	log "github.com/Sirupsen/logrus"
	prefixed "github.com/x-cray/logrus-prefixed-formatter"
)

var needsInit = true
var verboseMode = false

// InitLogger initializes the logging system
func InitLogger() {
	log.SetOutput(os.Stdout)
	prefixedFormatter := &prefixed.TextFormatter{ForceColors: true, TimestampFormat: "15:04:05.000"}

	log.SetFormatter(prefixedFormatter)
	log.SetLevel(log.InfoLevel)

	needsInit = false
}

// VerboseMode activates the verbose mode, allowing more traces to be outputted
func VerboseMode() {
	if needsInit {
		InitLogger()
	}
	verboseMode = true
}

// DebugMode activate the debug mode, lowering the log level to print out debug traces
func DebugMode() {
	if needsInit {
		InitLogger()
	}
	log.SetLevel(log.DebugLevel)

}

// Info prints out a Info level message
func Info(message string) {
	if needsInit {
		InitLogger()
	}
	log.Info(message)
}

// Step prints out a Info level message but only when in Verbose mode
func Step(message string) {
	if needsInit {
		InitLogger()
	}
	if verboseMode == true {
		log.Info(message)
	}
}

// Debug prints out a Debug level message
func Debug(message string) {
	if needsInit {
		InitLogger()
	}
	log.Debug(message)
} // Debug prints out a Debug level message

// Trace prints out more Debug level messages if Verbose activated
func Trace(message string) {
	if needsInit {
		InitLogger()
	}
	if verboseMode {
		log.Debug(message)
	}
}

// Fatal exits after printing out critical error
func Fatal(message string) {
	if needsInit {
		InitLogger()
	}
	log.Fatal(message)
}

// Die will exit after printing system error
func Die(message string) {
	if needsInit {
		InitLogger()
	}
	log.Panic(message)
}
<|endoftext|>


<commit_before>// Package mailjet provides methods for interacting with the last version of the Mailjet API.
// The goal of this component is to simplify the usage of the MailJet API for GO developers.
//
// For more details, see the full API Documentation at http://dev.mailjet.com/
package mailjet

import (
	"bytes"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/textproto"
	"os"
	"strings"
	"sync"
)

// NewMailjetClient returns a new MailjetClient using an public apikey
// and an secret apikey to be used when authenticating to API.
func NewMailjetClient(apiKeyPublic, apiKeyPrivate string, baseURL ...string) *Client {
	httpClient := NewHTTPClient(apiKeyPublic, apiKeyPrivate)
	smtpClient := NewSMTPClient(apiKeyPublic, apiKeyPrivate)

	client := &Client{
		httpClient: httpClient,
		smtpClient: smtpClient,
		mutex:      new(sync.Mutex),
		apiBase:    apiBase,
	}

	if len(baseURL) > 0 {
		client.apiBase = baseURL[0]
	}
	return client
}

// NewClient function
func NewClient(httpCl HTTPClientInterface, smtpCl SMTPClientInterface, baseURL ...string) *Client {

	client := &Client{
		httpClient: httpCl,
		smtpClient: smtpCl,
		apiBase:    apiBase,
		mutex:      new(sync.Mutex),
	}

	if len(baseURL) > 0 {
		client.apiBase = baseURL[0]
	}
	return client
}

// APIKeyPublic returns the public key.
func (c *Client) APIKeyPublic() string {
	return c.httpClient.APIKeyPublic()
}

// APIKeyPrivate returns the secret key.
func (c *Client) APIKeyPrivate() string {
	return c.httpClient.APIKeyPrivate()

}

// Client returns the underlying http client
func (c *Client) Client() *http.Client {
	return c.httpClient.Client()
}

// SetClient allows to customize http client.
func (c *Client) SetClient(client *http.Client) {
	c.mutex.Lock()
	defer c.mutex.Unlock()
	c.httpClient.SetClient(client)
}

// Filter applies a filter with the defined key and value.
func Filter(key, value string) RequestOptions {
	return func(req *http.Request) {
		q := req.URL.Query()
		q.Add(key, value)
		req.URL.RawQuery = strings.Replace(q.Encode(), "%2B", "+", 1)
	}
}

// SortOrder defines the order of the result.
type SortOrder int

// These are the two possible order.
const (
	SortDesc = SortOrder(iota)
	SortAsc
)

var debugOut io.Writer = os.Stderr

// SetDebugOutput sets the output destination for the debug.
func SetDebugOutput(w io.Writer) {
	debugOut = w
	log.SetOutput(w)
}

// Sort applies the Sort filter to the request.
func Sort(value string, order SortOrder) RequestOptions {
	if order == SortDesc {
		value = value + "+DESC"
	}
	return Filter("Sort", value)
}

// List issues a GET to list the specified resource
// and stores the result in the value pointed to by res.
// Filters can be add via functional options.
func (c *Client) List(resource string, resp interface{}, options ...RequestOptions) (count, total int, err error) {
	url := buildURL(c.apiBase, &Request{Resource: resource})
	req, err := createRequest("GET", url, nil, nil, options...)
	if err != nil {
		return count, total, err
	}

	c.mutex.Lock()
	defer c.mutex.Unlock()
	return c.httpClient.Send(req).Read(resp).Call()
}

// Get issues a GET to view a resource specifying an id
// and stores the result in the value pointed to by res.
// Filters can be add via functional options.
// Without an specified ID in MailjetRequest, it is the same as List.
func (c *Client) Get(mr *Request, resp interface{}, options ...RequestOptions) (err error) {
	url := buildURL(c.apiBase, mr)
	req, err := createRequest("GET", url, nil, nil, options...)
	if err != nil {
		return err
	}

	c.mutex.Lock()
	defer c.mutex.Unlock()
	_, _, err = c.httpClient.Send(req).Read(resp).Call()
	return err
}

// Post issues a POST to create a new resource
// and stores the result in the value pointed to by res.
// Filters can be add via functional options.
func (c *Client) Post(fmr *FullRequest, resp interface{}, options ...RequestOptions) (err error) {
	url := buildURL(c.apiBase, fmr.Info)
	req, err := createRequest("POST", url, fmr.Payload, nil, options...)
	if err != nil {
		return err
	}

	headers := map[string]string{"Content-Type": "application/json"}
	c.mutex.Lock()
	defer c.mutex.Unlock()
	_, _, err = c.httpClient.Send(req).With(headers).Read(resp).Call()
	return err
}

// Put is used to update a resource.
// Fields to be updated must be specified by the string array onlyFields.
// If onlyFields is nil, all fields except these with the tag read_only, are updated.
// Filters can be add via functional options.
func (c *Client) Put(fmr *FullRequest, onlyFields []string, options ...RequestOptions) (err error) {
	url := buildURL(c.apiBase, fmr.Info)
	req, err := createRequest("PUT", url, fmr.Payload, onlyFields, options...)
	if err != nil {
		return err
	}

	headers := map[string]string{"Content-Type": "application/json"}
	c.mutex.Lock()
	defer c.mutex.Unlock()
	_, _, err = c.httpClient.Send(req).With(headers).Call()
	return err
}

// Delete is used to delete a resource.
func (c *Client) Delete(mr *Request) (err error) {
	url := buildURL(c.apiBase, mr)
	req, err := createRequest("DELETE", url, nil, nil)
	if err != nil {
		return err
	}

	c.mutex.Lock()
	defer c.mutex.Unlock()
	_, _, err = c.httpClient.Send(req).Call()
	return err
}

// SendMail send mail via API.
func (c *Client) SendMail(data *InfoSendMail) (res *SentResult, err error) {
	url := c.apiBase + "/send/message"
	req, err := createRequest("POST", url, data, nil)
	if err != nil {
		return res, err
	}

	headers := map[string]string{"Content-Type": "application/json"}

	c.mutex.Lock()
	defer c.mutex.Unlock()
	_, _, err = c.httpClient.Send(req).With(headers).Read(&res).Call()
	return res, err
}

// SendMailSMTP send mail via SMTP.
func (c *Client) SendMailSMTP(info *InfoSMTP) error {
	return c.smtpClient.SendMail(
		info.From,
		info.Recipients,
		buildMessage(info.Header, info.Content))
}

func buildMessage(header textproto.MIMEHeader, content []byte) []byte {
	buff := bytes.NewBuffer(nil)
	for key, values := range header {
		buff.WriteString(fmt.Sprintf("%s: %s\r\n", key, strings.Join(values, ", ")))
	}
	buff.WriteString("\r\n")
	buff.Write(content)

	return buff.Bytes()
}
<commit_msg>Add SetURL method to the wrapper<commit_after>// Package mailjet provides methods for interacting with the last version of the Mailjet API.
// The goal of this component is to simplify the usage of the MailJet API for GO developers.
//
// For more details, see the full API Documentation at http://dev.mailjet.com/
package mailjet

import (
	"bytes"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/textproto"
	"os"
	"strings"
	"sync"
)

// NewMailjetClient returns a new MailjetClient using an public apikey
// and an secret apikey to be used when authenticating to API.
func NewMailjetClient(apiKeyPublic, apiKeyPrivate string, baseURL ...string) *Client {
	httpClient := NewHTTPClient(apiKeyPublic, apiKeyPrivate)
	smtpClient := NewSMTPClient(apiKeyPublic, apiKeyPrivate)

	client := &Client{
		httpClient: httpClient,
		smtpClient: smtpClient,
		mutex:      new(sync.Mutex),
		apiBase:    apiBase,
	}

	if len(baseURL) > 0 {
		client.apiBase = baseURL[0]
	}
	return client
}

// NewClient function
func NewClient(httpCl HTTPClientInterface, smtpCl SMTPClientInterface, baseURL ...string) *Client {

	client := &Client{
		httpClient: httpCl,
		smtpClient: smtpCl,
		apiBase:    apiBase,
		mutex:      new(sync.Mutex),
	}

	if len(baseURL) > 0 {
		client.apiBase = baseURL[0]
	}
	return client
}

// APIKeyPublic returns the public key.
func (c *Client) APIKeyPublic() string {
	return c.httpClient.APIKeyPublic()
}

// APIKeyPrivate returns the secret key.
func (c *Client) APIKeyPrivate() string {
	return c.httpClient.APIKeyPrivate()

}

// SetURL function to set the base url of the wrapper instance
func (c *Client) SetURL(baseURL string) {
	c.mutex.Lock()
	defer c.mutex.Unlock()
	c.apiBase = baseURL
}

// Client returns the underlying http client
func (c *Client) Client() *http.Client {
	return c.httpClient.Client()
}

// SetClient allows to customize http client.
func (c *Client) SetClient(client *http.Client) {
	c.mutex.Lock()
	defer c.mutex.Unlock()
	c.httpClient.SetClient(client)
}

// Filter applies a filter with the defined key and value.
func Filter(key, value string) RequestOptions {
	return func(req *http.Request) {
		q := req.URL.Query()
		q.Add(key, value)
		req.URL.RawQuery = strings.Replace(q.Encode(), "%2B", "+", 1)
	}
}

// SortOrder defines the order of the result.
type SortOrder int

// These are the two possible order.
const (
	SortDesc = SortOrder(iota)
	SortAsc
)

var debugOut io.Writer = os.Stderr

// SetDebugOutput sets the output destination for the debug.
func SetDebugOutput(w io.Writer) {
	debugOut = w
	log.SetOutput(w)
}

// Sort applies the Sort filter to the request.
func Sort(value string, order SortOrder) RequestOptions {
	if order == SortDesc {
		value = value + "+DESC"
	}
	return Filter("Sort", value)
}

// List issues a GET to list the specified resource
// and stores the result in the value pointed to by res.
// Filters can be add via functional options.
func (c *Client) List(resource string, resp interface{}, options ...RequestOptions) (count, total int, err error) {
	url := buildURL(c.apiBase, &Request{Resource: resource})
	req, err := createRequest("GET", url, nil, nil, options...)
	if err != nil {
		return count, total, err
	}

	c.mutex.Lock()
	defer c.mutex.Unlock()
	return c.httpClient.Send(req).Read(resp).Call()
}

// Get issues a GET to view a resource specifying an id
// and stores the result in the value pointed to by res.
// Filters can be add via functional options.
// Without an specified ID in MailjetRequest, it is the same as List.
func (c *Client) Get(mr *Request, resp interface{}, options ...RequestOptions) (err error) {
	url := buildURL(c.apiBase, mr)
	req, err := createRequest("GET", url, nil, nil, options...)
	if err != nil {
		return err
	}

	c.mutex.Lock()
	defer c.mutex.Unlock()
	_, _, err = c.httpClient.Send(req).Read(resp).Call()
	return err
}

// Post issues a POST to create a new resource
// and stores the result in the value pointed to by res.
// Filters can be add via functional options.
func (c *Client) Post(fmr *FullRequest, resp interface{}, options ...RequestOptions) (err error) {
	url := buildURL(c.apiBase, fmr.Info)
	req, err := createRequest("POST", url, fmr.Payload, nil, options...)
	if err != nil {
		return err
	}

	headers := map[string]string{"Content-Type": "application/json"}
	c.mutex.Lock()
	defer c.mutex.Unlock()
	_, _, err = c.httpClient.Send(req).With(headers).Read(resp).Call()
	return err
}

// Put is used to update a resource.
// Fields to be updated must be specified by the string array onlyFields.
// If onlyFields is nil, all fields except these with the tag read_only, are updated.
// Filters can be add via functional options.
func (c *Client) Put(fmr *FullRequest, onlyFields []string, options ...RequestOptions) (err error) {
	url := buildURL(c.apiBase, fmr.Info)
	req, err := createRequest("PUT", url, fmr.Payload, onlyFields, options...)
	if err != nil {
		return err
	}

	headers := map[string]string{"Content-Type": "application/json"}
	c.mutex.Lock()
	defer c.mutex.Unlock()
	_, _, err = c.httpClient.Send(req).With(headers).Call()
	return err
}

// Delete is used to delete a resource.
func (c *Client) Delete(mr *Request) (err error) {
	url := buildURL(c.apiBase, mr)
	req, err := createRequest("DELETE", url, nil, nil)
	if err != nil {
		return err
	}

	c.mutex.Lock()
	defer c.mutex.Unlock()
	_, _, err = c.httpClient.Send(req).Call()
	return err
}

// SendMail send mail via API.
func (c *Client) SendMail(data *InfoSendMail) (res *SentResult, err error) {
	url := c.apiBase + "/send/message"
	req, err := createRequest("POST", url, data, nil)
	if err != nil {
		return res, err
	}

	headers := map[string]string{"Content-Type": "application/json"}

	c.mutex.Lock()
	defer c.mutex.Unlock()
	_, _, err = c.httpClient.Send(req).With(headers).Read(&res).Call()
	return res, err
}

// SendMailSMTP send mail via SMTP.
func (c *Client) SendMailSMTP(info *InfoSMTP) error {
	return c.smtpClient.SendMail(
		info.From,
		info.Recipients,
		buildMessage(info.Header, info.Content))
}

func buildMessage(header textproto.MIMEHeader, content []byte) []byte {
	buff := bytes.NewBuffer(nil)
	for key, values := range header {
		buff.WriteString(fmt.Sprintf("%s: %s\r\n", key, strings.Join(values, ", ")))
	}
	buff.WriteString("\r\n")
	buff.Write(content)

	return buff.Bytes()
}
<|endoftext|>


<commit_before>// +build windows

/*
 * Copyright 2017 Dgraph Labs, Inc. and Contributors
 *
 * 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 badger

// OpenDir opens a directory in windows with write access for syncing.
import (
	"fmt"
	"os"
	"path/filepath"
	"syscall"

	"github.com/pkg/errors"
)

func openDir(path string) (*os.File, error) {
	fd, err := openDirWin(path)
	if err != nil {
		return nil, err
	}
	return os.NewFile(uintptr(fd), path), nil
}

func openDirWin(path string) (fd syscall.Handle, err error) {
	if len(path) == 0 {
		return syscall.InvalidHandle, syscall.ERROR_FILE_NOT_FOUND
	}
	pathp, err := syscall.UTF16PtrFromString(path)
	if err != nil {
		return syscall.InvalidHandle, err
	}
	access := uint32(syscall.GENERIC_READ | syscall.GENERIC_WRITE)
	sharemode := uint32(syscall.FILE_SHARE_READ | syscall.FILE_SHARE_WRITE)
	createmode := uint32(syscall.OPEN_EXISTING)
	fl := uint32(syscall.FILE_FLAG_BACKUP_SEMANTICS)
	return syscall.CreateFile(pathp, access, sharemode, nil, createmode, fl, 0)
}

// DirectoryLockGuard holds a lock on the directory.
type directoryLockGuard struct {
	path string
}

// AcquireDirectoryLock acquires exclusive access to a directory.
func acquireDirectoryLock(dirPath string, pidFileName string, readOnly bool) (*directoryLockGuard, error) {
	if readOnly {
		return nil, ErrWindowsNotSupported
	}

	// Convert to absolute path so that Release still works even if we do an unbalanced
	// chdir in the meantime.
	absLockFilePath, err := filepath.Abs(filepath.Join(dirPath, pidFileName))
	if err != nil {
		return nil, errors.Wrap(err, "Cannot get absolute path for pid lock file")
	}

	f, err := os.OpenFile(absLockFilePath, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666)
	if err != nil {
		return nil, errors.Wrapf(err,
			"Cannot create pid lock file %q.  Another process is using this Badger database",
			absLockFilePath)
	}
	_, err = fmt.Fprintf(f, "%d\n", os.Getpid())
	closeErr := f.Close()
	if err != nil {
		return nil, errors.Wrap(err, "Cannot write to pid lock file")
	}
	if closeErr != nil {
		return nil, errors.Wrap(closeErr, "Cannot close pid lock file")
	}
	return &directoryLockGuard{path: absLockFilePath}, nil
}

// Release removes the directory lock.
func (g *directoryLockGuard) release() error {
	path := g.path
	g.path = ""
	return os.Remove(path)
}
<commit_msg>Windows lock exists cant restart after crash (#572)<commit_after>// +build windows

/*
 * Copyright 2017 Dgraph Labs, Inc. and Contributors
 *
 * 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 badger

// OpenDir opens a directory in windows with write access for syncing.
import (
	"os"
	"path/filepath"
	"syscall"

	"github.com/pkg/errors"
)

// FILE_ATTRIBUTE_TEMPORARY - A file that is being used for temporary storage.
// FILE_FLAG_DELETE_ON_CLOSE - The file is to be deleted immediately after all of its handles are
// closed, which includes the specified handle and any other open or duplicated handles.
// See: https://docs.microsoft.com/en-us/windows/desktop/FileIO/file-attribute-constants
// NOTE: Added here to avoid importing golang.org/x/sys/windows
const (
	FILE_ATTRIBUTE_TEMPORARY  = 0x00000100
	FILE_FLAG_DELETE_ON_CLOSE = 0x04000000
)

func openDir(path string) (*os.File, error) {
	fd, err := openDirWin(path)
	if err != nil {
		return nil, err
	}
	return os.NewFile(uintptr(fd), path), nil
}

func openDirWin(path string) (fd syscall.Handle, err error) {
	if len(path) == 0 {
		return syscall.InvalidHandle, syscall.ERROR_FILE_NOT_FOUND
	}
	pathp, err := syscall.UTF16PtrFromString(path)
	if err != nil {
		return syscall.InvalidHandle, err
	}
	access := uint32(syscall.GENERIC_READ | syscall.GENERIC_WRITE)
	sharemode := uint32(syscall.FILE_SHARE_READ | syscall.FILE_SHARE_WRITE)
	createmode := uint32(syscall.OPEN_EXISTING)
	fl := uint32(syscall.FILE_FLAG_BACKUP_SEMANTICS)
	return syscall.CreateFile(pathp, access, sharemode, nil, createmode, fl, 0)
}

// DirectoryLockGuard holds a lock on the directory.
type directoryLockGuard struct {
	h    syscall.Handle
	path string
}

// AcquireDirectoryLock acquires exclusive access to a directory.
func acquireDirectoryLock(dirPath string, pidFileName string, readOnly bool) (*directoryLockGuard, error) {
	if readOnly {
		return nil, ErrWindowsNotSupported
	}

	// Convert to absolute path so that Release still works even if we do an unbalanced
	// chdir in the meantime.
	absLockFilePath, err := filepath.Abs(filepath.Join(dirPath, pidFileName))
	if err != nil {
		return nil, errors.Wrap(err, "Cannot get absolute path for pid lock file")
	}

	// This call creates a file handler in memory that only one process can use at a time. When
	// that process ends, the file is deleted by the system.
	// FILE_ATTRIBUTE_TEMPORARY is used to tell Windows to try to create the handle in memory.
	// FILE_FLAG_DELETE_ON_CLOSE is not specified in syscall_windows.go but tells Windows to delete
	// the file when all processes holding the handler are closed.
	// XXX: this works but it's a bit klunky. i'd prefer to use LockFileEx but it needs unsafe pkg.
	h, err := syscall.CreateFile(
		syscall.StringToUTF16Ptr(absLockFilePath), 0, 0, nil,
		syscall.OPEN_ALWAYS,
		uint32(FILE_ATTRIBUTE_TEMPORARY|FILE_FLAG_DELETE_ON_CLOSE),
		0)
	if err != nil {
		return nil, errors.Wrapf(err,
			"Cannot create lock file %q.  Another process is using this Badger database",
			absLockFilePath)
	}

	return &directoryLockGuard{h: h, path: absLockFilePath}, nil
}

// Release removes the directory lock.
func (g *directoryLockGuard) release() error {
	g.path = ""
	return syscall.CloseHandle(g.h)
}
<|endoftext|>


<commit_before>// Copyright (c) 2013 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 or at
// https://developers.google.com/open-source/licenses/bsd.

// Package lintutil provides helpers for writing linter command lines.
package lintutil // import "honnef.co/go/tools/lint/lintutil"

import (
	"errors"
	"flag"
	"fmt"
	"go/build"
	"go/parser"
	"log"
	"os"
	"strings"

	"honnef.co/go/tools/lint"

	"github.com/kisielk/gotool"
	"golang.org/x/tools/go/loader"
)

func usage(name string, flags *flag.FlagSet) func() {
	return func() {
		fmt.Fprintf(os.Stderr, "Usage of %s:\n", name)
		fmt.Fprintf(os.Stderr, "\t%s [flags] # runs on package in current directory\n", name)
		fmt.Fprintf(os.Stderr, "\t%s [flags] packages\n", name)
		fmt.Fprintf(os.Stderr, "\t%s [flags] directory\n", name)
		fmt.Fprintf(os.Stderr, "\t%s [flags] files... # must be a single package\n", name)
		fmt.Fprintf(os.Stderr, "Flags:\n")
		flags.PrintDefaults()
	}
}

type runner struct {
	checker lint.Checker
	tags    []string
	ignores []lint.Ignore

	unclean bool
}

func (runner runner) resolveRelative(importPaths []string) (goFiles bool, err error) {
	if len(importPaths) == 0 {
		return false, nil
	}
	if strings.HasSuffix(importPaths[0], ".go") {
		// User is specifying a package in terms of .go files, don't resolve
		return true, nil
	}
	wd, err := os.Getwd()
	if err != nil {
		return false, err
	}
	ctx := build.Default
	ctx.BuildTags = runner.tags
	for i, path := range importPaths {
		bpkg, err := ctx.Import(path, wd, build.FindOnly)
		if err != nil {
			return false, fmt.Errorf("can't load package %q: %v", path, err)
		}
		importPaths[i] = bpkg.ImportPath
	}
	return false, nil
}

func parseIgnore(s string) ([]lint.Ignore, error) {
	var out []lint.Ignore
	if len(s) == 0 {
		return nil, nil
	}
	for _, part := range strings.Fields(s) {
		p := strings.Split(part, ":")
		if len(p) != 2 {
			return nil, errors.New("malformed ignore string")
		}
		path := p[0]
		checks := strings.Split(p[1], ",")
		out = append(out, lint.Ignore{Pattern: path, Checks: checks})
	}
	return out, nil
}

func FlagSet(name string) *flag.FlagSet {
	flags := flag.NewFlagSet("", flag.ExitOnError)
	flags.Usage = usage(name, flags)
	flags.Float64("min_confidence", 0, "Deprecated; use -ignore instead")
	flags.String("tags", "", "List of `build tags`")
	flags.String("ignore", "", "Space separated list of checks to ignore, in the following format: 'import/path/file.go:Check1,Check2,...' Both the import path and file name sections support globbing, e.g. 'os/exec/*_test.go'")
	flags.Bool("tests", true, "Include tests")
	return flags
}

func ProcessFlagSet(name string, c lint.Checker, fs *flag.FlagSet) {
	tags := fs.Lookup("tags").Value.(flag.Getter).Get().(string)
	ignore := fs.Lookup("ignore").Value.(flag.Getter).Get().(string)
	tests := fs.Lookup("tests").Value.(flag.Getter).Get().(bool)

	ignores, err := parseIgnore(ignore)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	runner := &runner{
		checker: c,
		tags:    strings.Fields(tags),
		ignores: ignores,
	}
	paths := gotool.ImportPaths(fs.Args())
	goFiles, err := runner.resolveRelative(paths)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		runner.unclean = true
	}
	ctx := build.Default
	ctx.BuildTags = runner.tags
	conf := &loader.Config{
		Build:      &ctx,
		ParserMode: parser.ParseComments,
		ImportPkgs: map[string]bool{},
	}
	if goFiles {
		conf.CreateFromFilenames("adhoc", paths...)
		lprog, err := conf.Load()
		if err != nil {
			log.Fatal(err)
		}
		ps := runner.lint(lprog)
		for _, ps := range ps {
			for _, p := range ps {
				runner.unclean = true
				fmt.Printf("%v: %s\n", p.Position, p.Text)
			}
		}
	} else {
		conf.TypeCheckFuncBodies = func(s string) bool {
			for _, path := range paths {
				if s == path || s == path+"_test" {
					return true
				}
			}
			return false
		}
		for _, path := range paths {
			conf.ImportPkgs[path] = tests
		}
		lprog, err := conf.Load()
		if err != nil {
			log.Fatal(err)
		}
		ps := runner.lint(lprog)
		for _, ps := range ps {
			for _, p := range ps {
				runner.unclean = true
				fmt.Printf("%v: %s\n", p.Position, p.Text)
			}

		}
	}
	if runner.unclean {
		os.Exit(1)
	}
}

func ProcessArgs(name string, c lint.Checker, args []string) {
	flags := FlagSet(name)
	flags.Parse(args)

	ProcessFlagSet(name, c, flags)
}

func (runner *runner) lint(lprog *loader.Program) map[string][]lint.Problem {
	l := &lint.Linter{
		Checker: runner.checker,
		Ignores: runner.ignores,
	}
	return l.Lint(lprog)
}
<commit_msg>lint/lintutil: print relative paths in reported problems<commit_after>// Copyright (c) 2013 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 or at
// https://developers.google.com/open-source/licenses/bsd.

// Package lintutil provides helpers for writing linter command lines.
package lintutil // import "honnef.co/go/tools/lint/lintutil"

import (
	"errors"
	"flag"
	"fmt"
	"go/build"
	"go/parser"
	"go/token"
	"log"
	"os"
	"path/filepath"
	"strings"

	"honnef.co/go/tools/lint"

	"github.com/kisielk/gotool"
	"golang.org/x/tools/go/loader"
)

func usage(name string, flags *flag.FlagSet) func() {
	return func() {
		fmt.Fprintf(os.Stderr, "Usage of %s:\n", name)
		fmt.Fprintf(os.Stderr, "\t%s [flags] # runs on package in current directory\n", name)
		fmt.Fprintf(os.Stderr, "\t%s [flags] packages\n", name)
		fmt.Fprintf(os.Stderr, "\t%s [flags] directory\n", name)
		fmt.Fprintf(os.Stderr, "\t%s [flags] files... # must be a single package\n", name)
		fmt.Fprintf(os.Stderr, "Flags:\n")
		flags.PrintDefaults()
	}
}

type runner struct {
	checker lint.Checker
	tags    []string
	ignores []lint.Ignore

	unclean bool
}

func (runner runner) resolveRelative(importPaths []string) (goFiles bool, err error) {
	if len(importPaths) == 0 {
		return false, nil
	}
	if strings.HasSuffix(importPaths[0], ".go") {
		// User is specifying a package in terms of .go files, don't resolve
		return true, nil
	}
	wd, err := os.Getwd()
	if err != nil {
		return false, err
	}
	ctx := build.Default
	ctx.BuildTags = runner.tags
	for i, path := range importPaths {
		bpkg, err := ctx.Import(path, wd, build.FindOnly)
		if err != nil {
			return false, fmt.Errorf("can't load package %q: %v", path, err)
		}
		importPaths[i] = bpkg.ImportPath
	}
	return false, nil
}

func parseIgnore(s string) ([]lint.Ignore, error) {
	var out []lint.Ignore
	if len(s) == 0 {
		return nil, nil
	}
	for _, part := range strings.Fields(s) {
		p := strings.Split(part, ":")
		if len(p) != 2 {
			return nil, errors.New("malformed ignore string")
		}
		path := p[0]
		checks := strings.Split(p[1], ",")
		out = append(out, lint.Ignore{Pattern: path, Checks: checks})
	}
	return out, nil
}

func FlagSet(name string) *flag.FlagSet {
	flags := flag.NewFlagSet("", flag.ExitOnError)
	flags.Usage = usage(name, flags)
	flags.Float64("min_confidence", 0, "Deprecated; use -ignore instead")
	flags.String("tags", "", "List of `build tags`")
	flags.String("ignore", "", "Space separated list of checks to ignore, in the following format: 'import/path/file.go:Check1,Check2,...' Both the import path and file name sections support globbing, e.g. 'os/exec/*_test.go'")
	flags.Bool("tests", true, "Include tests")
	return flags
}

func ProcessFlagSet(name string, c lint.Checker, fs *flag.FlagSet) {
	tags := fs.Lookup("tags").Value.(flag.Getter).Get().(string)
	ignore := fs.Lookup("ignore").Value.(flag.Getter).Get().(string)
	tests := fs.Lookup("tests").Value.(flag.Getter).Get().(bool)

	ignores, err := parseIgnore(ignore)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	runner := &runner{
		checker: c,
		tags:    strings.Fields(tags),
		ignores: ignores,
	}
	paths := gotool.ImportPaths(fs.Args())
	goFiles, err := runner.resolveRelative(paths)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		runner.unclean = true
	}
	ctx := build.Default
	ctx.BuildTags = runner.tags
	conf := &loader.Config{
		Build:      &ctx,
		ParserMode: parser.ParseComments,
		ImportPkgs: map[string]bool{},
	}
	if goFiles {
		conf.CreateFromFilenames("adhoc", paths...)
		lprog, err := conf.Load()
		if err != nil {
			log.Fatal(err)
		}
		ps := runner.lint(lprog)
		for _, ps := range ps {
			for _, p := range ps {
				runner.unclean = true
				fmt.Printf("%v: %s\n", relativePositionString(p.Position), p.Text)
			}
		}
	} else {
		conf.TypeCheckFuncBodies = func(s string) bool {
			for _, path := range paths {
				if s == path || s == path+"_test" {
					return true
				}
			}
			return false
		}
		for _, path := range paths {
			conf.ImportPkgs[path] = tests
		}
		lprog, err := conf.Load()
		if err != nil {
			log.Fatal(err)
		}
		ps := runner.lint(lprog)
		for _, ps := range ps {
			for _, p := range ps {
				runner.unclean = true
				fmt.Printf("%v: %s\n", relativePositionString(p.Position), p.Text)
			}

		}
	}
	if runner.unclean {
		os.Exit(1)
	}
}

func relativePositionString(pos token.Position) string {
	var s string
	pwd, err := os.Getwd()
	if err == nil {
		rel, err := filepath.Rel(pwd, pos.Filename)
		if err == nil {
			s = rel
		}
	}
	if s == "" {
		s = pos.Filename
	}
	if pos.IsValid() {
		if s != "" {
			s += ":"
		}
		s += fmt.Sprintf("%d:%d", pos.Line, pos.Column)
	}
	if s == "" {
		s = "-"
	}
	return s
}

func ProcessArgs(name string, c lint.Checker, args []string) {
	flags := FlagSet(name)
	flags.Parse(args)

	ProcessFlagSet(name, c, flags)
}

func (runner *runner) lint(lprog *loader.Program) map[string][]lint.Problem {
	l := &lint.Linter{
		Checker: runner.checker,
		Ignores: runner.ignores,
	}
	return l.Lint(lprog)
}
<|endoftext|>