<commit_before>// Package magnet provides support for parsing magnet links.
package magnet

import (
	"encoding/base32"
	"encoding/hex"
	"errors"
	"net/url"
	"sort"
	"strconv"
	"strings"

	"github.com/multiformats/go-multihash"
)

type Magnet struct {
	InfoHash [20]byte
	Name     string
	Trackers [][]string
	Peers    []string
}

func New(s string) (*Magnet, error) {
	u, err := url.Parse(s)
	if err != nil {
		return nil, err
	}

	if u.Scheme != "magnet" {
		return nil, errors.New("not a magnet link")
	}

	params := u.Query()

	xts, ok := params["xt"]
	if !ok {
		return nil, errors.New("missing xt param")
	}
	if len(xts) == 0 {
		return nil, errors.New("empty xt param")
	}
	xt := xts[0]

	var magnet Magnet
	magnet.InfoHash, err = infoHashString(xt)
	if err != nil {
		return nil, err
	}

	names := params["dn"]
	if len(names) != 0 {
		magnet.Name = names[0]
	}

	var tiers []trackerTier
	for key, tier := range params {
		if key == "tr" {
			for i, tr := range tier {
				tiers = append(tiers, trackerTier{trackers: []string{tr}, index: i - len(tier)})
			}
		} else if strings.HasPrefix(key, "tr.") {
			index, err := strconv.Atoi(key[3:])
			if err == nil && index >= 0 {
				tiers = append(tiers, trackerTier{trackers: tier, index: index})
			}
		}
	}

	sort.Slice(tiers, func(i, j int) bool { return tiers[i].index < tiers[j].index })

	magnet.Trackers = make([][]string, len(tiers))
	for i, ti := range tiers {
		magnet.Trackers[i] = ti.trackers
	}

	magnet.Peers = params["x.pe"]

	return &magnet, nil
}

type trackerTier struct {
	trackers []string
	index    int
}

// infoHashString returns a new info hash value from a string.
// s must be 40 (hex encoded) or 32 (base32 encoded) characters, otherwise it returns error.
func infoHashString(xt string) ([20]byte, error) {
	var ih [20]byte
	var b []byte
	var err error
	switch {
	case strings.HasPrefix(xt, "urn:btih:"):
		xt = xt[9:]
		switch len(xt) {
		case 40:
			b, err = hex.DecodeString(xt)
		case 32:
			b, err = base32.StdEncoding.DecodeString(xt)
		default:
			return ih, errors.New("info hash must be 32 or 40 characters")
		}
		if err != nil {
			return ih, err
		}
	case strings.HasPrefix(xt, "urn:btmh:"):
		xt = xt[9:]
		b, err = multihash.FromHexString(xt)
		if err != nil {
			return ih, err
		}
		if len(b) != 20 {
			return ih, errors.New("invalid multihash (len != 20)")
		}
	default:
		return ih, errors.New("invalid xt param: must start with \"urn:btih:\" or \"urn:btmh\"")
	}
	copy(ih[:], b)
	return ih, nil
}
<commit_msg>filter out control chars in magnet links<commit_after>// Package magnet provides support for parsing magnet links.
package magnet

import (
	"encoding/base32"
	"encoding/hex"
	"errors"
	"net/url"
	"sort"
	"strconv"
	"strings"

	"github.com/multiformats/go-multihash"
)

type Magnet struct {
	InfoHash [20]byte
	Name     string
	Trackers [][]string
	Peers    []string
}

func New(s string) (*Magnet, error) {
	s = filterOutControlChars(s)

	u, err := url.Parse(s)
	if err != nil {
		return nil, err
	}

	if u.Scheme != "magnet" {
		return nil, errors.New("not a magnet link")
	}

	params := u.Query()

	xts, ok := params["xt"]
	if !ok {
		return nil, errors.New("missing xt param")
	}
	if len(xts) == 0 {
		return nil, errors.New("empty xt param")
	}
	xt := xts[0]

	var magnet Magnet
	magnet.InfoHash, err = infoHashString(xt)
	if err != nil {
		return nil, err
	}

	names := params["dn"]
	if len(names) != 0 {
		magnet.Name = names[0]
	}

	var tiers []trackerTier
	for key, tier := range params {
		if key == "tr" {
			for i, tr := range tier {
				tiers = append(tiers, trackerTier{trackers: []string{tr}, index: i - len(tier)})
			}
		} else if strings.HasPrefix(key, "tr.") {
			index, err := strconv.Atoi(key[3:])
			if err == nil && index >= 0 {
				tiers = append(tiers, trackerTier{trackers: tier, index: index})
			}
		}
	}

	sort.Slice(tiers, func(i, j int) bool { return tiers[i].index < tiers[j].index })

	magnet.Trackers = make([][]string, len(tiers))
	for i, ti := range tiers {
		magnet.Trackers[i] = ti.trackers
	}

	magnet.Peers = params["x.pe"]

	return &magnet, nil
}

type trackerTier struct {
	trackers []string
	index    int
}

// infoHashString returns a new info hash value from a string.
// s must be 40 (hex encoded) or 32 (base32 encoded) characters, otherwise it returns error.
func infoHashString(xt string) ([20]byte, error) {
	var ih [20]byte
	var b []byte
	var err error
	switch {
	case strings.HasPrefix(xt, "urn:btih:"):
		xt = xt[9:]
		switch len(xt) {
		case 40:
			b, err = hex.DecodeString(xt)
		case 32:
			b, err = base32.StdEncoding.DecodeString(xt)
		default:
			return ih, errors.New("info hash must be 32 or 40 characters")
		}
		if err != nil {
			return ih, err
		}
	case strings.HasPrefix(xt, "urn:btmh:"):
		xt = xt[9:]
		b, err = multihash.FromHexString(xt)
		if err != nil {
			return ih, err
		}
		if len(b) != 20 {
			return ih, errors.New("invalid multihash (len != 20)")
		}
	default:
		return ih, errors.New("invalid xt param: must start with \"urn:btih:\" or \"urn:btmh\"")
	}
	copy(ih[:], b)
	return ih, nil
}

func filterOutControlChars(s string) string {
	var sb strings.Builder
	sb.Grow(len(s))
	for i := 0; i < len(s); i++ {
		b := s[i]
		if b < ' ' || b == 0x7f {
			continue
		}
		sb.WriteByte(b)
	}
	return sb.String()
}
<|endoftext|>


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

// Package static builds static assets for the frontend and the worker.
package static

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"

	"github.com/evanw/esbuild/pkg/api"
)

type Config struct {
	// Entrypoint is a directory in which to to build TypeScript
	// sources.
	EntryPoint string

	// Bundle is true if files imported by an entry file
	// should be joined together in a single output file.
	Bundle bool

	// Watch is true in development. Sourcemaps are placed inline,
	// the output is unminified, and changes to any TypeScript
	// files will force a rebuild of the JavaScript output.
	Watch bool
}

// Build compiles TypeScript files into minified JavaScript
// files using github.com/evanw/esbuild.
//
// This function is used in Server.staticHandler with Watch=true
// when cmd/frontend is run in dev mode and in
// devtools/cmd/static/main.go with Watch=false for building
// productionized assets.
func Build(config Config) (*api.BuildResult, error) {
	files, err := getEntry(config.EntryPoint)
	if err != nil {
		return nil, err
	}
	options := api.BuildOptions{
		EntryPoints: files,
		Bundle:      config.Bundle,
		Outdir:      config.EntryPoint,
		Write:       true,
	}
	if config.Watch {
		options.Sourcemap = api.SourceMapInline
		options.Watch = &api.WatchMode{}
	} else {
		options.MinifyIdentifiers = true
		options.MinifySyntax = true
		options.MinifyWhitespace = true
		options.Sourcemap = api.SourceMapLinked
	}
	result := api.Build(options)
	if len(result.Errors) > 0 {
		return nil, fmt.Errorf("error building static files: %v", result.Errors)
	}
	if len(result.Warnings) > 0 {
		return nil, fmt.Errorf("error building static files: %v", result.Warnings)
	}
	return &result, nil
}

// getEntry walks the the given directory and collects entry file paths
// for esbuild. It ignores test files and files prefixed with an underscore.
// Underscore prefixed files are assumed to be imported by and bundled together
// with the output of an entry file.
func getEntry(dir string) ([]string, error) {
	var matches []string
	err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if info.IsDir() {
			return nil
		}
		basePath := filepath.Base(path)
		notPartial := !strings.HasPrefix(basePath, "_")
		notTest := !strings.HasSuffix(basePath, ".test.ts")
		matched, err := filepath.Match("*.ts", basePath)
		if err != nil {
			return err
		}
		if notPartial && notTest && matched {
			matches = append(matches, path)
		}
		return nil
	})
	if err != nil {
		return nil, err
	}
	return matches, nil
}
<commit_msg>internal/static: bundle and minifiy css files during static build<commit_after>// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package static builds static assets for the frontend and the worker.
package static

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"

	"github.com/evanw/esbuild/pkg/api"
)

type Config struct {
	// Entrypoint is a directory in which to to build TypeScript
	// sources.
	EntryPoint string

	// Bundle is true if files imported by an entry file
	// should be joined together in a single output file.
	Bundle bool

	// Watch is true in development. Sourcemaps are placed inline,
	// the output is unminified, and changes to any TypeScript
	// files will force a rebuild of the JavaScript output.
	Watch bool
}

// Build compiles TypeScript files into minified JavaScript
// files using github.com/evanw/esbuild.
//
// This function is used in Server.staticHandler with Watch=true
// when cmd/frontend is run in dev mode and in
// devtools/cmd/static/main.go with Watch=false for building
// productionized assets.
func Build(config Config) (*api.BuildResult, error) {
	files, err := getEntry(config.EntryPoint, config.Bundle)
	if err != nil {
		return nil, err
	}
	options := api.BuildOptions{
		EntryPoints:   files,
		Bundle:        config.Bundle,
		Outdir:        config.EntryPoint,
		Write:         true,
		OutExtensions: map[string]string{".css": ".min.css"},
		External:      []string{"*.svg"},
		Banner: map[string]string{"css": "/*!\n" +
			" * Copyright 2021 The Go Authors. All rights reserved.\n" +
			" * Use of this source code is governed by a BSD-style\n" +
			" * license that can be found in the LICENSE file.\n" +
			" */"},
	}
	if config.Watch {
		options.Sourcemap = api.SourceMapInline
		options.Watch = &api.WatchMode{}
	} else {
		options.MinifyIdentifiers = true
		options.MinifySyntax = true
		options.MinifyWhitespace = true
		options.Sourcemap = api.SourceMapLinked
	}
	result := api.Build(options)
	if len(result.Errors) > 0 {
		return nil, fmt.Errorf("error building static files: %v", result.Errors)
	}
	if len(result.Warnings) > 0 {
		return nil, fmt.Errorf("error building static files: %v", result.Warnings)
	}
	return &result, nil
}

// getEntry walks the the given directory and collects entry file paths
// for esbuild. It ignores test files and files prefixed with an underscore.
// Underscore prefixed files are assumed to be imported by and bundled together
// with the output of an entry file.
func getEntry(dir string, bundle bool) ([]string, error) {
	var matches []string
	err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if info.IsDir() {
			return nil
		}
		basePath := filepath.Base(path)
		notPartial := !strings.HasPrefix(basePath, "_")
		notTest := !strings.HasSuffix(basePath, ".test.ts")
		isTS := strings.HasSuffix(basePath, ".ts")
		isCSS := strings.HasSuffix(basePath, ".css") && !strings.HasSuffix(basePath, ".min.css")
		if notPartial && notTest && (isTS || (bundle && isCSS)) {
			matches = append(matches, path)
		}
		return nil
	})
	if err != nil {
		return nil, err
	}
	return matches, nil
}
<|endoftext|>


<commit_before>// Copyright 2016 Hajime Hoshi
//
// 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.

// +build !js

package ui

// TODO: Use golang.org/x/sys/windows (NewLazyDLL) instead of cgo.

// #cgo LDFLAGS: -lgdi32
//
// #include <windows.h>
//
// static int getCaptionHeight() {
//   return GetSystemMetrics(SM_CYCAPTION);
// }
import "C"

import (
	"github.com/hajimehoshi/ebiten/internal/devicescale"
)

func glfwScale() float64 {
	return devicescale.DeviceScale()
}

func adjustWindowPosition(x, y int) (int, int) {
	// As the video width/height might be wrong,
	// adjust x/y at least to enable to handle the window (#328)
	if x < 0 {
		x = 0
	}
	t := int(C.getCaptionHeight())
	if y < t {
		y = t
	}
	return x, y
}
<commit_msg>ui: Don't call devicescale.DeviceScale too often<commit_after>// Copyright 2016 Hajime Hoshi
//
// 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.

// +build !js

package ui

// TODO: Use golang.org/x/sys/windows (NewLazyDLL) instead of cgo.

// #cgo LDFLAGS: -lgdi32
//
// #include <windows.h>
//
// static int getCaptionHeight() {
//   return GetSystemMetrics(SM_CYCAPTION);
// }
import "C"

func glfwScale() float64 {
	// This function must be called on the main thread.
	return currentUI.deviceScale.Get()
}

func adjustWindowPosition(x, y int) (int, int) {
	// As the video width/height might be wrong,
	// adjust x/y at least to enable to handle the window (#328)
	if x < 0 {
		x = 0
	}
	t := int(C.getCaptionHeight())
	if y < t {
		y = t
	}
	return x, y
}
<|endoftext|>


<commit_before>package interpreter

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"regexp"
	"strings"
	"time"

	"github.com/maknahar/go-utils"
	"github.com/nlopes/slack"
)

type ReportResponse struct {
	CreatedAt      string `json:"CreatedAt"`
	CurrentTime    string `json:"CurrentTime"`
	FailureReason  string `json:"FailureReason"`
	FromTime       string `json:"FromTime"`
	Status         string `json:"Status"`
	ToTime         string `json:"ToTime"`
	UpdatedAt      string `json:"UpdatedAt"`
	Link           string
	MissingSession string
}

func GetReportStatus(staging bool) (*ReportResponse, error) {
	url := os.Getenv("REPORT_STATUS")
	if staging {
		url = os.Getenv("STAGING_REPORT_STATUS")
	}
	res, err := http.Get(url)
	if err != nil {
		return nil, fmt.Errorf("Error in getting order data %v", err)
	}

	d, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return nil, fmt.Errorf("Error in reading order data %v", err)
	}

	order := make([]ReportResponse, 0)
	err = json.Unmarshal(d, &order)
	if err != nil {
		log.Println("Error in decoding report response", err, go_utils.JsonPrettyPrint(string(d),
			"", "\t"))
		return nil, errors.New("Error in decoding report response")
	}

	l := len(order)
	if l == 0 {
		return nil, errors.New("Report Service might be down")
	}
	activity := &order[l-1]
	activity.Link = url

	return activity, nil
}

func (r *ReportResponse) GetDelayReason() string {
	loc, _ := time.LoadLocation("Asia/Kolkata")
	fromTime, err := time.ParseInLocation("2006-01-02T15:04:05.999999", r.FromTime, loc)
	if err != nil {
		return "Unable to parse to time. Err: %+v"
	}

	if strings.Contains(r.FailureReason, "SessionNotFound") {
		s := regexp.MustCompile("[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[8|9|aA|bB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$")
		r.MissingSession = s.FindString(r.FailureReason)
		return fmt.Sprintf("A Session is missing from data pack since %s", fromTime)
	}

	if r.FailureReason == "" {
		if time.Since(fromTime).Minutes() > 15 {
			return fmt.Sprintf("Report sync is running smoothly.")
		}
		return fmt.Sprintf("Report is in sync.")
	}

	return r.FailureReason
}

func (r *ReportResponse) FormatSlackMessage(attachment *slack.Attachment) {
	cause := r.GetDelayReason()
	attachment.Pretext = cause
	attachment.Title = "Report Sync Activity Details"
	attachment.TitleLink = r.Link
	if r.MissingSession != "" {
		attachment.Fields = append(attachment.Fields, slack.AttachmentField{
			Title: "Missing Session ID:",
			Value: r.MissingSession,
			Short: true})
	}

	attachment.Fields = append(attachment.Fields, slack.AttachmentField{
		Title: "Status:",
		Value: r.Status,
		Short: true})

	loc, _ := time.LoadLocation("Asia/Kolkata")
	fromTime, err := time.ParseInLocation("2006-01-02T15:04:05.999999", r.FromTime, loc)
	if err == nil {
		attachment.Fields = append(attachment.Fields, slack.AttachmentField{
			Title: "Delay:",
			Value: time.Since(fromTime).String(),
			Short: true})
	}

	ct, err := time.ParseInLocation("2006-01-02T15:04:05.999999", r.CreatedAt, loc)
	if err == nil {
		attachment.Fields = append(attachment.Fields, slack.AttachmentField{
			Title: "Created At:",
			Value: ct.Format("2006-01-02 15:04:05"),
			Short: true})
	}

	ut, err := time.ParseInLocation("2006-01-02T15:04:05.999999", r.UpdatedAt, loc)
	if err == nil {
		attachment.Fields = append(attachment.Fields, slack.AttachmentField{
			Title: "Last Updated At:",
			Value: ut.Format("2006-01-02 15:04:05"),
			Short: true})
	}

}
<commit_msg>Added service availability check<commit_after>package interpreter

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"regexp"
	"strings"
	"time"

	"github.com/maknahar/go-utils"
	"github.com/nlopes/slack"
)

type ReportResponse struct {
	CreatedAt      string `json:"CreatedAt"`
	CurrentTime    string `json:"CurrentTime"`
	FailureReason  string `json:"FailureReason"`
	FromTime       string `json:"FromTime"`
	Status         string `json:"Status"`
	ToTime         string `json:"ToTime"`
	UpdatedAt      string `json:"UpdatedAt"`
	Link           string
	MissingSession string
}

func GetReportStatus(staging bool) (*ReportResponse, error) {
	url := os.Getenv("REPORT_STATUS")
	if staging {
		url = os.Getenv("STAGING_REPORT_STATUS")
	}
	res, err := http.Get(url)
	if err != nil {
		return nil, fmt.Errorf("Error in getting order data %v", err)
	}

	d, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return nil, fmt.Errorf("Error in reading order data %v", err)
	}

	order := make([]ReportResponse, 0)
	err = json.Unmarshal(d, &order)
	if err != nil {
		if res.StatusCode == http.StatusServiceUnavailable {
			return nil, errors.New("Report Service is unavailable")
		}
		log.Println("Error in decoding report response", err, go_utils.JsonPrettyPrint(string(d),
			"", "\t"))
		return nil, errors.New("Error in decoding report response")
	}

	l := len(order)
	if l == 0 {
		return nil, errors.New("Report Service might be down")
	}
	activity := &order[l-1]
	activity.Link = url

	return activity, nil
}

func (r *ReportResponse) GetDelayReason() string {
	loc, _ := time.LoadLocation("Asia/Kolkata")
	fromTime, err := time.ParseInLocation("2006-01-02T15:04:05.999999", r.FromTime, loc)
	if err != nil {
		return "Unable to parse to time. Err: %+v"
	}

	if strings.Contains(r.FailureReason, "SessionNotFound") {
		s := regexp.MustCompile("[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[8|9|aA|bB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$")
		r.MissingSession = s.FindString(r.FailureReason)
		return fmt.Sprintf("A Session is missing from data pack since %s", fromTime)
	}

	if r.FailureReason == "" {
		if time.Since(fromTime).Minutes() > 15 {
			return fmt.Sprintf("Report sync is running smoothly.")
		}
		return fmt.Sprintf("Report is in sync.")
	}

	return r.FailureReason
}

func (r *ReportResponse) FormatSlackMessage(attachment *slack.Attachment) {
	cause := r.GetDelayReason()
	attachment.Pretext = cause
	attachment.Title = "Report Sync Activity Details"
	attachment.TitleLink = r.Link
	if r.MissingSession != "" {
		attachment.Fields = append(attachment.Fields, slack.AttachmentField{
			Title: "Missing Session ID:",
			Value: r.MissingSession,
			Short: true})
	}

	attachment.Fields = append(attachment.Fields, slack.AttachmentField{
		Title: "Status:",
		Value: r.Status,
		Short: true})

	loc, _ := time.LoadLocation("Asia/Kolkata")
	fromTime, err := time.ParseInLocation("2006-01-02T15:04:05.999999", r.FromTime, loc)
	if err == nil {
		attachment.Fields = append(attachment.Fields, slack.AttachmentField{
			Title: "Delay:",
			Value: time.Since(fromTime).String(),
			Short: true})
	}

	ct, err := time.ParseInLocation("2006-01-02T15:04:05.999999", r.CreatedAt, loc)
	if err == nil {
		attachment.Fields = append(attachment.Fields, slack.AttachmentField{
			Title: "Created At:",
			Value: ct.Format("2006-01-02 15:04:05"),
			Short: true})
	}

	ut, err := time.ParseInLocation("2006-01-02T15:04:05.999999", r.UpdatedAt, loc)
	if err == nil {
		attachment.Fields = append(attachment.Fields, slack.AttachmentField{
			Title: "Last Updated At:",
			Value: ut.Format("2006-01-02 15:04:05"),
			Short: true})
	}

}
<|endoftext|>


<commit_before>package inmem

import (
	"github.com/docker/libswarm/beam"
	"io"
	"sync"
)

func Pipe() (*PipeReceiver, *PipeSender) {
	p := new(pipe)
	p.rwait.L = &p.l
	p.wwait.L = &p.l
	r := &PipeReceiver{p}
	w := &PipeSender{p}
	return r, w
}

type pipe struct {
	ch    chan *pipeMessage
	rwait sync.Cond
	wwait sync.Cond
	l     sync.Mutex
	rl    sync.Mutex
	wl    sync.Mutex
	rerr  error // if reader closed, error to give writes
	werr  error // if writer closed, error to give reads
	pmsg  *pipeMessage
}

type pipeMessage struct {
	msg *beam.Message
	out *PipeSender
	in  *PipeReceiver
}

func (p *pipe) psend(pmsg *pipeMessage) error {
	var err error
	// One writer at a time.
	p.wl.Lock()
	defer p.wl.Unlock()

	p.l.Lock()
	defer p.l.Unlock()
	p.pmsg = pmsg
	p.rwait.Signal()
	for {
		if p.pmsg == nil {
			break
		}
		if p.rerr != nil {
			err = p.rerr
			break
		}
		if p.werr != nil {
			err = io.ErrClosedPipe
		}
		p.wwait.Wait()
	}
	p.pmsg = nil // in case of rerr or werr
	return err
}

func (p *pipe) send(msg *beam.Message, mode int) (in *PipeReceiver, out *PipeSender, err error) {
	// Prepare the message
	pmsg := &pipeMessage{msg: msg}
	if mode&beam.R != 0 {
		in, pmsg.out = Pipe()
		defer func() {
			if err != nil {
				in.Close()
				in = nil
				pmsg.out.Close()
			}
		}()
	}
	if mode&beam.W != 0 {
		pmsg.in, out = Pipe()
		defer func() {
			if err != nil {
				out.Close()
				out = nil
				pmsg.in.Close()
			}
		}()
	}
	err = p.psend(pmsg)
	return
}

func (p *pipe) preceive() (*pipeMessage, error) {
	p.rl.Lock()
	defer p.rl.Unlock()

	p.l.Lock()
	defer p.l.Unlock()
	for {
		if p.rerr != nil {
			return nil, io.ErrClosedPipe
		}
		if p.pmsg != nil {
			break
		}
		if p.werr != nil {
			return nil, p.werr
		}
		p.rwait.Wait()
	}
	pmsg := p.pmsg
	p.pmsg = nil
	p.wwait.Signal()
	return pmsg, nil
}

func (p *pipe) receive(mode int) (*beam.Message, *PipeReceiver, *PipeSender, error) {
	pmsg, err := p.preceive()
	if err != nil {
		return nil, nil, nil, err
	}
	if pmsg.out != nil && mode&beam.W == 0 {
		pmsg.out.Close()
		pmsg.out = nil
	}
	if pmsg.in != nil && mode&beam.R == 0 {
		pmsg.in.Close()
		pmsg.in = nil
	}
	return pmsg.msg, pmsg.in, pmsg.out, nil
}

func (p *pipe) rclose(err error) {
	if err == nil {
		err = io.ErrClosedPipe
	}
	p.l.Lock()
	defer p.l.Unlock()
	p.rerr = err
	p.rwait.Signal()
	p.wwait.Signal()
}

func (p *pipe) wclose(err error) {
	if err == nil {
		err = io.EOF
	}
	p.l.Lock()
	defer p.l.Unlock()
	p.werr = err
	p.rwait.Signal()
	p.wwait.Signal()
}

// PipeReceiver

type PipeReceiver struct {
	p *pipe
}

func (r *PipeReceiver) Receive(mode int) (*beam.Message, beam.Receiver, beam.Sender, error) {
	msg, pin, pout, err := r.p.receive(mode)
	if err != nil {
		return nil, nil, nil, err
	}
	var (
		// Always return NopReceiver/NopSender instead of nil values,
		// because:
		// - if they were requested in the mode, they can safely be used
		// - if they were not requested, they can safely be ignored (ie no leak if they
		// aren't closed)
		in  beam.Receiver = beam.NopReceiver{}
		out beam.Sender   = beam.NopSender{}
	)
	if pin != nil {
		in = pin
	}
	if pout != nil {
		out = pout
	}
	return msg, in, out, err
}

func (r *PipeReceiver) SendTo(dst beam.Sender) (int, error) {
	var n int
	// If the destination is a PipeSender, we can cheat
	pdst, ok := dst.(*PipeSender)
	if !ok {
		return 0, beam.ErrIncompatibleSender
	}
	for {
		pmsg, err := r.p.preceive()
		if err == io.EOF {
			break
		}
		if err != nil {
			return n, err
		}
		if err := pdst.p.psend(pmsg); err != nil {
			return n, err
		}
	}
	n++
	return n, nil
}

func (r *PipeReceiver) Close() error {
	return r.CloseWithError(nil)
}

func (r *PipeReceiver) CloseWithError(err error) error {
	r.p.rclose(err)
	return nil
}

// PipeSender

type PipeSender struct {
	p *pipe
}

func (w *PipeSender) Send(msg *beam.Message, mode int) (beam.Receiver, beam.Sender, error) {
	pin, pout, err := w.p.send(msg, mode)
	var (
		in  beam.Receiver
		out beam.Sender
	)
	if pin != nil {
		in = pin
	}
	if pout != nil {
		out = pout
	}
	return in, out, err
}

func (w *PipeSender) ReceiveFrom(src beam.Receiver) (int, error) {
	var n int
	// If the destination is a PipeReceiver, we can cheat
	psrc, ok := src.(*PipeReceiver)
	if !ok {
		return 0, beam.ErrIncompatibleReceiver
	}
	for {
		pmsg, err := psrc.p.preceive()
		if err == io.EOF {
			break
		}
		if err != nil {
			return n, err
		}
		if err := w.p.psend(pmsg); err != nil {
			return n, err
		}
		n++
	}
	return n, nil
}

func (w *PipeSender) Close() error {
	return w.CloseWithError(nil)
}

func (w *PipeSender) CloseWithError(err error) error {
	w.p.wclose(err)
	return nil
}
<commit_msg>beam/inmem: remove unused structure field<commit_after>package inmem

import (
	"github.com/docker/libswarm/beam"
	"io"
	"sync"
)

func Pipe() (*PipeReceiver, *PipeSender) {
	p := new(pipe)
	p.rwait.L = &p.l
	p.wwait.L = &p.l
	r := &PipeReceiver{p}
	w := &PipeSender{p}
	return r, w
}

type pipe struct {
	rwait sync.Cond
	wwait sync.Cond
	l     sync.Mutex
	rl    sync.Mutex
	wl    sync.Mutex
	rerr  error // if reader closed, error to give writes
	werr  error // if writer closed, error to give reads
	pmsg  *pipeMessage
}

type pipeMessage struct {
	msg *beam.Message
	out *PipeSender
	in  *PipeReceiver
}

func (p *pipe) psend(pmsg *pipeMessage) error {
	var err error
	// One writer at a time.
	p.wl.Lock()
	defer p.wl.Unlock()

	p.l.Lock()
	defer p.l.Unlock()
	p.pmsg = pmsg
	p.rwait.Signal()
	for {
		if p.pmsg == nil {
			break
		}
		if p.rerr != nil {
			err = p.rerr
			break
		}
		if p.werr != nil {
			err = io.ErrClosedPipe
		}
		p.wwait.Wait()
	}
	p.pmsg = nil // in case of rerr or werr
	return err
}

func (p *pipe) send(msg *beam.Message, mode int) (in *PipeReceiver, out *PipeSender, err error) {
	// Prepare the message
	pmsg := &pipeMessage{msg: msg}
	if mode&beam.R != 0 {
		in, pmsg.out = Pipe()
		defer func() {
			if err != nil {
				in.Close()
				in = nil
				pmsg.out.Close()
			}
		}()
	}
	if mode&beam.W != 0 {
		pmsg.in, out = Pipe()
		defer func() {
			if err != nil {
				out.Close()
				out = nil
				pmsg.in.Close()
			}
		}()
	}
	err = p.psend(pmsg)
	return
}

func (p *pipe) preceive() (*pipeMessage, error) {
	p.rl.Lock()
	defer p.rl.Unlock()

	p.l.Lock()
	defer p.l.Unlock()
	for {
		if p.rerr != nil {
			return nil, io.ErrClosedPipe
		}
		if p.pmsg != nil {
			break
		}
		if p.werr != nil {
			return nil, p.werr
		}
		p.rwait.Wait()
	}
	pmsg := p.pmsg
	p.pmsg = nil
	p.wwait.Signal()
	return pmsg, nil
}

func (p *pipe) receive(mode int) (*beam.Message, *PipeReceiver, *PipeSender, error) {
	pmsg, err := p.preceive()
	if err != nil {
		return nil, nil, nil, err
	}
	if pmsg.out != nil && mode&beam.W == 0 {
		pmsg.out.Close()
		pmsg.out = nil
	}
	if pmsg.in != nil && mode&beam.R == 0 {
		pmsg.in.Close()
		pmsg.in = nil
	}
	return pmsg.msg, pmsg.in, pmsg.out, nil
}

func (p *pipe) rclose(err error) {
	if err == nil {
		err = io.ErrClosedPipe
	}
	p.l.Lock()
	defer p.l.Unlock()
	p.rerr = err
	p.rwait.Signal()
	p.wwait.Signal()
}

func (p *pipe) wclose(err error) {
	if err == nil {
		err = io.EOF
	}
	p.l.Lock()
	defer p.l.Unlock()
	p.werr = err
	p.rwait.Signal()
	p.wwait.Signal()
}

// PipeReceiver

type PipeReceiver struct {
	p *pipe
}

func (r *PipeReceiver) Receive(mode int) (*beam.Message, beam.Receiver, beam.Sender, error) {
	msg, pin, pout, err := r.p.receive(mode)
	if err != nil {
		return nil, nil, nil, err
	}
	var (
		// Always return NopReceiver/NopSender instead of nil values,
		// because:
		// - if they were requested in the mode, they can safely be used
		// - if they were not requested, they can safely be ignored (ie no leak if they
		// aren't closed)
		in  beam.Receiver = beam.NopReceiver{}
		out beam.Sender   = beam.NopSender{}
	)
	if pin != nil {
		in = pin
	}
	if pout != nil {
		out = pout
	}
	return msg, in, out, err
}

func (r *PipeReceiver) SendTo(dst beam.Sender) (int, error) {
	var n int
	// If the destination is a PipeSender, we can cheat
	pdst, ok := dst.(*PipeSender)
	if !ok {
		return 0, beam.ErrIncompatibleSender
	}
	for {
		pmsg, err := r.p.preceive()
		if err == io.EOF {
			break
		}
		if err != nil {
			return n, err
		}
		if err := pdst.p.psend(pmsg); err != nil {
			return n, err
		}
	}
	n++
	return n, nil
}

func (r *PipeReceiver) Close() error {
	return r.CloseWithError(nil)
}

func (r *PipeReceiver) CloseWithError(err error) error {
	r.p.rclose(err)
	return nil
}

// PipeSender

type PipeSender struct {
	p *pipe
}

func (w *PipeSender) Send(msg *beam.Message, mode int) (beam.Receiver, beam.Sender, error) {
	pin, pout, err := w.p.send(msg, mode)
	var (
		in  beam.Receiver
		out beam.Sender
	)
	if pin != nil {
		in = pin
	}
	if pout != nil {
		out = pout
	}
	return in, out, err
}

func (w *PipeSender) ReceiveFrom(src beam.Receiver) (int, error) {
	var n int
	// If the destination is a PipeReceiver, we can cheat
	psrc, ok := src.(*PipeReceiver)
	if !ok {
		return 0, beam.ErrIncompatibleReceiver
	}
	for {
		pmsg, err := psrc.p.preceive()
		if err == io.EOF {
			break
		}
		if err != nil {
			return n, err
		}
		if err := w.p.psend(pmsg); err != nil {
			return n, err
		}
		n++
	}
	return n, nil
}

func (w *PipeSender) Close() error {
	return w.CloseWithError(nil)
}

func (w *PipeSender) CloseWithError(err error) error {
	w.p.wclose(err)
	return nil
}
<|endoftext|>


<commit_before>package router

import (
	"net/http"
	"appengine"
)

type RequestStruct struct {
	Route          Route
	PathParams     map[string]string
	HttpRequest    *http.Request
	ResponseWriter http.ResponseWriter
}

type Request interface {
	GetRoute() Route
	GetPathParams() map[string]string
	GetHttpRequest() *http.Request
	GetResponseWriter() http.ResponseWriter
	GetContext() appengine.Context
	GetContent() []byte
}

func (this RequestStruct) GetRoute() Route {
	return this.Route
}

func (this RequestStruct) GetPathParams() map[string]string {
	return this.PathParams
}

func (this RequestStruct) GetHttpRequest() *http.Request {
	return this.HttpRequest
}

func (this RequestStruct) GetResponseWriter() http.ResponseWriter {
	return this.ResponseWriter
}

func (this RequestStruct) GetContext() appengine.Context {
	return appengine.NewContext(this.HttpRequest)
}

func (this RequestStruct) GetContent() []byte {
	content := make([]byte, this.HttpRequest.ContentLength)
	this.HttpRequest.Body.Read(content)
	return content
}<commit_msg>Fixing formatting for request.go<commit_after>package router

import (
	"appengine"
	"net/http"
)

type RequestStruct struct {
	Route          Route
	PathParams     map[string]string
	HttpRequest    *http.Request
	ResponseWriter http.ResponseWriter
}

type Request interface {
	GetRoute() Route
	GetPathParams() map[string]string
	GetHttpRequest() *http.Request
	GetResponseWriter() http.ResponseWriter
	GetContext() appengine.Context
	GetContent() []byte
}

func (this RequestStruct) GetRoute() Route {
	return this.Route
}

func (this RequestStruct) GetPathParams() map[string]string {
	return this.PathParams
}

func (this RequestStruct) GetHttpRequest() *http.Request {
	return this.HttpRequest
}

func (this RequestStruct) GetResponseWriter() http.ResponseWriter {
	return this.ResponseWriter
}

func (this RequestStruct) GetContext() appengine.Context {
	return appengine.NewContext(this.HttpRequest)
}

func (this RequestStruct) GetContent() []byte {
	content := make([]byte, this.HttpRequest.ContentLength)
	this.HttpRequest.Body.Read(content)
	return content
}
<|endoftext|>


<commit_before>package focker_test

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"os"

	"github.com/hatofmonkeys/cloudfocker/focker"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
)

var _ = Describe("Focker", func() {
	var (
		testfocker *focker.Focker
		buffer     *gbytes.Buffer
	)
	BeforeEach(func() {
		testfocker = focker.NewFocker()
		buffer = gbytes.NewBuffer()
	})

	Describe("Displaying the docker version", func() {
		It("should tell Docker to output its version", func() {
			testfocker.DockerVersion(buffer)
			Eventually(buffer).Should(gbytes.Say(`Checking Docker version`))
			Eventually(buffer).Should(gbytes.Say(`Client API version: `))
			Eventually(buffer).Should(gbytes.Say(`Go version \(client\): go`))
		})
	})

	Describe("Bootstrapping the base image", func() {
		//This works, but speed depends on your net connection
		XIt("should download and tag the lucid64 filesystem", func() {
			fmt.Println("Downloading lucid64 - this could take a while")
			testfocker.ImportRootfsImage(buffer)
			Eventually(buffer, 600).Should(gbytes.Say(`[a-f0-9]{64}`))
		})
	})

	Describe("Writing a dockerfile", func() {
		It("should write a valid dockerfile", func() {
			testfocker.WriteDockerfile(buffer)
			Eventually(buffer).Should(gbytes.Say(`FROM`))
		})
	})

	Describe("Building a docker image", func() {
		It("should output a built image tag", func() {
			testfocker.BuildImage(buffer)
			Eventually(buffer, 20).Should(gbytes.Say(`Successfully built [a-f0-9]{12}`))
		})
	})

	Describe("Running the docker container", func() {
		It("should output a valid URL for the running application", func() {
			testfocker.RunContainer(buffer)
			Eventually(buffer, 20).Should(gbytes.Say(`Successfully built [a-f0-9]{12}`))
			Eventually(buffer).Should(gbytes.Say(`[a-f0-9]{64}`))
			Eventually(buffer).Should(gbytes.Say(`Connect to your running application at http://localhost:8080/`))
			Eventually(statusCodeChecker).Should(Equal(200))
			testfocker.StopContainer(buffer)
		})
	})

	Describe("Stopping the docker container", func() {
		It("should output the stopped image ID, not respond to HTTP, and delete the container", func() {
			testfocker.RunContainer(buffer)
			testfocker.StopContainer(buffer)
			Eventually(buffer).Should(gbytes.Say(`Stopping the CloudFocker container...`))
			Eventually(buffer).Should(gbytes.Say(`cloudfocker-container`))
			Eventually(statusCodeChecker).Should(Equal(0))
			Eventually(buffer).Should(gbytes.Say(`Deleting the CloudFocker container...`))
			Eventually(buffer).Should(gbytes.Say(`cloudfocker-container`))
		})
	})

	Describe("Adding a buildpack", func() {
		It("should download the buildpack and add it to the buildpack directory", func() {
			buildpackDir, _ := ioutil.TempDir(os.TempDir(), "cfocker-buildpack-test")
			buffer := gbytes.NewBuffer()
			testfocker.AddBuildpack(buffer, "https://github.com/hatofmonkeys/ruby-buildpack", buildpackDir)
			Eventually(buffer).Should(gbytes.Say(`Downloading buildpack...`))
			Eventually(buffer, 120).Should(gbytes.Say(`Downloaded buildpack.`))
			os.RemoveAll(buildpackDir)
		})
	})
})

func statusCodeChecker() int {
	res, err := http.Get("http://localhost:8080/")
	if err != nil {
		return 0
	} else {
		return res.StatusCode
	}
}
<commit_msg>Disabled buildpack download test for speed<commit_after>package focker_test

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"os"

	"github.com/hatofmonkeys/cloudfocker/focker"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
)

var _ = Describe("Focker", func() {
	var (
		testfocker *focker.Focker
		buffer     *gbytes.Buffer
	)
	BeforeEach(func() {
		testfocker = focker.NewFocker()
		buffer = gbytes.NewBuffer()
	})

	Describe("Displaying the docker version", func() {
		It("should tell Docker to output its version", func() {
			testfocker.DockerVersion(buffer)
			Eventually(buffer).Should(gbytes.Say(`Checking Docker version`))
			Eventually(buffer).Should(gbytes.Say(`Client API version: `))
			Eventually(buffer).Should(gbytes.Say(`Go version \(client\): go`))
		})
	})

	Describe("Bootstrapping the base image", func() {
		//This works, but speed depends on your net connection
		XIt("should download and tag the lucid64 filesystem", func() {
			fmt.Println("Downloading lucid64 - this could take a while")
			testfocker.ImportRootfsImage(buffer)
			Eventually(buffer, 600).Should(gbytes.Say(`[a-f0-9]{64}`))
		})
	})

	Describe("Writing a dockerfile", func() {
		It("should write a valid dockerfile", func() {
			testfocker.WriteDockerfile(buffer)
			Eventually(buffer).Should(gbytes.Say(`FROM`))
		})
	})

	Describe("Building a docker image", func() {
		It("should output a built image tag", func() {
			testfocker.BuildImage(buffer)
			Eventually(buffer, 20).Should(gbytes.Say(`Successfully built [a-f0-9]{12}`))
		})
	})

	Describe("Running the docker container", func() {
		It("should output a valid URL for the running application", func() {
			testfocker.RunContainer(buffer)
			Eventually(buffer, 20).Should(gbytes.Say(`Successfully built [a-f0-9]{12}`))
			Eventually(buffer).Should(gbytes.Say(`[a-f0-9]{64}`))
			Eventually(buffer).Should(gbytes.Say(`Connect to your running application at http://localhost:8080/`))
			Eventually(statusCodeChecker).Should(Equal(200))
			testfocker.StopContainer(buffer)
		})
	})

	Describe("Stopping the docker container", func() {
		It("should output the stopped image ID, not respond to HTTP, and delete the container", func() {
			testfocker.RunContainer(buffer)
			testfocker.StopContainer(buffer)
			Eventually(buffer).Should(gbytes.Say(`Stopping the CloudFocker container...`))
			Eventually(buffer).Should(gbytes.Say(`cloudfocker-container`))
			Eventually(statusCodeChecker).Should(Equal(0))
			Eventually(buffer).Should(gbytes.Say(`Deleting the CloudFocker container...`))
			Eventually(buffer).Should(gbytes.Say(`cloudfocker-container`))
		})
	})

	Describe("Adding a buildpack", func() {
		XIt("should download the buildpack and add it to the buildpack directory", func() {
			//This works, but speed depends on your net connection
			buildpackDir, _ := ioutil.TempDir(os.TempDir(), "cfocker-buildpack-test")
			buffer := gbytes.NewBuffer()
			testfocker.AddBuildpack(buffer, "https://github.com/hatofmonkeys/ruby-buildpack", buildpackDir)
			Eventually(buffer).Should(gbytes.Say(`Downloading buildpack...`))
			Eventually(buffer, 120).Should(gbytes.Say(`Downloaded buildpack.`))
			os.RemoveAll(buildpackDir)
		})
	})
})

func statusCodeChecker() int {
	res, err := http.Get("http://localhost:8080/")
	if err != nil {
		return 0
	} else {
		return res.StatusCode
	}
}
<|endoftext|>


<commit_before>package all

import (
	_ "github.com/karimra/gnmic/formatters/event_convert"
	_ "github.com/karimra/gnmic/formatters/event_date_string"
	_ "github.com/karimra/gnmic/formatters/event_delete"
	_ "github.com/karimra/gnmic/formatters/event_drop"
	_ "github.com/karimra/gnmic/formatters/event_strings"
	_ "github.com/karimra/gnmic/formatters/event_to_tag"
	_ "github.com/karimra/gnmic/formatters/event_write"
)
<commit_msg>register processor<commit_after>package all

import (
	_ "github.com/karimra/gnmic/formatters/event_add_tag"
	_ "github.com/karimra/gnmic/formatters/event_convert"
	_ "github.com/karimra/gnmic/formatters/event_date_string"
	_ "github.com/karimra/gnmic/formatters/event_delete"
	_ "github.com/karimra/gnmic/formatters/event_drop"
	_ "github.com/karimra/gnmic/formatters/event_strings"
	_ "github.com/karimra/gnmic/formatters/event_to_tag"
	_ "github.com/karimra/gnmic/formatters/event_write"
)
<|endoftext|>


<commit_before>/*
Copyright 2015 Google Inc. All rights reserved.

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 commands

import (
	"errors"
	"flag"
	"fmt"
	"github.com/google/git-appraise/commands/input"
	"github.com/google/git-appraise/repository"
	"github.com/google/git-appraise/review"
	"github.com/google/git-appraise/review/comment"
	"strings"
)

var commentFlagSet = flag.NewFlagSet("comment", flag.ExitOnError)

var (
	commentMessage = commentFlagSet.String("m", "", "Message to attach to the review")
	commentParent  = commentFlagSet.String("p", "", "Parent comment")
	commentFile    = commentFlagSet.String("f", "", "File being commented upon")
	commentLine    = commentFlagSet.Uint("l", 0, "Line being commented upon; requires that the -f flag also be set")
	commentLgtm    = commentFlagSet.Bool("lgtm", false, "'Looks Good To Me'. Set this to express your approval. This cannot be combined with nmw")
	commentNmw     = commentFlagSet.Bool("nmw", false, "'Needs More Work'. Set this to express your disapproval. This cannot be combined with lgtm")
)

// commentHashExists checks if the given comment hash exists in the given comment threads.
func commentHashExists(hashToFind string, threads []review.CommentThread) bool {
	for _, thread := range threads {
		if thread.Hash == hashToFind {
			return true
		}
		if commentHashExists(hashToFind, thread.Children) {
			return true
		}
	}
	return false
}

// checkCommentLocation verifies that the given location exists at the given commit.
func checkCommentLocation(repo repository.Repo, commit, file string, line uint) error {
	contents, err := repo.Show(commit, file)
	if err != nil {
		return err
	}
	lines := strings.Split(contents, "\n")
	if line >= uint(len(lines)) {
		return fmt.Errorf("Line number %d does not exist in file %q", line, file)
	}
	return nil
}

// commentOnReview adds a comment to the current code review.
func commentOnReview(repo repository.Repo, args []string) error {
	commentFlagSet.Parse(args)
	args = commentFlagSet.Args()

	var r *review.Review
	var err error
	if len(args) > 1 {
		return errors.New("Only accepting a single review is supported.")
	}

	if len(args) == 1 {
		r, err = review.Get(repo, args[0])
	} else {
		r, err = review.GetCurrent(repo)
	}

	if err != nil {
		return fmt.Errorf("Failed to load the review: %v\n", err)
	}
	if r == nil {
		return errors.New("There is no matching review.")
	}

	if *commentLgtm && *commentNmw {
		return errors.New("You cannot combine the flags -lgtm and -nmw.")
	}
	if *commentLine != 0 && *commentFile == "" {
		return errors.New("Specifying a line number with the -l flag requires that you also specify a file name with the -f flag.")
	}
	if *commentParent != "" && !commentHashExists(*commentParent, r.Comments) {
		return errors.New("There is no matching parent comment.")
	}

	if *commentMessage == "" {
		*commentMessage, err = input.LaunchEditor(repo, commentFilename)
		if err != nil {
			return err
		}
	}

	commentedUponCommit, err := r.GetHeadCommit()
	if err != nil {
		return err
	}
	location := comment.Location{
		Commit: commentedUponCommit,
	}
	if *commentFile != "" {
		if err := checkCommentLocation(r.Repo, commentedUponCommit, *commentFile, *commentLine); err != nil {
			return fmt.Errorf("Unabled to comment on the given location: %v", err)
		}
		location.Path = *commentFile
		if *commentLine != 0 {
			location.Range = &comment.Range{
				StartLine: uint32(*commentLine),
			}
		}
	}

	userEmail, err := repo.GetUserEmail()
	if err != nil {
		return err
	}
	c := comment.New(userEmail, *commentMessage)
	c.Location = &location
	c.Parent = *commentParent
	if *commentLgtm || *commentNmw {
		resolved := *commentLgtm
		c.Resolved = &resolved
	}
	return r.AddComment(c)
}

// commentCmd defines the "comment" subcommand.
var commentCmd = &Command{
	Usage: func(arg0 string) {
		fmt.Printf("Usage: %s comment [<option>...] [<review-hash>]\n\nOptions:\n", arg0)
		commentFlagSet.PrintDefaults()
	},
	RunMethod: func(repo repository.Repo, args []string) error {
		return commentOnReview(repo, args)
	},
}
<commit_msg>Submitting review 1b6d44cd17cb<commit_after>/*
Copyright 2015 Google Inc. All rights reserved.

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 commands

import (
	"errors"
	"flag"
	"fmt"
	"github.com/google/git-appraise/commands/input"
	"github.com/google/git-appraise/repository"
	"github.com/google/git-appraise/review"
	"github.com/google/git-appraise/review/comment"
	"strings"
)

var commentFlagSet = flag.NewFlagSet("comment", flag.ExitOnError)

var (
	commentMessage = commentFlagSet.String("m", "", "Message to attach to the review")
	commentParent  = commentFlagSet.String("p", "", "Parent comment")
	commentFile    = commentFlagSet.String("f", "", "File being commented upon")
	commentLine    = commentFlagSet.Uint("l", 0, "Line being commented upon; requires that the -f flag also be set")
	commentLgtm    = commentFlagSet.Bool("lgtm", false, "'Looks Good To Me'. Set this to express your approval. This cannot be combined with nmw")
	commentNmw     = commentFlagSet.Bool("nmw", false, "'Needs More Work'. Set this to express your disapproval. This cannot be combined with lgtm")
)

// commentHashExists checks if the given comment hash exists in the given comment threads.
func commentHashExists(hashToFind string, threads []review.CommentThread) bool {
	for _, thread := range threads {
		if thread.Hash == hashToFind {
			return true
		}
		if commentHashExists(hashToFind, thread.Children) {
			return true
		}
	}
	return false
}

// checkCommentLocation verifies that the given location exists at the given commit.
func checkCommentLocation(repo repository.Repo, commit, file string, line uint) error {
	contents, err := repo.Show(commit, file)
	if err != nil {
		return err
	}
	lines := strings.Split(contents, "\n")
	if line > uint(len(lines)) {
		return fmt.Errorf("Line number %d does not exist in file %q", line, file)
	}
	return nil
}

// commentOnReview adds a comment to the current code review.
func commentOnReview(repo repository.Repo, args []string) error {
	commentFlagSet.Parse(args)
	args = commentFlagSet.Args()

	var r *review.Review
	var err error
	if len(args) > 1 {
		return errors.New("Only accepting a single review is supported.")
	}

	if len(args) == 1 {
		r, err = review.Get(repo, args[0])
	} else {
		r, err = review.GetCurrent(repo)
	}

	if err != nil {
		return fmt.Errorf("Failed to load the review: %v\n", err)
	}
	if r == nil {
		return errors.New("There is no matching review.")
	}

	if *commentLgtm && *commentNmw {
		return errors.New("You cannot combine the flags -lgtm and -nmw.")
	}
	if *commentLine != 0 && *commentFile == "" {
		return errors.New("Specifying a line number with the -l flag requires that you also specify a file name with the -f flag.")
	}
	if *commentParent != "" && !commentHashExists(*commentParent, r.Comments) {
		return errors.New("There is no matching parent comment.")
	}

	if *commentMessage == "" {
		*commentMessage, err = input.LaunchEditor(repo, commentFilename)
		if err != nil {
			return err
		}
	}

	commentedUponCommit, err := r.GetHeadCommit()
	if err != nil {
		return err
	}
	location := comment.Location{
		Commit: commentedUponCommit,
	}
	if *commentFile != "" {
		if err := checkCommentLocation(r.Repo, commentedUponCommit, *commentFile, *commentLine); err != nil {
			return fmt.Errorf("Unabled to comment on the given location: %v", err)
		}
		location.Path = *commentFile
		if *commentLine != 0 {
			location.Range = &comment.Range{
				StartLine: uint32(*commentLine),
			}
		}
	}

	userEmail, err := repo.GetUserEmail()
	if err != nil {
		return err
	}
	c := comment.New(userEmail, *commentMessage)
	c.Location = &location
	c.Parent = *commentParent
	if *commentLgtm || *commentNmw {
		resolved := *commentLgtm
		c.Resolved = &resolved
	}
	return r.AddComment(c)
}

// commentCmd defines the "comment" subcommand.
var commentCmd = &Command{
	Usage: func(arg0 string) {
		fmt.Printf("Usage: %s comment [<option>...] [<review-hash>]\n\nOptions:\n", arg0)
		commentFlagSet.PrintDefaults()
	},
	RunMethod: func(repo repository.Repo, args []string) error {
		return commentOnReview(repo, args)
	},
}
<|endoftext|>


<commit_before>package commands

import (
	"fmt"
	"github.com/jingweno/gh/github"
	"github.com/jingweno/gh/utils"
	"regexp"
)

var cmdCompare = &Command{
	Run:   compare,
	Usage: "compare [-u] [USER] [<START>...]<END>",
	Short: "Open a compare page on GitHub",
	Long: `Open a GitHub compare view page in the system's default web browser.
<START> to <END> are branch names, tag names, or commit SHA1s specifying
the range of history to compare. If a range with two dots ("a..b") is given,
it will be transformed into one with three dots. If <START> is omitted,
GitHub will compare against the base branch (the default is "master").
If <END> is omitted, GitHub compare view is opened for the current branch.
With "-u", outputs the URL rather than opening the browser.
`,
}

var (
	flagCompareURLOnly bool
)

func init() {
	cmdCompare.Flag.BoolVarP(&flagCompareURLOnly, "url-only", "u", false, "URL only")

	CmdRunner.Use(cmdCompare)
}

/*
  $ gh compare refactor
  > open https://github.com/CURRENT_REPO/compare/refactor

  $ gh compare 1.0..1.1
  > open https://github.com/CURRENT_REPO/compare/1.0...1.1

  $ gh compare -u other-user patch
  > open https://github.com/other-user/REPO/compare/patch
*/
func compare(command *Command, args *Args) {
	localRepo := github.LocalRepo()
	var (
		branch  *github.Branch
		project *github.Project
		r       string
		err     error
	)

	branch, project, err = localRepo.RemoteBranchAndProject("")
	utils.Check(err)

	if args.IsParamsEmpty() {
		master := localRepo.MasterBranch()
		if master.ShortName() == branch.ShortName() {
			err = fmt.Errorf(command.FormattedUsage())
			utils.Check(err)
		} else {
			r = branch.ShortName()
		}
	} else {
		r = parseCompareRange(args.RemoveParam(args.ParamsSize() - 1))
		if args.IsParamsEmpty() {
			project, err = localRepo.CurrentProject()
			utils.Check(err)
		} else {
			project = github.NewProject(args.RemoveParam(args.ParamsSize()-1), "", "")
		}
	}

	subpage := utils.ConcatPaths("compare", r)
	url := project.WebURL("", "", subpage)
	launcher, err := utils.BrowserLauncher()
	utils.Check(err)

	if flagCompareURLOnly {
		args.Replace("echo", url)
	} else {
		args.Replace(launcher[0], "", launcher[1:]...)
		args.AppendParams(url)
	}
}

func parseCompareRange(r string) string {
	shaOrTag := fmt.Sprintf("((?:%s:)?\\w[\\w.-]+\\w)", OwnerRe)
	shaOrTagRange := fmt.Sprintf("^%s\\.\\.%s$", shaOrTag, shaOrTag)
	shaOrTagRangeRegexp := regexp.MustCompile(shaOrTagRange)
	return shaOrTagRangeRegexp.ReplaceAllString(r, "$1...$2")
}
<commit_msg>Escape slashes in compare URLs with semicolon<commit_after>package commands

import (
	"fmt"
	"regexp"
	"strings"

	"github.com/jingweno/gh/github"
	"github.com/jingweno/gh/utils"
)

var cmdCompare = &Command{
	Run:   compare,
	Usage: "compare [-u] [USER] [<START>...]<END>",
	Short: "Open a compare page on GitHub",
	Long: `Open a GitHub compare view page in the system's default web browser.
<START> to <END> are branch names, tag names, or commit SHA1s specifying
the range of history to compare. If a range with two dots ("a..b") is given,
it will be transformed into one with three dots. If <START> is omitted,
GitHub will compare against the base branch (the default is "master").
If <END> is omitted, GitHub compare view is opened for the current branch.
With "-u", outputs the URL rather than opening the browser.
`,
}

var (
	flagCompareURLOnly bool
)

func init() {
	cmdCompare.Flag.BoolVarP(&flagCompareURLOnly, "url-only", "u", false, "URL only")

	CmdRunner.Use(cmdCompare)
}

/*
  $ gh compare refactor
  > open https://github.com/CURRENT_REPO/compare/refactor

  $ gh compare 1.0..1.1
  > open https://github.com/CURRENT_REPO/compare/1.0...1.1

  $ gh compare -u other-user patch
  > open https://github.com/other-user/REPO/compare/patch
*/
func compare(command *Command, args *Args) {
	localRepo := github.LocalRepo()
	var (
		branch  *github.Branch
		project *github.Project
		r       string
		err     error
	)

	branch, project, err = localRepo.RemoteBranchAndProject("")
	utils.Check(err)

	if args.IsParamsEmpty() {
		master := localRepo.MasterBranch()
		if master.ShortName() == branch.ShortName() {
			err = fmt.Errorf(command.FormattedUsage())
			utils.Check(err)
		} else {
			r = branch.ShortName()
		}
	} else {
		r = parseCompareRange(args.RemoveParam(args.ParamsSize() - 1))
		if args.IsParamsEmpty() {
			project, err = localRepo.CurrentProject()
			utils.Check(err)
		} else {
			project = github.NewProject(args.RemoveParam(args.ParamsSize()-1), "", "")
		}
	}

	r = strings.Replace(r, "/", ";", -1)
	subpage := utils.ConcatPaths("compare", r)
	url := project.WebURL("", "", subpage)
	launcher, err := utils.BrowserLauncher()
	utils.Check(err)

	if flagCompareURLOnly {
		args.Replace("echo", url)
	} else {
		args.Replace(launcher[0], "", launcher[1:]...)
		args.AppendParams(url)
	}
}

func parseCompareRange(r string) string {
	shaOrTag := fmt.Sprintf("((?:%s:)?\\w[\\w.-]+\\w)", OwnerRe)
	shaOrTagRange := fmt.Sprintf("^%s\\.\\.%s$", shaOrTag, shaOrTag)
	shaOrTagRangeRegexp := regexp.MustCompile(shaOrTagRange)
	return shaOrTagRangeRegexp.ReplaceAllString(r, "$1...$2")
}
<|endoftext|>


<commit_before>package po

import (
	"fmt"
	"regexp"
	"sort"
	"strconv"
	"strings"
)

var example = `
#: faq_whyipv6.html
msgid "Note this is in addition to any NAT you do at home."
msgstr ""

#: faq_whyipv6.html
msgid "Q: So, why worry? NAT will work, right? I use NAT at home today after all.."
msgstr ""
`

var reWHITESPACE = regexp.MustCompile(`\s+`)

func unquote(s string) (string, error) {
	if len(s) == 0 {
		return s, nil
	}
	s = strings.TrimSpace(s)
	return strconv.Unquote(s)
}

// Languages returns the list of locales loaded in the combined *Files object
func (combined *Files) Languages() []string {
	ret := []string{}

	for k := range combined.ByLanguage {
		ret = append(ret, k)
	}
	sort.Strings(ret)
	return ret
}

// GetLocale simply returns the locale name; ie en_US or pt_BR
func (f *File) GetLocale() string {
	s := f.Locale
	return s
}

// GetLang returns the lowercase name string; ie en or pt
func (f *File) GetLang() string {
	s := f.Locale
	p := strings.Split(s, "_")
	return p[0]
}

// GetLangUC  returns the uppercase name string; ie EN or PT
func (f *File) GetLangUC() string {
	s := f.Locale
	p := strings.Split(s, "_")
	return strings.ToUpper(p[0])
}

// GetLang returns the lowercase name string; ie en or pt
func (f *File) GetLangName() string {
	s := f.Language
	s = Friendly(s)
	return s
}

// Translate takes a given input text, and returns back
// either the translated text, or the original text again.
func (f *File) Translate(input string, escapequotes bool) string {

	// Canonicalize.
	// Remove redundant, leading, and trailing whitespace.
	input = strings.TrimSpace(input)
	input = reWHITESPACE.ReplaceAllString(input, " ")

	if input == "lang" {
		return f.GetLang()
	}
	if input == "langUC" {
		return f.GetLangUC()
	}
	if input == "locale" {
		return f.GetLocale()
	}
	if input == "langname" {
		return f.GetLangName()
	}

	newtext := input

	if found, ok := f.ByID[input]; ok {
		c := found.MsgStr
		if c != "" {
			newtext = c
		}
	}

	if escapequotes {
		newtext = strings.Replace(newtext, `"`, `\"`, -1)
		newtext = strings.Replace(newtext, `'`, `\'`, -1)
	}
	// TODO escapequotes
	// Perl does this:
	//         $text =~ s/(?<![\\])"/\\"/g;
	//    $text =~ s/(?<![\\])'/\\'/g;
	// GO does not do look-behind assertions
	return newtext
}

// Translate takes a given input text, and returns back
// either the translated text, or the original text again.
func (f *File) Add(input string, context string, escapequotes bool) {

	//	log.Printf("po file Add(%s)\n", input)
	// Canonicalize.
	// Remove redundant, leading, and trailing whitespace.
	input = strings.TrimSpace(input)
	input = reWHITESPACE.ReplaceAllString(input, " ")

	//	log.Printf("po Add input=%s context=%s escape=%v\n", input, context, escapequotes)

	// Skip these, these will be dynamically responded to.
	if input == "lang" || input == "langUC" || input == "locale" {
		return
	}

	f.lock.Lock()
	defer f.lock.Unlock()

	_ = "breakpoint"

	if v, ok := f.ByID[input]; ok == false {
		// Not yet set?  Let's do so.
		//	fmt.Printf("DEBUG Saving Comment=%s MsgID=%s\n", context, input)
		f.ByID[input] = &Record{
			Comment: context,
			MsgID:   input,
			MsgStr:  "",
		}
		f.InOrder = append(f.InOrder, input)
	} else if strings.Contains(v.Comment, "not-used") {
		v.Comment = context // Update context
	} else {
		//	fmt.Printf("DEBUG ALREADY HAVE %#v\n", f.ByID[input])

	}

	/*
		if escapequotes {
			newtext = strings.Replace(newtext, `"`, `\"`, -1)
			newtext = strings.Replace(newtext, `'`, `\'`, -1)
		}
	*/

}

// ApacheAddLanguage  Generates the Apache "AddLanguage" text
func (f *Files) ApacheAddLanguage() string {
	list := append([]string{"en_US"}, f.Languages()...)
	text := ""
	seen := make(map[string]bool)

	add := func(s string) {
		if seen[s] == false {
			text = text + s + "\n"
			seen[s] = true
		}
	}

	for _, locale := range list {
		parts := strings.Split(locale, "_")
		if len(parts) > 0 {
			add(fmt.Sprintf("AddLanguage %s .%s", parts[0], locale))
		}
		dashed := strings.Replace(locale, "_", "-", -1)
		add(fmt.Sprintf("AddLanguage %s .%s", dashed, locale))

	}

	return text

}
<commit_msg>make percenttranslated available to translations<commit_after>package po

import (
	"fmt"
	"regexp"
	"sort"
	"strconv"
	"strings"
)

var example = `
#: faq_whyipv6.html
msgid "Note this is in addition to any NAT you do at home."
msgstr ""

#: faq_whyipv6.html
msgid "Q: So, why worry? NAT will work, right? I use NAT at home today after all.."
msgstr ""
`

var reWHITESPACE = regexp.MustCompile(`\s+`)

func unquote(s string) (string, error) {
	if len(s) == 0 {
		return s, nil
	}
	s = strings.TrimSpace(s)
	return strconv.Unquote(s)
}

// Languages returns the list of locales loaded in the combined *Files object
func (combined *Files) Languages() []string {
	ret := []string{}

	for k := range combined.ByLanguage {
		ret = append(ret, k)
	}
	sort.Strings(ret)
	return ret
}

// GetLocale simply returns the locale name; ie en_US or pt_BR
func (f *File) GetLocale() string {
	s := f.Locale
	return s
}

// GetLang returns the lowercase name string; ie en or pt
func (f *File) GetLang() string {
	s := f.Locale
	p := strings.Split(s, "_")
	return p[0]
}

// GetLangUC  returns the uppercase name string; ie EN or PT
func (f *File) GetLangUC() string {
	s := f.Locale
	p := strings.Split(s, "_")
	return strings.ToUpper(p[0])
}

// GetLang returns the lowercase name string; ie en or pt
func (f *File) GetLangName() string {
	s := f.Language
	s = Friendly(s)
	return s
}

// GetLangPercentTranslated returns what percentage of the translation is done
func (f *File) GetLangPercentTranslated() string {
	s := f.PercentTranslated
	return s
}

// Translate takes a given input text, and returns back
// either the translated text, or the original text again.
func (f *File) Translate(input string, escapequotes bool) string {

	// Canonicalize.
	// Remove redundant, leading, and trailing whitespace.
	input = strings.TrimSpace(input)
	input = reWHITESPACE.ReplaceAllString(input, " ")

	if input == "lang" {
		return f.GetLang()
	}
	if input == "langUC" {
		return f.GetLangUC()
	}
	if input == "locale" {
		return f.GetLocale()
	}
	if input == "langname" {
		return f.GetLangName()
	}
	if input == "percenttranslated" {
		return f.GetLangPercentTranslated()
	}

	newtext := input

	if found, ok := f.ByID[input]; ok {
		c := found.MsgStr
		if c != "" {
			newtext = c
		}
	}

	if escapequotes {
		newtext = strings.Replace(newtext, `"`, `\"`, -1)
		newtext = strings.Replace(newtext, `'`, `\'`, -1)
	}
	// TODO escapequotes
	// Perl does this:
	//         $text =~ s/(?<![\\])"/\\"/g;
	//    $text =~ s/(?<![\\])'/\\'/g;
	// GO does not do look-behind assertions
	return newtext
}

// Translate takes a given input text, and returns back
// either the translated text, or the original text again.
func (f *File) Add(input string, context string, escapequotes bool) {

	//	log.Printf("po file Add(%s)\n", input)
	// Canonicalize.
	// Remove redundant, leading, and trailing whitespace.
	input = strings.TrimSpace(input)
	input = reWHITESPACE.ReplaceAllString(input, " ")

	//	log.Printf("po Add input=%s context=%s escape=%v\n", input, context, escapequotes)

	// Skip these, these will be dynamically responded to.
	if input == "lang" || input == "langUC" || input == "locale" {
		return
	}

	f.lock.Lock()
	defer f.lock.Unlock()

	_ = "breakpoint"

	if v, ok := f.ByID[input]; ok == false {
		// Not yet set?  Let's do so.
		//	fmt.Printf("DEBUG Saving Comment=%s MsgID=%s\n", context, input)
		f.ByID[input] = &Record{
			Comment: context,
			MsgID:   input,
			MsgStr:  "",
		}
		f.InOrder = append(f.InOrder, input)
	} else if strings.Contains(v.Comment, "not-used") {
		v.Comment = context // Update context
	} else {
		//	fmt.Printf("DEBUG ALREADY HAVE %#v\n", f.ByID[input])

	}

	/*
		if escapequotes {
			newtext = strings.Replace(newtext, `"`, `\"`, -1)
			newtext = strings.Replace(newtext, `'`, `\'`, -1)
		}
	*/

}

// ApacheAddLanguage  Generates the Apache "AddLanguage" text
func (f *Files) ApacheAddLanguage() string {
	list := append([]string{"en_US"}, f.Languages()...)
	text := ""
	seen := make(map[string]bool)

	add := func(s string) {
		if seen[s] == false {
			text = text + s + "\n"
			seen[s] = true
		}
	}

	for _, locale := range list {
		parts := strings.Split(locale, "_")
		if len(parts) > 0 {
			add(fmt.Sprintf("AddLanguage %s .%s", parts[0], locale))
		}
		dashed := strings.Replace(locale, "_", "-", -1)
		add(fmt.Sprintf("AddLanguage %s .%s", dashed, locale))

	}

	return text

}
<|endoftext|>


<commit_before>// +build linux darwin freebsd

package commands

import (
	"fmt"
	"github.com/PagerDuty/godspeed"
	"github.com/zorkian/go-datadog-api"
	"os"
)

// StatsdIn sends metrics to Dogstatsd on a `kvexpress in` operation.
func StatsdIn(key string, dataLength int, data string) {
	if DogStatsd {
		Log(fmt.Sprintf("dogstatsd='true' key='%s' stats='in'", key), "debug")
		statsd, _ := godspeed.NewDefault()
		defer statsd.Conn.Close()
		tags := makeTags(key, "complete")
		statsd.Incr("kvexpress.in", tags)
		statsd.Gauge("kvexpress.bytes", float64(dataLength), tags)
		statsd.Gauge("kvexpress.lines", float64(LineCount(data)), tags)
	}
}

// StatsdOut sends metrics to Dogstatsd on a `kvexpress out` operation.
func StatsdOut(key string) {
	if DogStatsd {
		Log(fmt.Sprintf("dogstatsd='true' key='%s' stats='out'", key), "debug")
		statsd, _ := godspeed.NewDefault()
		defer statsd.Conn.Close()
		tags := makeTags(key, "complete")
		statsd.Incr("kvexpress.out", tags)
	}
}

// StatsdLocked sends metrics to Dogstatsd on a `kvexpress out` operation
// that is blocked by a locked file.
func StatsdLocked(file string) {
	if DogStatsd {
		Log(fmt.Sprintf("dogstatsd='true' file='%s' stats='locked'", file), "debug")
		statsd, _ := godspeed.NewDefault()
		defer statsd.Conn.Close()
		tags := makeTags(file, "complete")
		statsd.Incr("kvexpress.locked", tags)
	}
}

// StatsdLength sends metrics to Dogstatsd on a `kvexpress out` operation
// where the file isn't long enough.
func StatsdLength(key string) {
	if DogStatsd {
		Log(fmt.Sprintf("dogstatsd='true' key='%s' stats='not_long_enough'", key), "debug")
		statsd, _ := godspeed.NewDefault()
		defer statsd.Conn.Close()
		tags := makeTags(key, "not_long_enough")
		statsd.Incr("kvexpress.not_long_enough", tags)
	}
}

// StatsdChecksum sends metrics to Dogstatsd on a `kvexpress out` operation
// where the checksum doesn't match.
func StatsdChecksum(key string) {
	if DogStatsd {
		Log(fmt.Sprintf("dogstatsd='true' key='%s' stats='checksum_mismatch'", key), "debug")
		statsd, _ := godspeed.NewDefault()
		defer statsd.Conn.Close()
		tags := makeTags(key, "checksum_mismatch")
		statsd.Incr("kvexpress.checksum_mismatch", tags)
	}
}

// StatsdLock sends metrics to Dogstatsd on a `kvexpress lock` operation.
func StatsdLock(key string) {
	if DogStatsd {
		Log(fmt.Sprintf("dogstatsd='true' key='%s' stats='lock'", key), "debug")
		statsd, _ := godspeed.NewDefault()
		defer statsd.Conn.Close()
		tags := makeTags(key, "complete")
		statsd.Incr("kvexpress.lock", tags)
	}
}

// StatsdUnlock sends metrics to Dogstatsd on a `kvexpress unlock` operation.
func StatsdUnlock(key string) {
	if DogStatsd {
		Log(fmt.Sprintf("dogstatsd='true' key='%s' stats='unlock'", key), "debug")
		statsd, _ := godspeed.NewDefault()
		defer statsd.Conn.Close()
		tags := makeTags(key, "complete")
		statsd.Incr("kvexpress.unlock", tags)
	}
}

// StatsdRaw sends metrics to Dogstatsd on a `kvexpress raw` operation.
func StatsdRaw(key string) {
	if DogStatsd {
		Log(fmt.Sprintf("dogstatsd='true' key='%s' stats='raw'", key), "debug")
		statsd, _ := godspeed.NewDefault()
		defer statsd.Conn.Close()
		tags := makeTags(key, "complete")
		statsd.Incr("kvexpress.raw", tags)
	}
}

// StatsdReconnect sends metrics when we have Consul connection retries.
func StatsdReconnect(times int) {
	if DogStatsd {
		Log(fmt.Sprintf("dogstatsd='true' reconnect='%d'", times), "debug")
		statsd, _ := godspeed.NewDefault()
		defer statsd.Conn.Close()
		tags := make([]string, 2)
		hostname, _ := os.Hostname()
		hostTag := fmt.Sprintf("host:%s", hostname)
		directionTag := fmt.Sprintf("direction:%s", Direction)
		tags = append(tags, hostTag)
		tags = append(tags, directionTag)
		statsd.Incr("kvexpress.consul_reconnect", tags)
	}
}

// StatsdRunTime sends metrics to Dogstatsd on various operations.
func StatsdRunTime(key string, location string, msec int64) {
	if DogStatsd {
		Log(fmt.Sprintf("dogstatsd='true' key='%s' location='%s' msec='%d'", key, location, msec), "debug")
		statsd, _ := godspeed.NewDefault()
		defer statsd.Conn.Close()
		tags := makeTags(key, location)
		locationTag := fmt.Sprintf("location:%s", location)
		tags = append(tags, locationTag)
		statsd.Gauge("kvexpress.time", float64(msec), tags)
	}
}

// StatsdPanic sends metrics to Dogstatsd when something really bad happens.
// It also stops the execution of kvexpress.
func StatsdPanic(key, location string) {
	if DogStatsd {
		Log(fmt.Sprintf("dogstatsd='true' key='%s' location='%s' stats='panic'", key, location), "debug")
		statsd, _ := godspeed.NewDefault()
		defer statsd.Conn.Close()
		tags := makeTags(key, location)
		statsd.Incr("kvexpress.panic", tags)
	}
	// If we're going to panic, we might as well stop right here.
	// Means we can't connect to Consul, download a URL or
	// write and/or chown files.
	os.Exit(0)
}

// DDAPIConnect connects to the Datadog API and returns a client object.
func DDAPIConnect(api, app string) *datadog.Client {
	client := datadog.NewClient(api, app)
	return client
}

// makeTags creates some standard tags for use with Dogstatsd and the Datadog API.
func makeTags(key, location string) []string {
	tags := make([]string, 4)
	keyTag := fmt.Sprintf("key:%s", key)
	hostname, _ := os.Hostname()
	hostTag := fmt.Sprintf("host:%s", hostname)
	directionTag := fmt.Sprintf("direction:%s", Direction)
	locationTag := fmt.Sprintf("location:%s", location)
	tags = append(tags, keyTag)
	tags = append(tags, hostTag)
	tags = append(tags, directionTag)
	tags = append(tags, locationTag)
	return tags
}

// TODO: These three functions are ripe for refactoring to be more Golang like.

// DDStopEvent sends a Datadog event to the API when there's a stop key present.
func DDStopEvent(dd *datadog.Client, key, value string) {
	Log(fmt.Sprintf("datadog='true' DDStopEvent='true' key='%s'", key), "debug")
	tags := makeTags(key, "stop_key_present")
	tags = append(tags, "kvexpress:stop")
	title := fmt.Sprintf("Stop key is present: %s. Stopping.", key)
	event := datadog.Event{Title: title, Text: value, AlertType: "error", Tags: tags}
	post, _ := dd.PostEvent(&event)
	if post != nil {

	}
}

// DDLengthEvent sends a Datadog event to the API when the file/url is too short.
func DDLengthEvent(dd *datadog.Client, key, value string) {
	Log(fmt.Sprintf("datadog='true' DDLengthEvent='true' key='%s'", key), "debug")
	tags := makeTags(key, "not_long_enough")
	tags = append(tags, "kvexpress:length")
	title := fmt.Sprintf("Not long enough: %s. Stopping.", key)
	event := datadog.Event{Title: title, Text: value, AlertType: "error", Tags: tags}
	post, _ := dd.PostEvent(&event)
	if post != nil {

	}
}

// DDSaveDataEvent sends a Datadog event to the API when we have updated a Consul key.
func DDSaveDataEvent(dd *datadog.Client, key, value string) {
	Log(fmt.Sprintf("datadog='true' DDSaveDataEvent='true' key='%s'", key), "debug")
	tags := makeTags(key, "complete")
	tags = append(tags, "kvexpress:success")
	title := fmt.Sprintf("Updated: %s", key)
	event := datadog.Event{Title: title, Text: value, AlertType: "info", Tags: tags}
	post, _ := dd.PostEvent(&event)
	if post != nil {

	}
}

// DDCopyDataEvent sends a Datadog event to the API when we have used `kvexpress copy`
// to copy a Consul key.
func DDCopyDataEvent(dd *datadog.Client, keyFrom, keyTo string) {
	Log(fmt.Sprintf("datadog='true' DDCopyDataEvent='true' keyFrom='%s' keyTo='%s'", keyFrom, keyTo), "debug")
	tags := makeTags(keyTo, "complete")
	tags = append(tags, "kvexpress:success")
	tags = append(tags, fmt.Sprintf("keyFrom:%s", keyFrom))
	title := fmt.Sprintf("Copy: %s to %s", keyFrom, keyTo)
	event := datadog.Event{Title: title, Text: title, AlertType: "info", Tags: tags}
	post, _ := dd.PostEvent(&event)
	if post != nil {

	}
}

// DDSaveStopEvent sends a Datadog event when we have added a stop key to Consul.
func DDSaveStopEvent(dd *datadog.Client, key, value string) {
	Log(fmt.Sprintf("datadog='true' DDSaveStopEvent='true' key='%s'", key), "debug")
	tags := makeTags(key, "stop_key_save")
	tags = append(tags, "kvexpress:stop_set")
	title := fmt.Sprintf("Set Stop Key: %s", key)
	event := datadog.Event{Title: title, Text: value, AlertType: "warning", Tags: tags}
	post, _ := dd.PostEvent(&event)
	if post != nil {

	}
}
<commit_msg>Decompress and convert string if it's compressed to make sure the line stats are correct. This should close #91.<commit_after>// +build linux darwin freebsd

package commands

import (
	"fmt"
	"github.com/PagerDuty/godspeed"
	"github.com/zorkian/go-datadog-api"
	"os"
)

// StatsdIn sends metrics to Dogstatsd on a `kvexpress in` operation.
func StatsdIn(key string, dataLength int, data string) {
	if DogStatsd {
		Log(fmt.Sprintf("dogstatsd='true' key='%s' stats='in'", key), "debug")
		statsd, _ := godspeed.NewDefault()
		defer statsd.Conn.Close()
		tags := makeTags(key, "complete")
		statsd.Incr("kvexpress.in", tags)
		statsd.Gauge("kvexpress.bytes", float64(dataLength), tags)
		// If the data is compressed - then LineCount will always return 1.
		// That's not useful or accurate, so let's decompress and count that.
		if Compress {
			data = DecompressData(data)
		}
		statsd.Gauge("kvexpress.lines", float64(LineCount(data)), tags)
	}
}

// StatsdOut sends metrics to Dogstatsd on a `kvexpress out` operation.
func StatsdOut(key string) {
	if DogStatsd {
		Log(fmt.Sprintf("dogstatsd='true' key='%s' stats='out'", key), "debug")
		statsd, _ := godspeed.NewDefault()
		defer statsd.Conn.Close()
		tags := makeTags(key, "complete")
		statsd.Incr("kvexpress.out", tags)
	}
}

// StatsdLocked sends metrics to Dogstatsd on a `kvexpress out` operation
// that is blocked by a locked file.
func StatsdLocked(file string) {
	if DogStatsd {
		Log(fmt.Sprintf("dogstatsd='true' file='%s' stats='locked'", file), "debug")
		statsd, _ := godspeed.NewDefault()
		defer statsd.Conn.Close()
		tags := makeTags(file, "complete")
		statsd.Incr("kvexpress.locked", tags)
	}
}

// StatsdLength sends metrics to Dogstatsd on a `kvexpress out` operation
// where the file isn't long enough.
func StatsdLength(key string) {
	if DogStatsd {
		Log(fmt.Sprintf("dogstatsd='true' key='%s' stats='not_long_enough'", key), "debug")
		statsd, _ := godspeed.NewDefault()
		defer statsd.Conn.Close()
		tags := makeTags(key, "not_long_enough")
		statsd.Incr("kvexpress.not_long_enough", tags)
	}
}

// StatsdChecksum sends metrics to Dogstatsd on a `kvexpress out` operation
// where the checksum doesn't match.
func StatsdChecksum(key string) {
	if DogStatsd {
		Log(fmt.Sprintf("dogstatsd='true' key='%s' stats='checksum_mismatch'", key), "debug")
		statsd, _ := godspeed.NewDefault()
		defer statsd.Conn.Close()
		tags := makeTags(key, "checksum_mismatch")
		statsd.Incr("kvexpress.checksum_mismatch", tags)
	}
}

// StatsdLock sends metrics to Dogstatsd on a `kvexpress lock` operation.
func StatsdLock(key string) {
	if DogStatsd {
		Log(fmt.Sprintf("dogstatsd='true' key='%s' stats='lock'", key), "debug")
		statsd, _ := godspeed.NewDefault()
		defer statsd.Conn.Close()
		tags := makeTags(key, "complete")
		statsd.Incr("kvexpress.lock", tags)
	}
}

// StatsdUnlock sends metrics to Dogstatsd on a `kvexpress unlock` operation.
func StatsdUnlock(key string) {
	if DogStatsd {
		Log(fmt.Sprintf("dogstatsd='true' key='%s' stats='unlock'", key), "debug")
		statsd, _ := godspeed.NewDefault()
		defer statsd.Conn.Close()
		tags := makeTags(key, "complete")
		statsd.Incr("kvexpress.unlock", tags)
	}
}

// StatsdRaw sends metrics to Dogstatsd on a `kvexpress raw` operation.
func StatsdRaw(key string) {
	if DogStatsd {
		Log(fmt.Sprintf("dogstatsd='true' key='%s' stats='raw'", key), "debug")
		statsd, _ := godspeed.NewDefault()
		defer statsd.Conn.Close()
		tags := makeTags(key, "complete")
		statsd.Incr("kvexpress.raw", tags)
	}
}

// StatsdReconnect sends metrics when we have Consul connection retries.
func StatsdReconnect(times int) {
	if DogStatsd {
		Log(fmt.Sprintf("dogstatsd='true' reconnect='%d'", times), "debug")
		statsd, _ := godspeed.NewDefault()
		defer statsd.Conn.Close()
		tags := make([]string, 2)
		hostname, _ := os.Hostname()
		hostTag := fmt.Sprintf("host:%s", hostname)
		directionTag := fmt.Sprintf("direction:%s", Direction)
		tags = append(tags, hostTag)
		tags = append(tags, directionTag)
		statsd.Incr("kvexpress.consul_reconnect", tags)
	}
}

// StatsdRunTime sends metrics to Dogstatsd on various operations.
func StatsdRunTime(key string, location string, msec int64) {
	if DogStatsd {
		Log(fmt.Sprintf("dogstatsd='true' key='%s' location='%s' msec='%d'", key, location, msec), "debug")
		statsd, _ := godspeed.NewDefault()
		defer statsd.Conn.Close()
		tags := makeTags(key, location)
		locationTag := fmt.Sprintf("location:%s", location)
		tags = append(tags, locationTag)
		statsd.Gauge("kvexpress.time", float64(msec), tags)
	}
}

// StatsdPanic sends metrics to Dogstatsd when something really bad happens.
// It also stops the execution of kvexpress.
func StatsdPanic(key, location string) {
	if DogStatsd {
		Log(fmt.Sprintf("dogstatsd='true' key='%s' location='%s' stats='panic'", key, location), "debug")
		statsd, _ := godspeed.NewDefault()
		defer statsd.Conn.Close()
		tags := makeTags(key, location)
		statsd.Incr("kvexpress.panic", tags)
	}
	// If we're going to panic, we might as well stop right here.
	// Means we can't connect to Consul, download a URL or
	// write and/or chown files.
	os.Exit(0)
}

// DDAPIConnect connects to the Datadog API and returns a client object.
func DDAPIConnect(api, app string) *datadog.Client {
	client := datadog.NewClient(api, app)
	return client
}

// makeTags creates some standard tags for use with Dogstatsd and the Datadog API.
func makeTags(key, location string) []string {
	tags := make([]string, 4)
	keyTag := fmt.Sprintf("key:%s", key)
	hostname, _ := os.Hostname()
	hostTag := fmt.Sprintf("host:%s", hostname)
	directionTag := fmt.Sprintf("direction:%s", Direction)
	locationTag := fmt.Sprintf("location:%s", location)
	tags = append(tags, keyTag)
	tags = append(tags, hostTag)
	tags = append(tags, directionTag)
	tags = append(tags, locationTag)
	return tags
}

// TODO: These three functions are ripe for refactoring to be more Golang like.

// DDStopEvent sends a Datadog event to the API when there's a stop key present.
func DDStopEvent(dd *datadog.Client, key, value string) {
	Log(fmt.Sprintf("datadog='true' DDStopEvent='true' key='%s'", key), "debug")
	tags := makeTags(key, "stop_key_present")
	tags = append(tags, "kvexpress:stop")
	title := fmt.Sprintf("Stop key is present: %s. Stopping.", key)
	event := datadog.Event{Title: title, Text: value, AlertType: "error", Tags: tags}
	post, _ := dd.PostEvent(&event)
	if post != nil {

	}
}

// DDLengthEvent sends a Datadog event to the API when the file/url is too short.
func DDLengthEvent(dd *datadog.Client, key, value string) {
	Log(fmt.Sprintf("datadog='true' DDLengthEvent='true' key='%s'", key), "debug")
	tags := makeTags(key, "not_long_enough")
	tags = append(tags, "kvexpress:length")
	title := fmt.Sprintf("Not long enough: %s. Stopping.", key)
	event := datadog.Event{Title: title, Text: value, AlertType: "error", Tags: tags}
	post, _ := dd.PostEvent(&event)
	if post != nil {

	}
}

// DDSaveDataEvent sends a Datadog event to the API when we have updated a Consul key.
func DDSaveDataEvent(dd *datadog.Client, key, value string) {
	Log(fmt.Sprintf("datadog='true' DDSaveDataEvent='true' key='%s'", key), "debug")
	tags := makeTags(key, "complete")
	tags = append(tags, "kvexpress:success")
	title := fmt.Sprintf("Updated: %s", key)
	event := datadog.Event{Title: title, Text: value, AlertType: "info", Tags: tags}
	post, _ := dd.PostEvent(&event)
	if post != nil {

	}
}

// DDCopyDataEvent sends a Datadog event to the API when we have used `kvexpress copy`
// to copy a Consul key.
func DDCopyDataEvent(dd *datadog.Client, keyFrom, keyTo string) {
	Log(fmt.Sprintf("datadog='true' DDCopyDataEvent='true' keyFrom='%s' keyTo='%s'", keyFrom, keyTo), "debug")
	tags := makeTags(keyTo, "complete")
	tags = append(tags, "kvexpress:success")
	tags = append(tags, fmt.Sprintf("keyFrom:%s", keyFrom))
	title := fmt.Sprintf("Copy: %s to %s", keyFrom, keyTo)
	event := datadog.Event{Title: title, Text: title, AlertType: "info", Tags: tags}
	post, _ := dd.PostEvent(&event)
	if post != nil {

	}
}

// DDSaveStopEvent sends a Datadog event when we have added a stop key to Consul.
func DDSaveStopEvent(dd *datadog.Client, key, value string) {
	Log(fmt.Sprintf("datadog='true' DDSaveStopEvent='true' key='%s'", key), "debug")
	tags := makeTags(key, "stop_key_save")
	tags = append(tags, "kvexpress:stop_set")
	title := fmt.Sprintf("Set Stop Key: %s", key)
	event := datadog.Event{Title: title, Text: value, AlertType: "warning", Tags: tags}
	post, _ := dd.PostEvent(&event)
	if post != nil {

	}
}
<|endoftext|>


<commit_before>package commands

import (
	"fmt"
	"os"
	"path/filepath"
	"text/template"

	"runtime"

	"github.com/spf13/cobra"
)

var (
	force   = false
	clobber = false
	copy    = false
)

func init() {
	installCmd.Flags().BoolVarP(&force, "force", "f", false, "Allow installation to existing directory.")
	installCmd.Flags().BoolVarP(&clobber, "clobber", "c", false, "Overwrite existing files in target destination.")
	installCmd.Flags().BoolVar(&copy, "copy", false, "Copy this file to the target destination as well. [Currently unimplemented]")
	installCmd.Flags().StringSliceP("skip", "s", []string{}, "Commands to skip during installation.")

	RootCmd.AddCommand(installCmd)
}

// Commands to not create shims for
var skipCommands = []string{
	"help",
	"install",
	"version",
}

var installCmd = &cobra.Command{
	Use:   "install [flags] targetdirectory",
	Short: "Install cmdo and all subcommand shims.",
	Run: func(cmd *cobra.Command, args []string) {
		if len(args) == 0 {
			cmd.Usage()
			return
		}

		// Installation target
		target, err := filepath.Abs(args[0])
		if err != nil {
			fmt.Println("Unable to determine absolute path for:", args[0])
			fmt.Println(err)
			os.Exit(-1)
		}

		// Should never fail, but better safe than sorry
		fi, err := os.Stat(target)
		if err != nil && !os.IsNotExist(err) {
			fmt.Println("Unable to access target path:", err)
			os.Exit(-1)
		}

		// Supplied a file as target? Shame
		if fi != nil && fi.IsDir() == false {
			fmt.Println("Target is a file. Try again.")
			os.Exit(-1)
		}

		if fi != nil && fi.IsDir() && force == false {
			fmt.Println("Target directory exists. Use --force if you want to install to existing directory.")
			os.Exit(-1)
		}

		if toSkip, err := cmd.Flags().GetStringSlice("skip"); err == nil {
			skipCommands = append(skipCommands, toSkip...)
		}

		// Create target directory if it does not exist
		if fi == nil {
			if err := os.MkdirAll(target, 0755); err != nil {
				fmt.Println("Unable to create target directory:", err)
				os.Exit(-1)
			}
		}

		// Loop through all non-hidden, non-skipped commands and create shims
		fmt.Println("Installing shims.")
		for _, cmd := range RootCmd.Commands() {
			name := cmd.Name()
			// Make sure we shouldn't skip this command
			if stringSliceContains(skipCommands, name) {
				continue
			}

			fmt.Printf("  Creating shim for '%s'...\n", cmd.Name())
			if err := createShim(target, cmd.Name()); err != nil {
				fmt.Printf("Error creating shim for %s: %s\n", cmd.Name(), err.Error())
			}
		}

		// All done!
		fmt.Println("All done! Shims should be in:", target)
	},
}

func stringSliceContains(slice []string, search string) bool {
	for _, v := range slice {
		if v == search {
			return true
		}
	}
	return false
}

// TODO Implement target exists && clobber == false
func targetExists(target string) (bool, error) {
	_, err := os.Stat(target)
	if err == nil {
		return false, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return true, err
}

func createShim(dir, command string) error {
	switch runtime.GOOS {
	case "windows":
		return winShim(dir, command)
	default:
		return shellShim(dir, command)
	}
}

func winShim(dir, command string) error {
	target := filepath.Join(dir, command+".cmd")
	if fi, err := os.Stat(target); err != nil && !os.IsNotExist(err) {
		return err
	} else if fi != nil && !clobber {
		fmt.Printf("    Skipping shim for '%s', target exists and clobber == false.\n", command)
		return nil
	}

	f, err := os.Create(target)
	if err != nil {
		return err
	}
	defer f.Close()

	cmdo, _ := filepath.Abs(os.Args[0])
	cmd := fmt.Sprintf(`@"%s" %s %%*`, cmdo, command)
	if _, err := f.WriteString(cmd); err != nil {
		return err
	}

	return nil
}

func shellShim(dir, command string) error {
	target := filepath.Join(dir, command)
	if _, err := os.Stat(target); err != nil && !os.IsNotExist(err) {
		return err
	}

	f, err := os.Create(target)
	if err != nil {
		return err
	}
	defer f.Close()

	tmpl := template.New("")
	tmpl, err = tmpl.Parse(shellShimTemplate)
	if err != nil {
		return err
	}

	cmdo, _ := filepath.Abs(os.Args[0])
	if err := tmpl.Execute(f, map[string]string{"CmdoPath": cmdo, "Command": command}); err != nil {
		// TODO Remove the created file
		return err
	}

	if err := os.Chmod(target, 0755); err != nil {
		return err
	}

	return nil
}

var shellShimTemplate = `#!/bin/sh

cmdo="{{.CmdoPath}}"

# TODO: Test in msys/mingw/etc.
case $(uname) in
    *CYGWIN*) cmdo=$(cygpath -w "${cmdo}");;
esac

if [ -x "${cmdo}" ]; then
  "${cmdo}" "{{.Command}}" "$@"
  ret=$?
  exit $ret
else
  echo "Unable to find base executable: ${cmdo}"
  exit 1
fi
`
<commit_msg>Switching to osext -- os.Args[0] wasn't cutting it<commit_after>package commands

import (
	"fmt"
	"os"
	"path/filepath"
	"text/template"

	"runtime"

	"github.com/kardianos/osext"
	"github.com/spf13/cobra"
)

var (
	force   = false
	clobber = false
	copy    = false
)

func init() {
	installCmd.Flags().BoolVarP(&force, "force", "f", false, "Allow installation to existing directory.")
	installCmd.Flags().BoolVarP(&clobber, "clobber", "c", false, "Overwrite existing files in target destination.")
	installCmd.Flags().BoolVar(&copy, "copy", false, "Copy this file to the target destination as well. [Currently unimplemented]")
	installCmd.Flags().StringSliceP("skip", "s", []string{}, "Commands to skip during installation.")

	RootCmd.AddCommand(installCmd)
}

// Commands to not create shims for
var skipCommands = []string{
	"help",
	"install",
	"version",
}

var installCmd = &cobra.Command{
	Use:   "install [flags] targetdirectory",
	Short: "Install cmdo and all subcommand shims.",
	Run: func(cmd *cobra.Command, args []string) {
		if len(args) == 0 {
			cmd.Usage()
			os.Exit(0)
		}

		// Installation target
		target, err := filepath.Abs(args[0])
		if err != nil {
			fmt.Println("Unable to determine absolute path for:", args[0])
			fmt.Println(err)
			os.Exit(-1)
		}

		// Should never fail, but better safe than sorry
		fi, err := os.Stat(target)
		if err != nil && !os.IsNotExist(err) {
			fmt.Println("Unable to access target path:", err)
			os.Exit(-1)
		}

		// Supplied a file as target? Shame
		if fi != nil && fi.IsDir() == false {
			fmt.Println("Target is a file. Try again.")
			os.Exit(-1)
		}

		if fi != nil && fi.IsDir() && force == false {
			fmt.Println("Target directory exists. Use --force if you want to install to existing directory.")
			os.Exit(-1)
		}

		if toSkip, err := cmd.Flags().GetStringSlice("skip"); err == nil {
			skipCommands = append(skipCommands, toSkip...)
		}

		// Create target directory if it does not exist
		if fi == nil {
			if err := os.MkdirAll(target, 0755); err != nil {
				fmt.Println("Unable to create target directory:", err)
				os.Exit(-1)
			}
		}

		// Loop through all non-hidden, non-skipped commands and create shims
		fmt.Println("Installing shims.")
		for _, cmd := range RootCmd.Commands() {
			name := cmd.Name()
			// Make sure we shouldn't skip this command
			if stringSliceContains(skipCommands, name) {
				continue
			}

			fmt.Printf("  Creating shim for '%s'...\n", cmd.Name())
			if err := createShim(target, cmd.Name()); err != nil {
				fmt.Printf("Error creating shim for %s: %s\n", cmd.Name(), err.Error())
			}
		}

		// All done!
		fmt.Println("All done! Shims should be in:", target)
	},
}

func stringSliceContains(slice []string, search string) bool {
	for _, v := range slice {
		if v == search {
			return true
		}
	}
	return false
}

// TODO Implement target exists && clobber == false
func targetExists(target string) (bool, error) {
	_, err := os.Stat(target)
	if err == nil {
		return false, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return true, err
}

func createShim(dir, command string) error {
	switch runtime.GOOS {
	case "windows":
		return winShim(dir, command)
	default:
		return shellShim(dir, command)
	}
}

func winShim(dir, command string) error {
	target := filepath.Join(dir, command+".cmd")
	if fi, err := os.Stat(target); err != nil && !os.IsNotExist(err) {
		return err
	} else if fi != nil && !clobber {
		fmt.Printf("    Skipping shim for '%s', target exists and clobber == false.\n", command)
		return nil
	}

	f, err := os.Create(target)
	if err != nil {
		return err
	}
	defer f.Close()

	cmdo, _ := filepath.Abs(os.Args[0])
	cmd := fmt.Sprintf(`@"%s" %s %%*`, cmdo, command)
	if _, err := f.WriteString(cmd); err != nil {
		return err
	}

	return nil
}

func shellShim(dir, command string) error {
	target := filepath.Join(dir, command)
	if _, err := os.Stat(target); err != nil && !os.IsNotExist(err) {
		return err
	}

	f, err := os.Create(target)
	if err != nil {
		return err
	}
	defer f.Close()

	tmpl := template.New("")
	tmpl, err = tmpl.Parse(shellShimTemplate)
	if err != nil {
		return err
	}

	cmdo, _ := osext.Executable()
	if err := tmpl.Execute(f, map[string]string{"CmdoPath": cmdo, "Command": command}); err != nil {
		// TODO Remove the created file
		return err
	}

	if err := os.Chmod(target, 0755); err != nil {
		return err
	}

	return nil
}

var shellShimTemplate = `#!/bin/sh

cmdo="{{.CmdoPath}}"

# TODO: Test in msys/mingw/etc.
case $(uname) in
    *CYGWIN*) cmdo=$(cygpath -w "${cmdo}");;
esac

if [ -x "${cmdo}" ]; then
  "${cmdo}" "{{.Command}}" "$@"
  ret=$?
  exit $ret
else
  echo "Unable to find base executable: ${cmdo}"
  exit 1
fi
`
<|endoftext|>