package main

import (
	"testing"
)

func TestNewK(t *testing.T) {
	k := NewK("iso9995")
	if k.Proc != "/proc/bus/input/devices" {
		t.Errorf("NewK() error: expected '/proc/bus/input/devices', received %q", k.Proc)
	}
}

func TestKBLookup(t *testing.T) {
	k := K{"./fixtures/devices", Mapper{}}

	kbd, err := k.Lookup()
	if err != nil {
		t.Errorf("Lookup() error: %q", err)
	}

	if kbd != "event4" {
		t.Errorf("Lookup() error: expected 'event4', received %q", kbd)
	}
}

package main

import (
	"testing"
)

func TestNewK(t *testing.T) {
	k := NewK("iso9995")
	if k.Proc != "/proc/bus/input/devices" {
		t.Errorf("NewK() error: expected '/proc/bus/input/devices', received %q", k.Proc)
	}
}

func TestKBLookup(t *testing.T) {
	k := K{"./fixtures/devices", false, false, false, []Mapping{}, 0, 0, 0, 0, 0}

	kbd, err := k.Path()
	if err != nil {
		t.Errorf("Lookup() error: %q", err)
	}

	if kbd != "/dev/input/event4" {
		t.Errorf("Lookup() error: expected 'event4', received %q", kbd)
	}
}

Create K with full intializer vals


package gstrings

import (
	"github.com/wallclockbuilder/testify/assert"
	"testing"
)

func TestEmpty(t *testing.T) {
	assert := assert.New(t)
	assert.Equal(false, Empty("hello"))
	assert.Equal(false, Empty(" "))
	assert.Equal(true, Empty(""))
}

package gstrings

import (
	"fmt"
	"github.com/wallclockbuilder/testify/assert"
	"testing"
)

func ExampleEmpty(){
	fmt.Println(Empty("hello"))
	fmt.Println(Empty(" "))
	fmt.Println(Empty(""))
	// Output: false
	// false
	// true
}

func TestEmpty(t *testing.T) {
	assert := assert.New(t)
	assert.Equal(false, Empty("hello"))
	assert.Equal(false, Empty(" "))
	assert.Equal(true, Empty(""))
}

Add examples to docs for Empty()


package peco

import "github.com/nsf/termbox-go"

type Input struct {
	*Ctx
}

func (i *Input) Loop() {
	defer i.ReleaseWaitGroup()

	// XXX termbox.PollEvent() can get stuck on unexpected signal
	// handling cases. We still would like to wait until the user
	// (termbox) has some event for us to process, but we don't
	// want to allow termbox to control/block our input loop.
	//
	// Solution: put termbox polling in a separate goroutine,
	// and we just watch for a channel. The loop can now
	// safely be implemented in terms of select {} which is
	// safe from being stuck.
	evCh := make(chan termbox.Event)
	go func() {
		evCh <- termbox.PollEvent()
	}()

	for {
		select {
		case <-i.LoopCh(): // can only fall here if we closed c.loopCh
			return
		case ev := <-evCh:
			switch ev.Type {
			case termbox.EventError:
				//update = false
			case termbox.EventResize:
				i.DrawMatches(nil)
			case termbox.EventKey:
				i.handleKeyEvent(ev)
			}
		}
	}
}

func (i *Input) handleKeyEvent(ev termbox.Event) {
	if h := i.config.Keymap.Handler(ev.Key); h != nil {
		h(i, ev)
		return
	}
}

package peco

import "github.com/nsf/termbox-go"

type Input struct {
	*Ctx
}

func (i *Input) Loop() {
	defer i.ReleaseWaitGroup()

	// XXX termbox.PollEvent() can get stuck on unexpected signal
	// handling cases. We still would like to wait until the user
	// (termbox) has some event for us to process, but we don't
	// want to allow termbox to control/block our input loop.
	//
	// Solution: put termbox polling in a separate goroutine,
	// and we just watch for a channel. The loop can now
	// safely be implemented in terms of select {} which is
	// safe from being stuck.
	evCh := make(chan termbox.Event)
	go func() {
		for {
			evCh <- termbox.PollEvent()
		}
	}()

	for {
		select {
		case <-i.LoopCh(): // can only fall here if we closed c.loopCh
			return
		case ev := <-evCh:
			switch ev.Type {
			case termbox.EventError:
				//update = false
			case termbox.EventResize:
				i.DrawMatches(nil)
			case termbox.EventKey:
				i.handleKeyEvent(ev)
			}
		}
	}
}

func (i *Input) handleKeyEvent(ev termbox.Event) {
	if h := i.config.Keymap.Handler(ev.Key); h != nil {
		h(i, ev)
		return
	}
}

Make sore to keep polling for events


package gokhipu

var (
	basePath = "https://khipu.com/api/2.0"
)

// Khipu implements a basic struct with revelant data to handle
// khipu's API requests.
type Khipu struct {
	Secret     string
	ReceiverID string
}

// NewKhipuClient returns an instance of khipu that is the client to make payment request
func NewKhipuClient(secret, receiverID string) *Khipu {
	return &Khipu{
		Secret:     secret,
		ReceiverID: receiverID,
	}
}

package gokhipu

import (
	"fmt"
	"net/http"
)

var (
	basePath = "https://khipu.com/api/2.0"
)

// Khipu implements a basic struct with revelant data to handle
// khipu's API requests.
type Khipu struct {
	Secret     string
	ReceiverID string
}

// NewKhipuClient returns an instance of khipu that is the client to make payment request
func NewKhipuClient(secret, receiverID string) *Khipu {
	return &Khipu{
		Secret:     secret,
		ReceiverID: receiverID,
	}
}

// Banks ...
func (kc *Khipu) Banks() (*http.Response, error) {
	requestPath := basePath + "/banks"
	req, err := http.NewRequest("GET", requestPath, nil)
	if err != nil {
		return nil, fmt.Errorf(fmt.Sprintf("failed to create request to %s\n%s", requestPath, err))
	}

	req.Header.Set("Authorization", setAuth(nil, "GET", requestPath, kc.Secret, kc.ReceiverID))
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	req.Header.Set("Accept", "application/json")

	cl := http.Client{}
	res, err := cl.Do(req)
	if err != nil {
		return nil, fmt.Errorf(fmt.Sprintf("failed to made request to %s\n%s", requestPath, err))
	}

	return res, nil
}

Add Banks request to Khipu


package mesos

import (
	"fmt"

	"github.com/CiscoCloud/mesos-consul/registry"
)

func (sj *StateJSON) GetFollowerById(id string) (string, error) {
	for _, f := range sj.Followers {

		if f.Id == id {
			return f.Hostname, nil
		}
	}

	return "", fmt.Errorf("Follower not found: %s", id)
}

// Task Methods

// GetCheck()
//   Build a Check structure from the Task labels
//
func (t *Task) GetCheck() *registry.Check {
	return registry.DefaultCheck()
}

package mesos

import (
	"fmt"
	"strings"

	"github.com/CiscoCloud/mesos-consul/registry"
)

func (sj *StateJSON) GetFollowerById(id string) (string, error) {
	for _, f := range sj.Followers {

		if f.Id == id {
			return f.Hostname, nil
		}
	}

	return "", fmt.Errorf("Follower not found: %s", id)
}

// Task Methods

// GetCheck()
//   Build a Check structure from the Task labels
//
func (t *Task) GetCheck() *registry.Check {
	c := registry.DefaultCheck()

	for _, l := range t.Labels {
		k := strings.ToLower(l.Key)

		switch k {
		case "consul_http_check":
			c.HTTP = l.Value
		case "consul_script_check":
			c.Script = l.Value
		case "consul_ttl_check":
			c.TTL = l.Value
		case "consul_check_interval":
			c.Interval = l.Value
		}
	}

	return c
}

Create a Consul check from mesos task labels


package fm

import (
	"go/ast"
	"go/format"
	"go/token"
	"os"
)

type ASTWriter interface {
	Write(file *ast.File, filename string) error
}

type DiskASTWriter struct{}

func (d *DiskASTWriter) Write(file *ast.File, filename string) error {
	spyFile, err := os.Create(filename)
	if err != nil {
		return err
	}

	return format.Node(spyFile, token.NewFileSet(), file)
}

package fm

import (
	"go/ast"
	"go/format"
	"go/token"
	"os"
)

// ASTWriter writes the ast.File to the provided filename
type ASTWriter interface {
	Write(file *ast.File, filename string) error
}

// DiskASTWriter saves an AST to disk
type DiskASTWriter struct{}

// Write outputs the ast.File to a file on disk specified by filename
func (d *DiskASTWriter) Write(file *ast.File, filename string) error {
	spyFile, err := os.Create(filename)
	if err != nil {
		return err
	}

	return format.Node(spyFile, token.NewFileSet(), file)
}

Add missing documentation to exported types


package gohandy

import (
	"archive/tar"
	"io"
	"os"
	"path/filepath"
)

func Unpack(r *tar.Reader, toPath string) error {
	for {
		hdr, err := r.Next()
		if err == io.EOF {
			break
		}

		if err != nil {
			return err
		}

		err = nil

		if hdr.Typeflag == tar.TypeDir {
			dirpath := filepath.Join(toPath, hdr.Name)
			err = os.MkdirAll(dirpath, 0777)
		} else if hdr.Typeflag == tar.TypeReg || hdr.Typeflag == tar.TypeRegA {
			err = writeFile(toPath, hdr.Name, r)
		}

		if err != nil {
			return nil
		}

	}

	return nil
}

func writeFile(toPath, filename string, r *tar.Reader) error {
	path := filepath.Join(toPath, filename)
	out, err := os.Create(path)
	if err != nil {
		return err
	}
	defer out.Close()

	if _, err := io.Copy(out, r); err != nil {
		return err
	}

	return nil
}

package gohandy

import (
	"archive/tar"
	"io"
	"os"
	"path/filepath"
)

func Unpack(r *tar.Reader, toPath string) error {
	for {
		hdr, err := r.Next()
		switch {
		case err == io.EOF:
			break
		case err != nil:
			return err
		default:
			if err := doOnType(hdr.Typeflag, toPath, hdr.Name, r); err != nil {
				return err
			}
		}

	}

	return nil
}

func doOnType(typeFlag byte, toPath string, name string, r *tar.Reader) error {
	fullpath := filepath.Join(toPath, name)
	switch typeFlag {
	case tar.TypeReg, tar.TypeRegA:
		return writeFile(fullpath, r)
	case tar.TypeDir:
		return os.MkdirAll(fullpath, 0777)
	default:
		return nil
	}
}

func writeFile(path string, r *tar.Reader) error {
	out, err := os.Create(path)
	if err != nil {
		return err
	}
	defer out.Close()

	_, err = io.Copy(out, r)
	return err
}

Refactor to make code more readable.


package generator

import (
	"io"
	"reflect"
	"testing"

	"github.com/golang/protobuf/proto"
	plugin "github.com/golang/protobuf/protoc-gen-go/plugin"
)

func TestGenerator_GenerateAllFiles(t *testing.T) {
	type fields struct {
		w io.Writer
	}
	tests := []struct {
		name   string
		fields fields
		want   *plugin.CodeGeneratorResponse
	}{
		{
			name: "helloworld",
			fields: fields{
				w: nil,
			},
			want: &plugin.CodeGeneratorResponse{
				File: []*plugin.CodeGeneratorResponse_File{
					{
						Name:    proto.String("foo"),
						Content: proto.String("bar"),
					},
				},
			},
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			g := &Generator{
				w: tt.fields.w,
			}
			if got := g.GenerateAllFiles(); !reflect.DeepEqual(got, tt.want) {
				t.Errorf("Generator.GenerateAllFiles() = %v, want %v", got, tt.want)
			}
		})
	}
}

package generator

import (
	"fmt"
	"os"
	"testing"

	"github.com/golang/protobuf/proto"
	plugin "github.com/golang/protobuf/protoc-gen-go/plugin"
	"github.com/google/go-cmp/cmp"
)

func TestGenerator_GenerateAllFiles(t *testing.T) {
	type fields struct {
	}
	tests := []struct {
		name   string
		fields fields
		want   *plugin.CodeGeneratorResponse
	}{
		{
			name:   "helloworld",
			fields: fields{},
			want: &plugin.CodeGeneratorResponse{
				File: []*plugin.CodeGeneratorResponse_File{
					{
						Name:    proto.String("foo"),
						Content: proto.String("bar"),
					},
				},
			},
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			p, err := os.Open(fmt.Sprintf("testdata/%s.proto", tt.name))
			if err != nil {
				t.Fatalf("failed to open proto file: %v", err)
			}
			g := &Generator{
				w: p,
			}
			if diff := cmp.Diff(g.GenerateAllFiles(), tt.want); diff != "" {
				t.Errorf("%s", diff)
			}
		})
	}
}

Change to open proto file from testdata


// +build linux,darwin

package github

import (
	"code.google.com/p/go.crypto/ssh/terminal"
)

func isTerminal(fd uintptr) bool {
	return terminal.IsTerminal(int(fd))
}

// +build !windows

package github

import (
	"code.google.com/p/go.crypto/ssh/terminal"
)

func isTerminal(fd uintptr) bool {
	return terminal.IsTerminal(int(fd))
}

Use not windows build tag


package main

// #include "types.h"
import "C"
import (
	"fmt"
	"github.com/amarburg/go-lazyquicktime"
)

//export MovInfo
func MovInfo(path *C.char) C.MovieInfo {

	file, err := sourceFromCPath(path)

	if err != nil {
		fmt.Printf("Error opening path: %s", err.Error())
		return C.MovieInfo{}
	}

	qtInfo, err := lazyquicktime.LoadMovMetadata(file)

	if err != nil {
		fmt.Printf("Error getting metadata: %s", err.Error())
		return C.MovieInfo{}
	}

	return qtInfoToMovieInfo(qtInfo)
}

func qtInfoToMovieInfo(qtInfo *lazyquicktime.LazyQuicktime) C.MovieInfo {
	return C.MovieInfo{
		duration:   C.float(qtInfo.Duration()),
		num_frames: C.int(qtInfo.NumFrames()),
		valid:      1,
	}
}

package main

// #include "types.h"
import "C"
import (
	"fmt"
	"github.com/amarburg/go-lazyquicktime"
)

//export MovInfo
func MovInfo(path *C.char) C.MovieInfo {

	file, err := sourceFromCPath(path)

	if file == nil || err != nil {
		fmt.Printf("Error opening path: %s", err.Error())
		return C.MovieInfo{}
	}

	qtInfo, err := lazyquicktime.LoadMovMetadata(file)

	if err != nil {
		fmt.Printf("Error getting metadata: %s", err.Error())
		return C.MovieInfo{}
	}

	return qtInfoToMovieInfo(qtInfo)
}

func qtInfoToMovieInfo(qtInfo *lazyquicktime.LazyQuicktime) C.MovieInfo {
	return C.MovieInfo{
		duration:   C.float(qtInfo.Duration()),
		num_frames: C.int(qtInfo.NumFrames()),
		valid:      1,
	}
}

Check for nil file as well.


package aws

import (
	"fmt"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/s3"
)

func ListBuckets() {
	fmt.Println("List buckets")
	// Specify profile for config and region for requests
	sess := session.Must(session.NewSessionWithOptions(session.Options{
		Config:  aws.Config{Region: aws.String("us-west-2")},
		Profile: "okta2aws",
	}))
	creds := stscreds.NewCredentials(sess,
		"arn:aws:iam::4xxxx9:role/SoeRolee")

	s3svc := s3.New(sess, &aws.Config{Credentials: creds})
	result, err := s3svc.ListBuckets(nil)
	if err != nil {
		fmt.Println("Failed to list s3 buckets.", err)
	}

	for _, b := range result.Buckets {
		fmt.Printf("* %s created on %s \n ",
			aws.StringValue(b.Name),
			aws.TimeValue(b.CreationDate))
	}

}

package aws

import (
	"fmt"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/s3"
)

func ListBuckets() {
	fmt.Println("List buckets")
	// Specify profile for config and region for requests
	sess := session.Must(session.NewSessionWithOptions(session.Options{
		Config:  aws.Config{Region: aws.String("us-west-2")},
		Profile: "okta2aws",
	}))
	creds := stscreds.NewCredentials(sess,
		"arn:aws:iam::461168169469:role/SSOAdmin1Role")

	s3svc := s3.New(sess, &aws.Config{Credentials: creds})
	result, err := s3svc.ListBuckets(nil)
	if err != nil {
		fmt.Println("Failed to list s3 buckets.", err)
	}

	for _, b := range result.Buckets {
		fmt.Printf("Bucket %s created on %s \n ",
			aws.StringValue(b.Name),
			aws.TimeValue(b.CreationDate))

		bucketname := aws.String(*b.Name)

		// Get Bucket location.
		input := &s3.GetBucketLocationInput{
			Bucket: bucketname,
		}
		result, err := s3svc.GetBucketLocation(input)
		if err != nil {
			fmt.Println(err.Error())
		}
		fmt.Printf("Result: %s", aws.StringValue(result.LocationConstraint))

	}

}

Update the s3 api example


package fate

type bigrams map[token]*tokset

func (b bigrams) Observe(tok0 token, tok1 token) {
	ctx, ok := b[tok0]
	if !ok {
		ctx = &tokset{}
		b[tok0] = ctx
	}
	ctx.Add(tok1)
}

type fwdrev struct {
	fwd *tokset
	rev *tokset
}

type trigrams map[bigram]*fwdrev

func (t trigrams) Observe(tok0, tok1, tok2, tok3 token) (had2 bool) {
	ctx := bigram{tok1, tok2}

	chain, had2 := t[ctx]
	if !had2 {
		chain = &fwdrev{&tokset{}, &tokset{}}
		t[ctx] = chain
	}

	chain.fwd.Add(tok3)
	chain.rev.Add(tok0)

	return had2
}

func (t trigrams) Fwd(ctx bigram) *tokset {
	return t[ctx].fwd
}

func (t trigrams) Rev(ctx bigram) *tokset {
	return t[ctx].rev
}

package fate

type bigrams map[token]*tokset

func (b bigrams) Observe(tok0 token, tok1 token) {
	ctx, ok := b[tok0]
	if !ok {
		ctx = &tokset{}
		b[tok0] = ctx
	}
	ctx.Add(tok1)
}

type fwdrev struct {
	fwd tokset
	rev tokset
}

type trigrams map[bigram]*fwdrev

func (t trigrams) Observe(tok0, tok1, tok2, tok3 token) (had2 bool) {
	ctx := bigram{tok1, tok2}

	chain, had2 := t[ctx]
	if !had2 {
		chain = &fwdrev{}
		t[ctx] = chain
	}

	chain.fwd.Add(tok3)
	chain.rev.Add(tok0)

	return had2
}

func (t trigrams) Fwd(ctx bigram) *tokset {
	return &(t[ctx].fwd)
}

func (t trigrams) Rev(ctx bigram) *tokset {
	return &(t[ctx].rev)
}

Remove an extra layer of pointer indirection in the trigram map


package potcp

import (
  "proboscis-go"
  "net"
)

type HandlerFunction func(*proboscis.Request) *proboscis.Response

type Handler struct {
  Method string
  Format string
  Function HandlerFunction
}

type Server struct {
  Handlers map[string]*Handler
}

func NewServer() *Server {
  var server *Server
  server = &Server{make(map[string]*Handler)}
  return server
}
func NewHandler(method string, format string, hf HandlerFunction) *Handler {
  var handler *Handler
  handler = &Handler{method, format, hf}
  return handler
}

func (server *Server) Register(handler *Handler) {
  server.Handlers[handler.Method] = handler
}
func (server *Server) ServeConn(conn net.Conn) {
  // FIXME: Make this work
}

package potcp

import (
  "proboscis-go"
  "net"
)

type HandlerFunction func(*proboscis.Request) *proboscis.Response

type Handler struct {
  Method string
  Format string
  Function HandlerFunction
}

type Server struct {
  Handlers map[string]*Handler
  Conn     net.Conn
}

type Client struct {
  Conn net.Conn
}

func NewServer() *Server {
  var server *Server
  server = &Server{make(map[string]*Handler), nil}
  return server
}
func NewHandler(method string, format string, hf HandlerFunction) *Handler {
  var handler *Handler
  handler = &Handler{method, format, hf}
  return handler
}

// SERVER ---------------------------------------------------------------------

func (server *Server) Register(handler *Handler) {
  server.Handlers[handler.Method] = handler
}
func (server *Server) ServeConn(conn net.Conn) {
  server.Conn = conn
  // FIXME: Make this work
}

Add connection to server; start work on clients


package main

import (
	"log"
	"os"

	"github.com/FiloSottile/CVE-2016-2107/LuckyMinus20"
)

func main() {
	res, err := LuckyMinus20.Test(os.Args[1])
	if err != nil {
		log.Fatal(err)
	}
	log.Println("Vulnerable:", res)
}

package main

import (
	"log"
	"os"

	"github.com/FiloSottile/CVE-2016-2107/LuckyMinus20"
)

func main() {
	res, err := LuckyMinus20.Test(os.Args[1])
	if err != nil {
		log.Fatal(err)
	}
	log.Println("Vulnerable:", res)
	if res {
		os.Exit(1)
	}
}

Exit with 1 when test is positive


package main

import (
	"bufio"
	"fmt"
	"log"
	"os/exec"
)

func main() {
	cmd := exec.Command("./a.sh")
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		log.Fatal(err)
	}
	if err := cmd.Start(); err != nil {
		log.Fatal(err)
	}
	scanner := bufio.NewScanner(stdout)
	for scanner.Scan() {
		fmt.Println(scanner.Text())
	}
	if err := cmd.Wait(); err != nil {
		log.Fatal(err)
	}
}

package main

import (
	"bufio"
	"fmt"
	"log"
	"os/exec"

	"github.com/mgutz/ansi"
)

func main() {
	cmd := exec.Command("./a.sh")
	err := runCommand(cmd)
	if err != nil {
		log.Fatal(err)
	}
}

func runCommand(cmd *exec.Cmd) error {
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		return err
	}
	stderr, err := cmd.StderrPipe()
	if err != nil {
		return err
	}

	if err := cmd.Start(); err != nil {
		return err
	}

	go func() {
		stdoutHeader := ansi.Color("stdout:", "green")
		stdoutScanner := bufio.NewScanner(stdout)
		for stdoutScanner.Scan() {
			fmt.Printf("%s%s\n", stdoutHeader, stdoutScanner.Text())
		}
	}()

	go func() {
		stderrHeader := ansi.Color("stderr:", "red")
		stderrScanner := bufio.NewScanner(stderr)
		for stderrScanner.Scan() {
			fmt.Printf("%s%s\n", stderrHeader, stderrScanner.Text())
		}
	}()

	return cmd.Wait()
}

Read stdout and stderr in real time with two goroutines


package server

import (
	"poule/configuration"
	"poule/gh"
	"poule/runner"

	"github.com/Sirupsen/logrus"
)

func executeAction(config *configuration.Config, action configuration.Action, item gh.Item) error {
	for _, opConfig := range action.Operations {
		logrus.WithFields(logrus.Fields{
			"operation":  opConfig.Type,
			"number":     item.Number(),
			"repository": item.Repository(),
		}).Info("running operation")

		opRunner, err := runner.NewOperationRunnerFromConfig(config, &opConfig)
		if err != nil {
			return err
		}
		return opRunner.Handle(item)
	}
	return nil
}

func executeActionOnAllItems(config *configuration.Config, action configuration.Action) error {
	for _, opConfig := range action.Operations {
		logrus.WithFields(logrus.Fields{
			"operation": opConfig.Type,
		}).Info("running operation on stock")

		opRunner, err := runner.NewOperationRunnerFromConfig(config, &opConfig)
		if err != nil {
			return err
		}
		return opRunner.HandleStock()
	}
	return nil
}

package server

import (
	"poule/configuration"
	"poule/gh"
	"poule/runner"

	"github.com/Sirupsen/logrus"
)

func executeAction(config *configuration.Config, action configuration.Action, item gh.Item) error {
	for _, opConfig := range action.Operations {
		logrus.WithFields(logrus.Fields{
			"operation":  opConfig.Type,
			"number":     item.Number(),
			"repository": item.Repository(),
		}).Info("running operation")

		opRunner, err := runner.NewOperationRunnerFromConfig(config, &opConfig)
		if err != nil {
			return err
		}
		if err := opRunner.Handle(item); err != nil {
			return err
		}
	}
	return nil
}

func executeActionOnAllItems(config *configuration.Config, action configuration.Action) error {
	for _, opConfig := range action.Operations {
		logrus.WithFields(logrus.Fields{
			"operation": opConfig.Type,
		}).Info("running operation on stock")

		opRunner, err := runner.NewOperationRunnerFromConfig(config, &opConfig)
		if err != nil {
			return err
		}
		if err := opRunner.HandleStock(); err != nil {
			return err
		}
	}
	return nil
}

Fix serve bug executing only the first operation


package mesos

import (
	"log"
	"net"
	"regexp"
	"strconv"
	"strings"
)

func cleanName(name string) string {
	reg, err := regexp.Compile("[^\\w-.\\.]")
	if err != nil {
		log.Print("[WARN] ", err)
		return name
	}

	s := reg.ReplaceAllString(name, "")

	return strings.ToLower(strings.Replace(s, "_", "", -1))
}

// The PID has a specific format:
// type@host:port
func parsePID(pid string) (string, string) {
	host := strings.Split(strings.Split(pid, ":")[0], "@")[1]
	port := strings.Split(pid, ":")[1]

	return host, port
}

func leaderIP(leader string) string {
	host := strings.Split(leader, "@")[1]
	host = strings.Split(host, ":")[0]

	return host
}

func toIP(host string) string {
	ip, err := net.LookupIP(host)
	if err != nil {
		return host
	}

	return ip[0].String()
}

func toPort(p string) int {
	ps, err := strconv.Atoi(p)
	if err != nil {
		log.Printf("[ERROR] Invalid port number: %d", p)
	}

	return ps
}

package mesos

import (
	"log"
	"net"
	"regexp"
	"strconv"
	"strings"
)

func cleanName(name string) string {
	reg, err := regexp.Compile("[^\\w-.\\.]")
	if err != nil {
		log.Print("[WARN] ", err)
		return name
	}

	s := reg.ReplaceAllString(name, "")

	return strings.ToLower(strings.Replace(s, "_", "", -1))
}

// The PID has a specific format:
// type@host:port
func parsePID(pid string) (string, string) {
	host := strings.Split(strings.Split(pid, ":")[0], "@")[1]
	port := strings.Split(pid, ":")[1]

	return host, port
}

func leaderIP(leader string) string {
	host := strings.Split(leader, "@")[1]
	host = strings.Split(host, ":")[0]

	return host
}

func toIP(host string) string {
	ip, err := net.LookupIP(host)
	if err != nil {
		return host
	}

	return ip[0].String()
}

func toPort(p string) int {
	ps, err := strconv.Atoi(p)
	if err != nil {
		log.Printf("[ERROR] Invalid port number: %s", p)
	}

	return ps
}

Write 100 times on the board: "%s: strings, %d: ints"


package model

// Post represents a Facebook Post
//
// https://developers.facebook.com/docs/graph-api/reference/v2.4/post
type Post struct {
	ID      string `json:"id"`
	Message string `json:"message,omitempty"`
}

package model

import "time"

// Post represents a Facebook Post
//
// https://developers.facebook.com/docs/graph-api/reference/v2.4/post
type Post struct {
	ID                   string    `json:"id"`
	Message              string    `json:"message,omitempty"`
	Published            bool      `json:"published"`
	ScheduledPublishTime time.Time `json:"scheduled_publish_time,omitempty"`
	BackdatedTime        time.Time `json:"backdated_time,omitempty"`
	ObjectAttachment     string    `json:"object_attachment,omitempty"`
	ChildAttachments     []Link    `json:"child_attachments,omitempty"`
}

// Link is used as a pointer to images in a post
//
// https://developers.facebook.com/docs/graph-api/reference/v2.4/link
type Link struct {
	Link string `json:"link"`
}

Add additional possible fields to the Post model


package fs

import (
	"os"
	"path/filepath"
)

// WARN (CEV): Investigate handling of environment variables and path expansion.

// Max is 255 but use 245 to be safe.
const winMaxLength = 245

func longPath(p string) (string, error) {
	path, err := absPath(p)
	if err == nil && len(path) >= winMaxLength {
		path = `\\?\` + path
	}
	return path, err
}

func absPath(path string) (string, error) {
	if filepath.IsAbs(path) {
		return filepath.Clean(path), nil
	}
	wd, err := os.Getwd()
	return filepath.Join(wd, path), err
}

func osPath(path string) (string, error) {
	p, err := absPath(path)
	if err != nil {
		return "", err
	}
	if len(p) >= winMaxLength {
		p = `\\?\` + p
	}
	return p, nil
}

func Path(path string) (string, error) {
	p, err := absPath(path)
	if err != nil {
		return "", err
	}
	if len(p) >= winMaxLength {
		p = `\\?\` + p
	}
	return p, nil
}

package fs

import (
	"os"
	"path/filepath"
)

// WARN (CEV): Investigate handling of environment variables and path expansion.

// Max is 255 but use 245 to be safe.
const winMaxLength = 245

func absPath(path string) (string, error) {
	if filepath.IsAbs(path) {
		return filepath.Clean(path), nil
	}
	wd, err := os.Getwd()
	return filepath.Join(wd, path), err
}

func Path(path string) (string, error) {
	p, err := absPath(path)
	if err != nil {
		return "", err
	}
	if len(p) >= winMaxLength {
		p = `\\?\` + p
	}
	return p, nil
}

Remove unused windows path functions


package cpu

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

type Cpu struct{}

func (self *Cpu) Collect() (result map[string]map[string]string, err error) {
	return map[string]map[string]string{
		"cpu": getCpuInfo(),
	}, err
}

func getCpuInfo() (cpuinfo map[string]string) {
	contents, err := ioutil.ReadFile("/proc/cpuinfo")
	if err != nil {
		return
	}

	lines := strings.Split(string(contents), "\n")

	cpuinfo = make(map[string]string)

	for _, line := range(lines) {
		fields := regSplit(line, "\t+: ")
		switch fields[0] {
		case "model name": cpuinfo["model_name"] = fields[1]
		}
	}
	return
}

func regSplit(text string, delimeter string) []string {
    reg := regexp.MustCompile(delimeter)
    indexes := reg.FindAllStringIndex(text, -1)
    laststart := 0
    result := make([]string, len(indexes) + 1)
    for i, element := range indexes {
            result[i] = text[laststart:element[0]]
            laststart = element[1]
    }
    result[len(indexes)] = text[laststart:len(text)]
    return result
}

package cpu

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

type Cpu struct{}

func (self *Cpu) Collect() (result map[string]map[string]string, err error) {
	cpuinfo, err := getCpuInfo()
	return map[string]map[string]string{
		"cpu": cpuinfo,
	}, err
}

func getCpuInfo() (cpuinfo map[string]string, err error) {
	contents, err := ioutil.ReadFile("/proc/cpuinfo")
	if err != nil {
		return
	}

	lines := strings.Split(string(contents), "\n")

	cpuinfo = make(map[string]string)

	for _, line := range(lines) {
		fields := regSplit(line, "\t+: ")
		switch fields[0] {
		case "model name": cpuinfo["model_name"] = fields[1]
		}
	}
	return
}

func regSplit(text string, delimeter string) []string {
    reg := regexp.MustCompile(delimeter)
    indexes := reg.FindAllStringIndex(text, -1)
    laststart := 0
    result := make([]string, len(indexes) + 1)
    for i, element := range indexes {
            result[i] = text[laststart:element[0]]
            laststart = element[1]
    }
    result[len(indexes)] = text[laststart:len(text)]
    return result
}

Use err variable of getCpuInfo()


package nvim

import "github.com/garyburd/neovim-go/vim"

func Echomsg(v *vim.Vim, msg string) error {
	return v.Command("echomsg '" + msg + "'")
}

func Echoerror(v *vim.Vim, msg string) error {
	return v.Command("echoerr '" + msg + "'")
}

package nvim

import (
	"fmt"

	"github.com/garyburd/neovim-go/vim"
)

func Echomsg(v *vim.Vim, format string, args ...interface{}) error {
	return v.Command("echomsg '" + fmt.Sprintf(format, args...) + "'")
}

func Echoerror(v *vim.Vim, format string, args ...interface{}) error {
	return v.Command("echoerr '" + fmt.Sprintf(format, args...) + "'")
}

Support fmt likes format for Echomsg & Echoerror


package codegen

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"path"
)

func Output(ctx *Context, p string, data string) error {
	op := path.Join(ctx.Dir, p)
	var out bytes.Buffer

	fmt.Fprintf(&out, "package %s\n", ctx.PackageName)
	outputImports(ctx, &out)

	out.WriteString(data)

	return ioutil.WriteFile(op, out.Bytes(), 0644)
}

func outputImports(ctx *Context, w io.Writer) {
	if len(ctx.Imports) == 0 {
		return
	}

	fmt.Fprint(w, "import (\n")

	for i, _ := range ctx.Imports {
		fmt.Fprintf(w, "\t\"%s\"\n", i)
	}
	fmt.Fprint(w, ")\n")

}

package codegen

import (
	"bytes"
	"fmt"
	"go/parser"
	"go/printer"
	"go/token"
	"io"
	"io/ioutil"
	"path"
)

func Output(ctx *Context, p string, data string) error {
	op := path.Join(ctx.Dir, p)
	var (
		unformatted bytes.Buffer
		out         bytes.Buffer
	)

	fmt.Fprintf(&unformatted, "package %s\n", ctx.PackageName)
	outputImports(ctx, &unformatted)
	unformatted.WriteString(data)

	fset := token.NewFileSet()
	file, err := parser.ParseFile(fset, p, unformatted.Bytes(), parser.ParseComments)
	if err != nil {
		return err
	}

	printer.Fprint(&out, fset, file)

	return ioutil.WriteFile(op, out.Bytes(), 0644)
}

func outputImports(ctx *Context, w io.Writer) {
	if len(ctx.Imports) == 0 {
		return
	}

	fmt.Fprint(w, "import (\n")

	for i, _ := range ctx.Imports {
		fmt.Fprintf(w, "\t\"%s\"\n", i)
	}
	fmt.Fprint(w, ")\n")

}

Add pretty printing to generated code


package main

import (
	"fmt"
	"io/ioutil"
	"runtime"

	"github.com/overlordtm/trayhost"
)

// TODO: Factor into trayhost.
func trayhost_NewSeparatorMenuItem() trayhost.MenuItem { return trayhost.MenuItem{Title: ""} }

func main() {
	runtime.LockOSThread()

	menuItems := trayhost.MenuItems{
		trayhost.MenuItem{
			Title: "Instant Share",
			Handler: func() {
				fmt.Println("TODO: grab content, content-type of clipboard")
				fmt.Println("TODO: request URL")
				fmt.Println("TODO: display/put URL in clipboard")
				fmt.Println("TODO: upload image in background")
			},
		},
		trayhost_NewSeparatorMenuItem(),
		trayhost.MenuItem{
			Title:   "Quit",
			Handler: trayhost.Exit,
		},
	}

	// TODO: Create a real icon and bake it into the binary.
	iconData, err := ioutil.ReadFile("./icon.png")
	if err != nil {
		panic(err)
	}

	trayhost.Initialize("InstantShare", iconData, menuItems)

	trayhost.EnterLoop()
}

package main

import (
	"fmt"
	"io/ioutil"
	"runtime"

	"github.com/shurcooL/trayhost"
)

func main() {
	runtime.LockOSThread()

	menuItems := trayhost.MenuItems{
		trayhost.MenuItem{
			Title: "Instant Share",
			Handler: func() {
				fmt.Println("TODO: grab content, content-type of clipboard")
				fmt.Println("TODO: request URL")
				fmt.Println("TODO: display/put URL in clipboard")
				fmt.Println("TODO: upload image in background")
			},
		},
		trayhost.SeparatorMenuItem(),
		trayhost.MenuItem{
			Title:   "Quit",
			Handler: trayhost.Exit,
		},
	}

	// TODO: Create a real icon and bake it into the binary.
	iconData, err := ioutil.ReadFile("./icon.png")
	if err != nil {
		panic(err)
	}

	trayhost.Initialize("InstantShare", iconData, menuItems)

	trayhost.EnterLoop()
}

Use fork of trayhost, where needed functionality will be added.


package cyberark

import (
	"fmt"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestNewClientHostIsRequired(t *testing.T) {
	_, err := NewClient()
	assert.NotNil(t, err)
	assert.Equal(t, "host is required", err.Error())
}

func TestNewClientAddsProtocolWhenNotSpecified(t *testing.T) {
	c, err := NewClient(SetHost("foo"))
	assert.Nil(t, err)
	assert.Equal(t, "https://foo/", c.host)
}

func TestNewClientAllowsProtocol(t *testing.T) {
	c, err := NewClient(SetHost("http://foo"))
	assert.Nil(t, err)
	assert.Equal(t, "http://foo/", c.host)
}

func TestBuildURLBuildsCorrectly(t *testing.T) {
	c, err := NewClient(SetHost("foo"))
	assert.Nil(t, err)
	assert.Equal(t, fmt.Sprintf("https://foo/%smy/path", basePath), c.buildURL("my/path"))
}

package cyberark

import (
	"fmt"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestNewClientHostIsRequired(t *testing.T) {
	_, err := NewClient()
	assert.NotNil(t, err)
	assert.Equal(t, "host is required", err.Error())
}

func TestSetHostFailsOnBlank(t *testing.T) {
	_, err := NewClient(SetHost(""))
	assert.NotNil(t, err)
	assert.Equal(t, "host cannot be empty", err.Error())
}

func TestNewClientAddsProtocolWhenNotSpecified(t *testing.T) {
	c, err := NewClient(SetHost("foo"))
	assert.Nil(t, err)
	assert.Equal(t, "https://foo/", c.host)
}

func TestNewClientAllowsProtocol(t *testing.T) {
	c, err := NewClient(SetHost("http://foo"))
	assert.Nil(t, err)
	assert.Equal(t, "http://foo/", c.host)
}

func TestBuildURLBuildsCorrectly(t *testing.T) {
	c, err := NewClient(SetHost("foo"))
	assert.Nil(t, err)
	assert.Equal(t, fmt.Sprintf("https://foo/%smy/path", basePath), c.buildURL("my/path"))
}

Add test for setting host to blank


package commands

import (
	"github.com/centurylinkcloud/clc-go-cli/base"
)

type CommandBase struct {
	Input   interface{}
	Output  interface{}
	ExcInfo CommandExcInfo
}

type CommandExcInfo struct {
	Verb     string
	Url      string
	Resource string
	Command  string
	Brief    string
	Help     string
}

func (c *CommandBase) Execute(cn base.Connection) error {
	return cn.ExecuteRequest(c.ExcInfo.Verb, c.ExcInfo.Url, c.Input, c.Output)
}

func (c *CommandBase) Resource() string {
	return c.ExcInfo.Resource
}

func (c *CommandBase) Command() string {
	return c.ExcInfo.Command
}

func (c *CommandBase) ShowBrief() string {
	return c.ExcInfo.Brief
}

func (c *CommandBase) ShowHelp() string {
	return c.ExcInfo.Help
}

func (c *CommandBase) InputModel() interface{} {
	return c.Input
}

func (c *CommandBase) OutputModel() interface{} {
	return c.Output
}

package commands

import (
	"github.com/centurylinkcloud/clc-go-cli/base"
)

type CommandBase struct {
	Input   interface{}
	Output  interface{}
	ExcInfo CommandExcInfo
}

type CommandExcInfo struct {
	Verb     string
	Url      string
	Resource string
	Command  string
	Brief    string
	Help     string
}

func (c *CommandBase) Execute(cn base.Connection) error {
	return cn.ExecuteRequest(c.ExcInfo.Verb, c.ExcInfo.Url, c.Input, c.Output)
}

func (c *CommandBase) Resource() string {
	return c.ExcInfo.Resource
}

func (c *CommandBase) Command() string {
	return c.ExcInfo.Command
}

func (c *CommandBase) ShowBrief() string {
	return c.ExcInfo.Brief
}

func (c *CommandBase) ShowHelp() string {
	return c.ExcInfo.Brief + c.ExcInfo.Help
}

func (c *CommandBase) InputModel() interface{} {
	return c.Input
}

func (c *CommandBase) OutputModel() interface{} {
	return c.Output
}

Return both brief help and full parameters description from ShowHelp


package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"regexp"
	"time"
)

func main() {
	fmt.Println("Verifying URLs..")

	readmeFile, err := ioutil.ReadFile("README.md")
	if err != nil {
		fmt.Println("Could not find README!")
		os.Exit(1)
	}

	fileContent := string(readmeFile)
	urlElementRegex := regexp.MustCompile(`(?m)\[.+?]\(((http|https)://.+?)\)`)

	httpClient := http.Client{Timeout: 10 * time.Second}

	var brokenUrls []string
	for _, urlElement := range urlElementRegex.FindAllStringSubmatch(fileContent, -1) {
		var url = urlElement[1]

		fmt.Printf("Checking %s: ", url)

		resp, err := httpClient.Get(url)
		if err != nil || resp.StatusCode != 200 {
			brokenUrls = append(brokenUrls, url)
			fmt.Println("FAILED - " err)
		} else {
			fmt.Println("OK")
		}
	}

	if len(brokenUrls) != 0 {
		fmt.Println("Broken URLs were found:")
		for _, brokenUrl := range brokenUrls {
			fmt.Println(brokenUrl)
		}

		os.Exit(1)
	}

	fmt.Println("No broken URLs found!")
	os.Exit(0)
}

package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"regexp"
	"time"
)

func main() {
	fmt.Println("Verifying URLs..")

	readmeFile, err := ioutil.ReadFile("README.md")
	if err != nil {
		fmt.Println("Could not find README!")
		os.Exit(1)
	}

	fileContent := string(readmeFile)
	urlElementRegex := regexp.MustCompile(`(?m)\[.+?]\(((http|https)://.+?)\)`)

	httpClient := http.Client{Timeout: 10 * time.Second}

	var brokenUrls []string
	for _, urlElement := range urlElementRegex.FindAllStringSubmatch(fileContent, -1) {
		var url = urlElement[1]

		fmt.Printf("Checking %s: ", url)

		resp, err := httpClient.Get(url)
		if err != nil || resp.StatusCode != 200 {
			brokenUrls = append(brokenUrls, url)
			fmt.Println("FAILED - ", err)
		} else {
			fmt.Println("OK")
		}
	}

	if len(brokenUrls) != 0 {
		fmt.Println("Broken URLs were found:")
		for _, brokenUrl := range brokenUrls {
			fmt.Println(brokenUrl)
		}

		os.Exit(1)
	}

	fmt.Println("No broken URLs found!")
	os.Exit(0)
}

Use error response when request fails


package gamerules

import (
	"os"

	"chunkymonkey/command"
)

// GameRules is a container type for block, item and recipe definitions.
var (
	Blocks           BlockTypeList
	Items            ItemTypeMap
	Recipes          *RecipeSet
	FurnaceReactions FurnaceData
	CommandFramework *command.CommandFramework
)

func LoadGameRules(blocksDefFile, itemsDefFile, recipesDefFile, furnaceDefFile string) (err os.Error) {
	Blocks, err = LoadBlocksFromFile(blocksDefFile)
	if err != nil {
		return
	}

	Items, err = LoadItemTypesFromFile(itemsDefFile)
	if err != nil {
		return
	}

	Blocks.CreateBlockItemTypes(Items)

	Recipes, err = LoadRecipesFromFile(recipesDefFile, Items)
	if err != nil {
		return
	}

	FurnaceReactions, err = LoadFurnaceDataFromFile(furnaceDefFile)
	if err != nil {
		return
	}

	// TODO: Load the prefix from a config file
	CommandFramework = command.NewCommandFramework("/")

	return
}

package gamerules

import (
	"os"

	"chunkymonkey/command"
	"chunkymonkey/permission"
)

// GameRules is a container type for block, item and recipe definitions.
var (
	Blocks           BlockTypeList
	Items            ItemTypeMap
	Recipes          *RecipeSet
	FurnaceReactions FurnaceData
	CommandFramework *command.CommandFramework
	Permissions      permission.IPermissions
)

func LoadGameRules(blocksDefFile, itemsDefFile, recipesDefFile, furnaceDefFile string) (err os.Error) {
	Blocks, err = LoadBlocksFromFile(blocksDefFile)
	if err != nil {
		return
	}

	Items, err = LoadItemTypesFromFile(itemsDefFile)
	if err != nil {
		return
	}

	Blocks.CreateBlockItemTypes(Items)

	Recipes, err = LoadRecipesFromFile(recipesDefFile, Items)
	if err != nil {
		return
	}

	FurnaceReactions, err = LoadFurnaceDataFromFile(furnaceDefFile)
	if err != nil {
		return
	}

	// TODO: Load the prefix from a config file
	CommandFramework = command.NewCommandFramework("/")

	Permissions, err = permission.LoadJsonPermission("./")
	if err != nil {
		return
	}

	return
}

Load JsonPermission in LoadGameRules func. Currently using the working path for loading of users.json and groups.json


package main

import (
	"os/exec"
	"strings"
	"sync"
	"testing"
	"time"
)

func TestMultipleAttachRestart(t *testing.T) {
	cmd := exec.Command(dockerBinary, "run", "--name", "attacher", "-d", "busybox",
		"/bin/sh", "-c", "sleep 1 && echo hello")

	group := sync.WaitGroup{}
	group.Add(4)

	go func() {
		defer group.Done()
		out, _, err := runCommandWithOutput(cmd)
		if err != nil {
			t.Fatal(err, out)
		}
	}()
	time.Sleep(500 * time.Millisecond)

	for i := 0; i < 3; i++ {
		go func() {
			defer group.Done()
			c := exec.Command(dockerBinary, "attach", "attacher")

			out, _, err := runCommandWithOutput(c)
			if err != nil {
				t.Fatal(err, out)
			}
			if actual := strings.Trim(out, "\r\n"); actual != "hello" {
				t.Fatalf("unexpected output %s expected hello", actual)
			}
		}()
	}

	group.Wait()

	cmd = exec.Command(dockerBinary, "kill", "attacher")
	if _, err := runCommand(cmd); err != nil {
		t.Fatal(err)
	}
	deleteAllContainers()

	logDone("run - multiple attach")
}

package main

import (
	"os/exec"
	"strings"
	"sync"
	"testing"
	"time"
)

func TestMultipleAttachRestart(t *testing.T) {
	cmd := exec.Command(dockerBinary, "run", "--name", "attacher", "-d", "busybox",
		"/bin/sh", "-c", "sleep 2 && echo hello")

	group := sync.WaitGroup{}
	group.Add(4)

	defer func() {
		cmd = exec.Command(dockerBinary, "kill", "attacher")
		if _, err := runCommand(cmd); err != nil {
			t.Fatal(err)
		}
		deleteAllContainers()
	}()

	go func() {
		defer group.Done()
		out, _, err := runCommandWithOutput(cmd)
		if err != nil {
			t.Fatal(err, out)
		}
	}()
	time.Sleep(500 * time.Millisecond)

	for i := 0; i < 3; i++ {
		go func() {
			defer group.Done()
			c := exec.Command(dockerBinary, "attach", "attacher")

			out, _, err := runCommandWithOutput(c)
			if err != nil {
				t.Fatal(err, out)
			}
			if actual := strings.Trim(out, "\r\n"); actual != "hello" {
				t.Fatalf("unexpected output %s expected hello", actual)
			}
		}()
	}

	group.Wait()

	logDone("attach - multiple attach")
}

Increase time before exit in TestMultipleAttachRestart


package txtdirect

import (
	"fmt"
	"regexp"
	"strings"
)

var dockerRegexs = map[string]string{
	"_catalog":  "^/v2/_catalog$",
	"tags":      "^/v2/(.*)/tags/(.*)",
	"manifests": "^/v2/(.*)/manifests/(.*)",
	"blobs":     "^/v2/(.*)/blobs/(.*)",
}

var DockerRegex = regexp.MustCompile("^\\/v2\\/(.*\\/(tags|manifests|blobs)\\/.*|_catalog$)")

func generateDockerv2URI(path string, rec record) (string, int) {
	if path != "" {
		regexType := DockerRegex.FindAllStringSubmatch(path, -1)[0]
		pathRegex, err := regexp.Compile(dockerRegexs[regexType[len(regexType)-1]])
		if err != nil {
			panic(err)
		}
		pathSubmatches := pathRegex.FindAllStringSubmatch(path, -1)
		pathSlice := pathSubmatches[0][1:]

		uri := rec.To
		for i, v := range pathSlice {
			uri = strings.Replace(uri, fmt.Sprintf("$%d", i+1), v, -1)
		}
		return uri, rec.Code
	}
	return rec.To, rec.Code
}

package txtdirect

import (
	"fmt"
	"regexp"
	"strings"
)

var dockerRegexs = map[string]string{
	"_catalog":  "^/v2/_catalog$",
	"tags":      "^/v2/(.*)/tags/(.*)",
	"manifests": "^/v2/(.*)/manifests/(.*)",
	"blobs":     "^/v2/(.*)/blobs/(.*)",
}

var DockerRegex = regexp.MustCompile("^\\/v2\\/(.*\\/(tags|manifests|blobs)\\/.*|_catalog$)")

func generateDockerv2URI(path string, rec record) (string, int) {
	if path != "/" {
		regexType := DockerRegex.FindAllStringSubmatch(path, -1)[0]
		pathRegex, err := regexp.Compile(dockerRegexs[regexType[len(regexType)-1]])
		if err != nil {
			panic(err)
		}
		pathSubmatches := pathRegex.FindAllStringSubmatch(path, -1)
		pathSlice := pathSubmatches[0][1:]

		uri := rec.To
		for i, v := range pathSlice {
			uri = strings.Replace(uri, fmt.Sprintf("$%d", i+1), v, -1)
		}
		return uri, rec.Code
	}
	return rec.To, rec.Code
}

Fix the bug causing all the requests getting parsed by the path code


package processor

import "github.com/materials-commons/mcstore/pkg/db/schema"

// fileProcess defines an interface for processing different
// types of files. Processing may include extracting data,
// conversion of the file to a different type, or whatever
// is deemed appropriate for the file type.
type Processor interface {
	Process() error
}

// newFileProcessor creates a new instance of a fileProcessor. It looks at
// the mime type for the file to determine what kind of processor it should
// use to handle this file. By default it returns a processor that does
// nothing to the file.
func New(fileID string, mediatype schema.MediaType) Processor {

	switch mediatype.Mime {
	case "image/tiff":
		return newImageFileProcessor(fileID)
	case "image/bmp":
		return newImageFileProcessor(fileID)
	case "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":
		return newSpreadsheetFileProcessor(fileID)
	case "application/vnd.MS-Excel":
		return newSpreadsheetFileProcessor(fileID)
	default:
		// Not a file type we process (yet)
		return &noopFileProcessor{}
	}
}

Format by removing extra new line.


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

// +build !windows

package backups

import (
	"os"
	"time"
)

func creationTime(fi os.FileInfo) time.Time {
	return time.Time{}
}

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

package backups

import (
	"os"
	"time"
)

func creationTime(fi os.FileInfo) time.Time {
	return time.Time{}
}

Drop the compile tag from the windows version (the file name covers it).


package cleanhttp

import (
	"net/http"
	"strings"
	"unicode"
)

// HandlerInput provides input options to cleanhttp's handlers
type HandlerInput struct {
	ErrStatus int
}

// PrintablePathCheckHandler is a middleware that ensures the request path
// contains only printable runes.
func PrintablePathCheckHandler(next http.Handler, input *HandlerInput) http.Handler {
	// Nil-check on input to make it optional
	if input == nil {
		input = &HandlerInput{
			ErrStatus: http.StatusBadRequest,
		}
	}

	// Default to http.StatusBadRequest on error
	if input.ErrStatus == 0 {
		input.ErrStatus = http.StatusBadRequest
	}

	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// Check URL path for non-printable characters
		idx := strings.IndexFunc(r.URL.Path, func(c rune) bool {
			return !unicode.IsPrint(c)
		})

		if idx != -1 {
			w.WriteHeader(input.ErrStatus)
			return
		}

		next.ServeHTTP(w, r)
		return
	})
}

package cleanhttp

import (
	"net/http"
	"strings"
	"unicode"
)

// HandlerInput provides input options to cleanhttp's handlers
type HandlerInput struct {
	ErrStatus int
}

// PrintablePathCheckHandler is a middleware that ensures the request path
// contains only printable runes.
func PrintablePathCheckHandler(next http.Handler, input *HandlerInput) http.Handler {
	// Nil-check on input to make it optional
	if input == nil {
		input = &HandlerInput{
			ErrStatus: http.StatusBadRequest,
		}
	}

	// Default to http.StatusBadRequest on error
	if input.ErrStatus == 0 {
		input.ErrStatus = http.StatusBadRequest
	}

	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r != nil {
			// Check URL path for non-printable characters
			idx := strings.IndexFunc(r.URL.Path, func(c rune) bool {
				return !unicode.IsPrint(c)
			})

			if idx != -1 {
				w.WriteHeader(input.ErrStatus)
				return
			}

			if next != nil {
				next.ServeHTTP(w, r)
			}
		}

		return
	})
}

Fix a panic if the request passed in is nil


package integration_test

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/sclevine/agouti/core"
	. "github.com/sclevine/agouti/internal/integration"

	"os"
	"testing"
)

var (
	phantomDriver  WebDriver
	chromeDriver   WebDriver
	seleniumDriver WebDriver
	headlessOnly   bool
)

func TestIntegration(t *testing.T) {
	headlessOnly = os.Getenv("HEADLESS_ONLY") == "true"
	RegisterFailHandler(Fail)
	RunSpecs(t, "Integration Suite")
}

var _ = BeforeSuite(func() {
	phantomDriver, _ = PhantomJS()
	Expect(phantomDriver.Start()).To(Succeed())

	if !headlessOnly {
		seleniumDriver, _ = Selenium()
		chromeDriver = ChromeDriver()
		Expect(seleniumDriver.Start()).To(Succeed())
		Expect(chromeDriver.Start()).To(Succeed())
	}

	Server.Start()
})

var _ = AfterSuite(func() {
	Server.Close()
	phantomDriver.Stop()

	if !headlessOnly {
		chromeDriver.Stop()
		seleniumDriver.Stop()
	}
})

package integration_test

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/sclevine/agouti/core"
	. "github.com/sclevine/agouti/internal/integration"

	"os"
	"testing"
)

var (
	phantomDriver  WebDriver
	chromeDriver   WebDriver
	seleniumDriver WebDriver
	headlessOnly   = os.Getenv("HEADLESS_ONLY") == "true"
)

func TestIntegration(t *testing.T) {
	RegisterFailHandler(Fail)
	RunSpecs(t, "Integration Suite")
}

var _ = BeforeSuite(func() {
	phantomDriver, _ = PhantomJS()
	Expect(phantomDriver.Start()).To(Succeed())

	if !headlessOnly {
		seleniumDriver, _ = Selenium()
		chromeDriver = ChromeDriver()
		Expect(seleniumDriver.Start()).To(Succeed())
		Expect(chromeDriver.Start()).To(Succeed())
	}

	Server.Start()
})

var _ = AfterSuite(func() {
	Server.Close()
	phantomDriver.Stop()

	if !headlessOnly {
		chromeDriver.Stop()
		seleniumDriver.Stop()
	}
})

Fix detection of HEADLESS_ONLY environment variable


package main

type LoggingConfig struct {
	ProjectID       string						`json:"project_id"`
	LogName		      string						`json:"log_name"`
	Type            string            `json:"type"`
	Labels          map[string]string `json:"labels"`
}

func (c *LoggingConfig) setup() *ConfigError {
	if c.ProjectID == "" {
		return &ConfigError{Name: "project_id", Message: "is required"}
	}
	if c.LogName == "" {
		return &ConfigError{Name: "log_name", Message: "is required"}
	}
	if c.Type == "" {
		return &ConfigError{Name: "type", Message: "is required"}
	}
	if c.Labels == nil {
		return &ConfigError{Name: "labels", Message: "are required"}
	}
	return nil
}

package main

type LoggingConfig struct {
	ProjectID       string						`json:"project_id"`
	LogName		      string						`json:"log_name"`
	Type            string            `json:"type"`
	Labels          map[string]string `json:"labels"`
}

func (c *LoggingConfig) setup() *ConfigError {
	for name, blank := range map[string]bool {
		"project_id": c.ProjectID == "",
		"log_name": c.LogName == "",
		"type": c.Type == "",
		"labels": c.Labels == nil,
	}{
		if blank {
			return &ConfigError{Name: name, Message: "is required"}
		}
	}
	return nil
}

Use map to remove duplications


package manifest

import (
	"fmt"

	"github.com/docker/cli/cli"
	"github.com/docker/cli/cli/command"

	"github.com/spf13/cobra"
)

// NewManifestCommand returns a cobra command for `manifest` subcommands
func NewManifestCommand(dockerCli command.Cli) *cobra.Command {
	// use dockerCli as command.Cli
	cmd := &cobra.Command{
		Use:   "manifest COMMAND",
		Short: "Manage Docker image manifests and manifest lists",
		Long:  manifestDescription,
		Args:  cli.NoArgs,
		Run: func(cmd *cobra.Command, args []string) {
			fmt.Fprintf(dockerCli.Err(), "\n"+cmd.UsageString())
		},
	}
	cmd.AddCommand(
		newCreateListCommand(dockerCli),
		newInspectCommand(dockerCli),
		newAnnotateCommand(dockerCli),
		newPushListCommand(dockerCli),
	)
	return cmd
}

var manifestDescription = `
The **docker manifest** command has subcommands for managing image manifests and
manifest lists. A manifest list allows you to use one name to refer to the same image
built for multiple architectures.

To see help for a subcommand, use:

    docker manifest CMD --help

For full details on using docker manifest lists, see the registry v2 specification.

`

package manifest

import (
	"fmt"

	"github.com/docker/cli/cli"
	"github.com/docker/cli/cli/command"

	"github.com/spf13/cobra"
)

// NewManifestCommand returns a cobra command for `manifest` subcommands
func NewManifestCommand(dockerCli command.Cli) *cobra.Command {
	// use dockerCli as command.Cli
	cmd := &cobra.Command{
		Use:   "manifest COMMAND",
		Short: "Manage Docker image manifests and manifest lists",
		Long:  manifestDescription,
		Args:  cli.NoArgs,
		Run: func(cmd *cobra.Command, args []string) {
			fmt.Fprintf(dockerCli.Err(), "\n"+cmd.UsageString())
		},
		Annotations: map[string]string{"experimentalCLI": ""},
	}
	cmd.AddCommand(
		newCreateListCommand(dockerCli),
		newInspectCommand(dockerCli),
		newAnnotateCommand(dockerCli),
		newPushListCommand(dockerCli),
	)
	return cmd
}

var manifestDescription = `
The **docker manifest** command has subcommands for managing image manifests and
manifest lists. A manifest list allows you to use one name to refer to the same image
built for multiple architectures.

To see help for a subcommand, use:

    docker manifest CMD --help

For full details on using docker manifest lists, see the registry v2 specification.

`

Mark docker-manifest command as experimental (cli)


// +build acceptance

package app_test

import (
	stdnet "net"
	"time"

	"github.com/DATA-DOG/godog"
	"github.com/deshboard/boilerplate-grpc-service/test"
	"github.com/goph/stdlib/net"
	"google.golang.org/grpc"
)

func init() {
	test.RegisterFeaturePath("../features")
	test.RegisterFeatureContext(FeatureContext)
}

func FeatureContext(s *godog.Suite) {
	addr := net.ResolveVirtualAddr("pipe", "pipe")
	listener, dialer := net.PipeListen(addr)

	server := grpc.NewServer()
	client, _ := grpc.Dial("", grpc.WithInsecure(), grpc.WithDialer(func(s string, t time.Duration) (stdnet.Conn, error) { return dialer.Dial() }))

	// Add steps here
	func(s *godog.Suite, server *grpc.Server, client *grpc.ClientConn) {}(s, server, client)

	go server.Serve(listener)
}

// +build acceptance

package app_test

import (
	"net"

	"github.com/DATA-DOG/godog"
	"github.com/deshboard/boilerplate-grpc-service/test"
	"google.golang.org/grpc"
)

func init() {
	test.RegisterFeaturePath("../features")
	test.RegisterFeatureContext(FeatureContext)
}

func FeatureContext(s *godog.Suite) {
	lis, err := net.Listen("tcp", ":0")
	if err != nil {
		panic(err)
	}

	client, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure())
	if err != nil {
		panic(err)
	}

	server := grpc.NewServer()

	// Add steps here
	func(s *godog.Suite, server *grpc.Server, client *grpc.ClientConn) {}(s, server, client)

	go server.Serve(lis)
}

Use real network interface for gRPC acceptance testing


package config

import (
	"github.com/lifesum/configsum/pkg/errors"

	"testing"
)

func TestLocationInvalidLocale(t *testing.T) {
	var (
		input = []byte(`{"locale": "foobarz"}`)
		l     = location{}
	)

	err := l.UnmarshalJSON(input)
	if have, want := errors.Cause(err), errors.ErrInvalidPayload; have != want {
		t.Errorf("have %v, want %v", have, want)
	}
}

func TestUnmarshalUserContext(t *testing.T) {
	var (
		input = []byte(`{
			"age": 27,
			"registered": "2017-12-04T23:11:38Z",
			"subscription": 2
			}`)
		u = userInfo{}
	)

	err := u.UnmarshalJSON(input)
	if err != nil {
		t.Fatal(err)
	}
}

package config

import (
	"reflect"
	"testing"

	"github.com/lifesum/configsum/pkg/errors"
)

func TestLocationInvalidLocale(t *testing.T) {
	var (
		input = []byte(`{"locale": "foobarz"}`)
		l     = location{}
	)

	err := l.UnmarshalJSON(input)
	if have, want := errors.Cause(err), errors.ErrInvalidPayload; have != want {
		t.Errorf("have %v, want %v", have, want)
	}
}

func TestUnmarshalUserContext(t *testing.T) {
	var (
		input = []byte(`{
			"age": 27,
			"registered": "2017-12-04T23:11:38Z",
			"subscription": 2
			}`)
		u = userInfo{}
	)

	err := u.UnmarshalJSON(input)
	if err != nil {
		t.Fatal(err)
	}

	have := u
	want := userInfo{
		Age:          27,
		Registered:   "2017-12-04T23:11:38Z",
		Subscription: 2,
	}

	if !reflect.DeepEqual(have, want) {
		t.Errorf("have %v, want %v", have, want)
	}
}

Update unmarshal test for User context


package goat

import (
	"log"
	"net"
	"strconv"
)

// Listener interface method Listen defines a network listener which accepts connections
type Listener interface {
	Listen(chan bool)
}

// HTTPListener listens for HTTP (TCP) connections
type HTTPListener struct {
}

// Listen and handle HTTP (TCP) connections
func (h HTTPListener) Listen(httpDoneChan chan bool) {
	// Listen on specified TCP port
	l, err := net.Listen("tcp", ":"+strconv.Itoa(Static.Config.Port))
	if err != nil {
		log.Println(err.Error())
	}

	// Send listener to HttpConnHandler
	go new(HTTPConnHandler).Handle(l, httpDoneChan)
}

// UDPListener listens for UDP connections
type UDPListener struct {
}

// Listen on specified UDP port, accept and handle connections
func (u UDPListener) Listen(udpDoneChan chan bool) {
	// Listen on specified UDP port
	addr, err := net.ResolveUDPAddr("udp", ":"+strconv.Itoa(Static.Config.Port))
	l, err := net.ListenUDP("udp", addr)
	if err != nil {
		log.Println(err.Error())
	}

	// Send listener to UdpConnHandler
	go new(UDPConnHandler).Handle(l, udpDoneChan)
}

package goat

import (
	"log"
	"net"
	"os"
	"strconv"
)

// Listener interface method Listen defines a network listener which accepts connections
type Listener interface {
	Listen(chan bool)
}

// HTTPListener listens for HTTP (TCP) connections
type HTTPListener struct {
}

// Listen and handle HTTP (TCP) connections
func (h HTTPListener) Listen(httpDoneChan chan bool) {
	// Listen on specified TCP port
	l, err := net.Listen("tcp", ":"+strconv.Itoa(Static.Config.Port))
	if err != nil {
		log.Println(err.Error())
		log.Println("Cannot start HTTP server, exiting now.")
		os.Exit(1)
	}

	// Send listener to HttpConnHandler
	go new(HTTPConnHandler).Handle(l, httpDoneChan)
}

// UDPListener listens for UDP connections
type UDPListener struct {
}

// Listen on specified UDP port, accept and handle connections
func (u UDPListener) Listen(udpDoneChan chan bool) {
	// Listen on specified UDP port
	addr, err := net.ResolveUDPAddr("udp", ":"+strconv.Itoa(Static.Config.Port))
	l, err := net.ListenUDP("udp", addr)
	if err != nil {
		log.Println(err.Error())
	}

	// Send listener to UdpConnHandler
	go new(UDPConnHandler).Handle(l, udpDoneChan)
}

Exit on failure to listen over HTTP


package main

import (
	"os"

	"github.com/Sirupsen/logrus"
	"github.com/citadel/citadel"
	"github.com/codegangsta/cli"
)

var (
	logger   = logrus.New()
	registry citadel.Registry
)

func main() {
	app := cli.NewApp()
	app.Usage = "mangage your docker containers across hosts"
	app.Name = "citadel"
	app.Version = "0.1"
	app.Author = "citadel team"

	app.Before = func(context *cli.Context) error {
		registry = citadel.NewRegistry(context.GlobalStringSlice("etcd-machines"))

		return nil
	}

	app.Flags = []cli.Flag{
		cli.StringSliceFlag{"etcd-machines", &cli.StringSlice{"http://127.0.0.1:4001"}, "etcd hosts"},
	}

	app.Commands = []cli.Command{
		appCommand,
		deleteCommand,
		startCommand,
		stopCommand,
		loadCommand,
		liveCommand,
		containerCommand,
		hostCommand,
		hostsCommand,
		managementCommand,
	}

	if err := app.Run(os.Args); err != nil {
		logger.Fatal(err)
	}
}

package main

import (
	"os"

	"github.com/Sirupsen/logrus"
	"github.com/citadel/citadel"
	"github.com/codegangsta/cli"
)

var (
	logger   = logrus.New()
	registry citadel.Registry
)

func main() {
	app := cli.NewApp()
	app.Usage = "mangage your docker containers across hosts"
	app.Name = "citadel"
	app.Version = "0.1"
	app.Author = "citadel team"

	app.Before = func(context *cli.Context) error {
		registry = citadel.NewRegistry(context.GlobalStringSlice("etcd-machines"))
		if context.GlobalBool("debug") {
			logger.Level = logrus.Debug
		}

		return nil
	}

	app.Flags = []cli.Flag{
		cli.StringSliceFlag{"etcd-machines", &cli.StringSlice{"http://127.0.0.1:4001"}, "etcd hosts"},
		cli.BoolFlag{"debug", "run the logger at the debug level"},
	}

	app.Commands = []cli.Command{
		appCommand,
		deleteCommand,
		startCommand,
		stopCommand,
		loadCommand,
		liveCommand,
		containerCommand,
		hostCommand,
		hostsCommand,
		managementCommand,
	}

	if err := app.Run(os.Args); err != nil {
		logger.Fatal(err)
	}
}

Add debug flag for logger


package discovery

import (
	"fmt"
	"github.com/coreos/go-etcd/etcd"
)

type Service interface {
	Get(key string) (string, error)
}

type Etcd struct {
	client *etcd.Client
}

func NewEtcd(machines []string) *Etcd {
	return &Etcd{
		client: etcd.NewClient(machines),
	}
}

func (e *Etcd) Get(key string) (string, error) {
	responses, err := e.client.Get(key)
	if err != nil {
		return "", err
	}
	if len(responses) == 0 {
		return "", fmt.Errorf("Not found")
	}
	return responses[0].Value, nil
}

package discovery

import (
	"fmt"
	"github.com/coreos/go-etcd/etcd"
)

type Service interface {
	Get(key string) (string, error)
}

type Etcd struct {
	client *etcd.Client
}

func NewEtcd(machines []string) *Etcd {
	return &Etcd{
		client: etcd.NewClient(machines),
	}
}

func (e *Etcd) Get(key string) (string, error) {
	response, err := e.client.Get(key, false, true)
	if err != nil {
		return "", err
	}
	if response == nil {
		return "", fmt.Errorf("Not found")
	}
	return response.Value, nil
}

Update for last etcd interface


package viber

import (
	"bytes"
	"encoding/json"
	"io/ioutil"
	"net/http"
)

// PostData to viber API
func (v *Viber) PostData(url string, i interface{}) ([]byte, error) {
	b, err := json.Marshal(i)
	if err != nil {
		return nil, err
	}

	Log.Println("Post data:", string(b))

	req, err := http.NewRequest("POST", url, bytes.NewBuffer(b))
	req.Header.Add("X-Viber-Auth-Token", v.AppKey)
	req.Close = true

	resp, err := v.client.Do(req)
	if err != nil {
		return nil, err
	}

	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	return body, nil
}

package viber

import (
	"bytes"
	"encoding/json"
	"io/ioutil"
	"net/http"
)

// PostData to viber API
func (v *Viber) PostData(url string, i interface{}) ([]byte, error) {
	b, err := json.Marshal(i)
	if err != nil {
		return nil, err
	}

	Log.Println("Post data:", string(b))

	req, err := http.NewRequest("POST", url, bytes.NewBuffer(b))
	req.Header.Add("X-Viber-Auth-Token", v.AppKey)
	req.Close = true

	if v.client == nil {
		v.client = &http.Client{}
	}

	resp, err := v.client.Do(req)
	if err != nil {
		return nil, err
	}

	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	return body, nil
}

Fix runtime error on v.client.Do()


package main

import (
	"fmt"
	"log"
	"net/http"
	"os"
	"os/signal"
	"showrss/handlers"

	"flag"

	"syscall"

	"github.com/braintree/manners"
)

const version = "1.0.0"

func main() {
	var httpAddr = flag.String("http", "localhost:7000", "HTTP service address")
	flag.Parse()

	log.Println("Starting server ...")
	log.Printf("HTTP service listening on %s", *httpAddr)

	errChan := make(chan error, 10)

	mux := http.NewServeMux()
	mux.HandleFunc("/", handlers.EpisodeHandler)
	httpServer := manners.NewServer()
	httpServer.Addr = *httpAddr
	httpServer.Handler = handlers.LoggingHandler(mux)

	go func() {
		errChan <- httpServer.ListenAndServe()
	}()

	signalChan := make(chan os.Signal, 1)
	signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM)

	for {
		select {
		case err := <-errChan:
			if err != nil {
				log.Fatal(err)
			}
		case s := <-signalChan:
			log.Println(fmt.Sprintf("Captured %v. Exiting...", s))
			httpServer.BlockingClose()
			os.Exit(0)
		}
	}

}

package main

import (
	"fmt"
	"log"
	"net/http"
	"os"
	"os/signal"
	"showrss/handlers"

	"flag"

	"syscall"

	"github.com/braintree/manners"
)

const version = "1.0.0"

func main() {
	var httpAddr = flag.String("http", "0.0.0.0:8000", "HTTP service address")
	flag.Parse()

	log.Println("Starting server ...")
	log.Printf("HTTP service listening on %s", *httpAddr)

	errChan := make(chan error, 10)

	mux := http.NewServeMux()
	mux.HandleFunc("/", handlers.HelloHandler)
	httpServer := manners.NewServer()
	httpServer.Addr = *httpAddr
	httpServer.Handler = handlers.LoggingHandler(mux)

	go func() {
		errChan <- httpServer.ListenAndServe()
	}()

	signalChan := make(chan os.Signal, 1)
	signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM)

	for {
		select {
		case err := <-errChan:
			if err != nil {
				log.Fatal(err)
			}
		case s := <-signalChan:
			log.Println(fmt.Sprintf("Captured %v. Exiting...", s))
			httpServer.BlockingClose()
			os.Exit(0)
		}
	}

}

Change default addr for http server


package httpd

import (
	"bufio"
	"fmt"
	"github.com/Symantec/Dominator/lib/html"
	"net/http"
)

func statusHandler(w http.ResponseWriter, req *http.Request) {
	writer := bufio.NewWriter(w)
	defer writer.Flush()
	fmt.Fprintln(writer, "<title>imageserver status page</title>")
	fmt.Fprintln(writer, "")
	fmt.Fprintln(writer, "")
	fmt.Fprintln(writer, "
imageserver status page
")
	fmt.Fprintln(writer, "")
	html.WriteHeaderWithRequest(writer, req)
	fmt.Fprintln(writer, "
")
	for _, htmlWriter := range htmlWriters {
		htmlWriter.WriteHtml(writer)
	}
	fmt.Fprintln(writer, "
")
	fmt.Fprintln(writer, "
")
	html.WriteFooter(writer)
	fmt.Fprintln(writer, "")
}

package httpd

import (
	"bufio"
	"fmt"
	"github.com/Symantec/Dominator/lib/html"
	"github.com/Symantec/Dominator/lib/srpc"
	"net/http"
)

func statusHandler(w http.ResponseWriter, req *http.Request) {
	writer := bufio.NewWriter(w)
	defer writer.Flush()
	fmt.Fprintln(writer, "<title>imageserver status page</title>")
	fmt.Fprintln(writer, "")
	fmt.Fprintln(writer, "")
	fmt.Fprintln(writer, "
imageserver status page
")
	if !srpc.CheckTlsRequired() {
		fmt.Fprintln(writer,
			`<h1><font color="red">Running in insecure mode. Your images can be pwned!!!</font></h1>`)
	}
	fmt.Fprintln(writer, "")
	html.WriteHeaderWithRequest(writer, req)
	fmt.Fprintln(writer, "
")
	for _, htmlWriter := range htmlWriters {
		htmlWriter.WriteHtml(writer)
	}
	fmt.Fprintln(writer, "
")
	fmt.Fprintln(writer, "
")
	html.WriteFooter(writer)
	fmt.Fprintln(writer, "")
}

Add warning banner to imageserver if in insecure mode.


package read

// Fre scores the Flesch reading-ease.
// See https://en.wikipedia.org/wiki/Flesch–Kincaid_readability_tests#Flesch_reading_ease.
func Fre(text string) float64 {
	sylCnt := float64(CntSyls(text))
	wordCnt := float64(CntWords(text))
	sentCnt := float64(CntSents(text))
	return 206.835 - 1.015*(wordCnt/sentCnt) - 84.6*(sylCnt/wordCnt)
}

package read

// Fre scores the Flesch reading-ease.
// See https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FFlesch%E2%80%93Kincaid_readability_tests%23Flesch_reading_ease.
func Fre(text string) float64 {
	sylCnt := float64(CntSyls(text))
	wordCnt := float64(CntWords(text))
	sentCnt := float64(CntSents(text))
	return 206.835 - 1.015*(wordCnt/sentCnt) - 84.6*(sylCnt/wordCnt)
}

Fix wikipedia url to Flesch reading-ease.


package Yafg

import (
  "net/http"
)

// A wrapper of http.ResponseWriter
type Response struct {
  Response http.ResponseWriter
}

func NewResponse(res http.ResponseWriter) *Response {
  response := new(Response)
  response.Response = res
  return response
}

package Yafg

import (
  "net/http"
  "time"
)

// A wrapper of http.ResponseWriter
type Response struct {
  http.ResponseWriter
}

func NewResponse(res http.ResponseWriter) *Response {
  response := new(Response)
  response.ResponseWriter = res
  return response
}

func (res *Response) Send(str string) {
  res.Write([]byte(str))
}

func (res *Response) Redirect(url string, code int) {
  res.Header().Set("Location", url)
  res.WriteHeader(code)
}

func (res *Response) SetCookie(key string, value string, expire int) {
  now := time.Now()
  expireTime := now.Add(time.Duration(expire) * time.Second)
  cookie := &http.Cookie{
    Name: key,
    Value: value,
    Path: "/",
    MaxAge: expire,
    Expires: expireTime,
  }
  http.SetCookie(res, cookie)
}

Use embedded struct for request.go


package serverlogger

import (
	"flag"
	"github.com/Symantec/Dominator/lib/log/debuglogger"
	"github.com/Symantec/Dominator/lib/logbuf"
	"io"
)

var (
	initialLogDebugLevel = flag.Int("initialLogDebugLevel", -1,
		"initial debug log level")
)

type Logger struct {
	*debuglogger.Logger
	circularBuffer *logbuf.LogBuffer
}

// New will create a Logger which has an internal log buffer (see the
// lib/logbuf package). It implements the log.DebugLogger interface.
// By default, the max debug level is -1, meaning all debug logs are dropped
// (ignored)
func New() *Logger {
	return newLogger()
}

// Flush flushes the open log file (if one is open). This should only be called
// just prior to process termination. The log file is automatically flushed
// after short periods of inactivity.
func (l *Logger) Flush() error {
	return l.circularBuffer.Flush()
}

// WriteHtml will write the contents of the internal log buffer to writer, with
// appropriate HTML markups.
func (l *Logger) WriteHtml(writer io.Writer) {
	l.circularBuffer.WriteHtml(writer)
}

package serverlogger

import (
	"flag"
	"fmt"
	"github.com/Symantec/Dominator/lib/log/debuglogger"
	"github.com/Symantec/Dominator/lib/logbuf"
	"io"
	"os"
)

var (
	initialLogDebugLevel = flag.Int("initialLogDebugLevel", -1,
		"initial debug log level")
)

type Logger struct {
	*debuglogger.Logger
	circularBuffer *logbuf.LogBuffer
}

// New will create a Logger which has an internal log buffer (see the
// lib/logbuf package). It implements the log.DebugLogger interface.
// By default, the max debug level is -1, meaning all debug logs are dropped
// (ignored)
func New() *Logger {
	return newLogger()
}

func (l *Logger) Fatal(v ...interface{}) {
	msg := fmt.Sprint(v...)
	l.Print(msg)
	l.circularBuffer.Flush()
	os.Exit(1)
}

func (l *Logger) Fatalf(format string, v ...interface{}) {
	l.Fatal(fmt.Sprintf(format, v...))
}

func (l *Logger) Fatalln(v ...interface{}) {
	l.Fatal(fmt.Sprintln(v...))
}

// Flush flushes the open log file (if one is open). This should only be called
// just prior to process termination. The log file is automatically flushed
// after short periods of inactivity.
func (l *Logger) Flush() error {
	return l.circularBuffer.Flush()
}

// WriteHtml will write the contents of the internal log buffer to writer, with
// appropriate HTML markups.
func (l *Logger) WriteHtml(writer io.Writer) {
	l.circularBuffer.WriteHtml(writer)
}

Call Flush() in Fatal() methods of lib/log/serverlogger.Logger.


package google

import (
	"os"
	"testing"

	"github.com/hashicorp/terraform/helper/schema"
	"github.com/hashicorp/terraform/terraform"
)

var testAccProviders map[string]terraform.ResourceProvider
var testAccProvider *schema.Provider

func init() {
	testAccProvider = Provider().(*schema.Provider)
	testAccProviders = map[string]terraform.ResourceProvider{
		"google": testAccProvider,
	}
}

func TestProvider(t *testing.T) {
	if err := Provider().(*schema.Provider).InternalValidate(); err != nil {
		t.Fatalf("err: %s", err)
	}
}

func TestProvider_impl(t *testing.T) {
	var _ terraform.ResourceProvider = Provider()
}

func testAccPreCheck(t *testing.T) {
	if v := os.Getenv("GOOGLE_CREDENTIALS"); v == "" {
		t.Fatal("GOOGLE_CREDENTIALS must be set for acceptance tests")
	}

	if v := os.Getenv("GOOGLE_PROJECT"); v == "" {
		t.Fatal("GOOGLE_PROJECT must be set for acceptance tests")
	}

	if v := os.Getenv("GOOGLE_REGION"); v != "us-central1" {
		t.Fatal("GOOGLE_REGION must be set to us-central1 for acceptance tests")
	}
}

package google

import (
	"io/ioutil"
	"os"
	"testing"

	"github.com/hashicorp/terraform/helper/schema"
	"github.com/hashicorp/terraform/terraform"
)

var testAccProviders map[string]terraform.ResourceProvider
var testAccProvider *schema.Provider

func init() {
	testAccProvider = Provider().(*schema.Provider)
	testAccProviders = map[string]terraform.ResourceProvider{
		"google": testAccProvider,
	}
}

func TestProvider(t *testing.T) {
	if err := Provider().(*schema.Provider).InternalValidate(); err != nil {
		t.Fatalf("err: %s", err)
	}
}

func TestProvider_impl(t *testing.T) {
	var _ terraform.ResourceProvider = Provider()
}

func testAccPreCheck(t *testing.T) {
	if v := os.Getenv("GOOGLE_CREDENTIALS_FILE"); v != "" {
		creds, err := ioutil.ReadFile(v)
		if err != nil {
			t.Fatalf("Error reading GOOGLE_CREDENTIALS_FILE path: %s", err)
		}
		os.Setenv("GOOGLE_CREDENTIALS", string(creds))
	}

	if v := os.Getenv("GOOGLE_CREDENTIALS"); v == "" {
		t.Fatal("GOOGLE_CREDENTIALS must be set for acceptance tests")
	}

	if v := os.Getenv("GOOGLE_PROJECT"); v == "" {
		t.Fatal("GOOGLE_PROJECT must be set for acceptance tests")
	}

	if v := os.Getenv("GOOGLE_REGION"); v != "us-central1" {
		t.Fatal("GOOGLE_REGION must be set to us-central1 for acceptance tests")
	}
}

Allow acctests to set credentials via file


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

package reswriter

const tfversions string = `
terraform {
  required_version = ">= 0.13"

  required_providers {
    google = {
      source  = "hashicorp/google"
      version = "~> 3.0"
    }
    google-beta = {
      source  = "hashicorp/google-beta"
      version = "~> 3.0"
    }
  }
}
`

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

package reswriter

const tfversions string = `
terraform {
  required_version = ">= 0.13"

  required_providers {
    google = {
      source  = "hashicorp/google"
      version = ">= 3.83, < 5.0"
    }
    google-beta = {
      source  = "hashicorp/google-beta"
      version = ">= 3.83, < 5.0"
    }
  }
}
`

Allow 4.x TPG (Terraform Provider Google)


package dockerignore

import (
	"bufio"
	"fmt"
	"io"
	"path/filepath"
	"strings"
)

// ReadAll reads a .dockerignore file and returns the list of file patterns
// to ignore. Note this will trim whitespace from each line as well
// as use GO's "clean" func to get the shortest/cleanest path for each.
func ReadAll(reader io.ReadCloser) ([]string, error) {
	if reader == nil {
		return nil, nil
	}
	defer reader.Close()
	scanner := bufio.NewScanner(reader)
	var excludes []string

	for scanner.Scan() {
		pattern := strings.TrimSpace(scanner.Text())
		if pattern == "" {
			continue
		}
		pattern = filepath.Clean(pattern)
		excludes = append(excludes, pattern)
	}
	if err := scanner.Err(); err != nil {
		return nil, fmt.Errorf("Error reading .dockerignore: %v", err)
	}
	return excludes, nil
}

package dockerignore

import (
	"bufio"
	"fmt"
	"io"
	"path/filepath"
	"strings"
)

// ReadAll reads a .dockerignore file and returns the list of file patterns
// to ignore. Note this will trim whitespace from each line as well
// as use GO's "clean" func to get the shortest/cleanest path for each.
func ReadAll(reader io.ReadCloser) ([]string, error) {
	if reader == nil {
		return nil, nil
	}
	defer reader.Close()
	scanner := bufio.NewScanner(reader)
	var excludes []string

	for scanner.Scan() {
		pattern := strings.TrimSpace(scanner.Text())
		if pattern == "" {
			continue
		}
		pattern = filepath.Clean(pattern)
		pattern = filepath.ToSlash(pattern)
		excludes = append(excludes, pattern)
	}
	if err := scanner.Err(); err != nil {
		return nil, fmt.Errorf("Error reading .dockerignore: %v", err)
	}
	return excludes, nil
}

Fix ReadAll to run on Windows.


package tailtopic

import (
	avro "github.com/elodina/go-avro"
	kavro "github.com/elodina/go-kafka-avro"
)

type avroSchemaRegistryDecoder struct {
	decoder *kavro.KafkaAvroDecoder
}

func newAvroDecoder(schemaregURI string) decoder {
	return &avroSchemaRegistryDecoder{kavro.NewKafkaAvroDecoder(schemaregURI)}
}

func (sr *avroSchemaRegistryDecoder) decode(msg []byte) (string, error) {
	decodedRecord, err := sr.decoder.Decode(msg)
	if err != nil {
		return "", err
	}
	return (decodedRecord.(*avro.GenericRecord)).String(), nil
}

package tailtopic

import (
	avro "github.com/dejan/go-avro"
	kavro "github.com/dejan/go-kafka-avro"
)

type avroSchemaRegistryDecoder struct {
	decoder *kavro.KafkaAvroDecoder
}

func newAvroDecoder(schemaregURI string) decoder {
	return &avroSchemaRegistryDecoder{kavro.NewKafkaAvroDecoder(schemaregURI)}
}

func (sr *avroSchemaRegistryDecoder) decode(msg []byte) (string, error) {
	decodedRecord, err := sr.decoder.Decode(msg)
	if err != nil {
		return "", err
	}
	return (decodedRecord.(*avro.GenericRecord)).String(), nil
}

Use my forks until NS fix is merged upstream


package hackedu

import "net/http"

func middleware(w http.ResponseWriter, r *http.Request) {
	allowCORS(w, r)
}

func allowCORS(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Access-Control-Allow-Origin", "*")
}

package hackedu

import "net/http"

func middleware(w http.ResponseWriter, r *http.Request) {
	allowCORS(w, r)
}

func allowCORS(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Headers",
		"Origin, X-Requested-With, Content-Type, Accept")
}

Add Access-Control-Allow-Headers header to responses.


package drivers

import "fmt"

var ErrTaskNotFound = fmt.Errorf("task not found for given id")

var DriverRequiresRootMessage = "Driver must run as root"

Add consistent message for requires root


package unionfs

import (
	"fmt"
	"log"
	"time"
	"testing"
)

var _ = fmt.Print
var _ = log.Print

func TestTimedCache(t *testing.T) {
	fetchCount := 0
	fetch := func(n string) interface{} {
		fetchCount++
		i := int(n[0])
		return &i
	}

	var ttl int64
	ttl = 1e6

	cache := NewTimedCache(fetch, ttl)
	v := cache.Get("n").(*int)
	if *v != int('n') {
		t.Errorf("value mismatch: got %d, want %d", *v, int('n'))
	}
	if fetchCount != 1 {
		t.Errorf("fetch count mismatch: got %d want 1", fetchCount)
	}

	// The cache update is async.
	time.Sleep(ttl / 10)

	w := cache.Get("n")
	if v != w {
		t.Errorf("Huh, inconsistent: 1st = %v != 2nd = %v", v, w)
	}

	if fetchCount > 1 {
		t.Errorf("fetch count fail: %d > 1", fetchCount)
	}

	time.Sleep(ttl * 2)
	cache.Purge()

	w = cache.Get("n")
	if fetchCount == 1 {
		t.Error("Did not fetch again. Purge unsuccessful?")
	}
}

package unionfs

import (
	"fmt"
	"log"
	"time"
	"testing"
)

var _ = fmt.Print
var _ = log.Print

func TestTimedCache(t *testing.T) {
	fetchCount := 0
	fetch := func(n string) interface{} {
		fetchCount++
		i := int(n[0])
		return &i
	}

	var ttl int64

	// This fails with 1e6 on some Opteron CPUs.
	ttl = 1e8

	cache := NewTimedCache(fetch, ttl)
	v := cache.Get("n").(*int)
	if *v != int('n') {
		t.Errorf("value mismatch: got %d, want %d", *v, int('n'))
	}
	if fetchCount != 1 {
		t.Errorf("fetch count mismatch: got %d want 1", fetchCount)
	}

	// The cache update is async.
	time.Sleep(ttl / 10)

	w := cache.Get("n")
	if v != w {
		t.Errorf("Huh, inconsistent: 1st = %v != 2nd = %v", v, w)
	}

	if fetchCount > 1 {
		t.Errorf("fetch count fail: %d > 1", fetchCount)
	}

	time.Sleep(ttl * 2)
	cache.Purge()

	w = cache.Get("n")
	if fetchCount == 1 {
		t.Error("Did not fetch again. Purge unsuccessful?")
	}
}

Fix test for some opteron cpus.


package formatters

import (
	"syscall"
	"unsafe"
)

type winsize struct {
	Row    uint16
	Col    uint16
	Xpixel uint16
	Ypixel uint16
}

func getTerminalWidth() uint {
	ws := &winsize{}
	retCode, _, errno := syscall.Syscall(syscall.SYS_IOCTL,
		uintptr(syscall.Stdin),
		uintptr(syscall.TIOCGWINSZ),
		uintptr(unsafe.Pointer(ws)))

	if int(retCode) == -1 {
		panic(errno)
	}
	return uint(ws.Col)
}

package formatters

import (
	"syscall"
	"unsafe"
)

type winsize struct {
	Row    uint16
	Col    uint16
	Xpixel uint16
	Ypixel uint16
}

func SetTerminalWidthFn(f func() uint) {
	getTerminalWidth = f
}

var getTerminalWidth = func() uint {
	ws := &winsize{}
	retCode, _, errno := syscall.Syscall(syscall.SYS_IOCTL,
		uintptr(syscall.Stdin),
		uintptr(syscall.TIOCGWINSZ),
		uintptr(unsafe.Pointer(ws)))

	if int(retCode) == -1 {
		panic(errno)
	}
	return uint(ws.Col)
}

Add an interface for mocking the terminal width defining function


package ebay

import "encoding/xml"

type RelistFixedPriceItem struct {
	ItemID                string
	StartPrice            string                 `xml:",omitempty"`
	ConditionID           uint                   `xml:",omitempty"`
	Quantity              uint                   `xml:",omitempty"`
	Title                 string                 `xml:",omitempty"`
	Description           string                 `xml:",omitempty"`
	PayPalEmailAddress    string                 `xml:",omitempty"`
	PictureDetails        *PictureDetails        `xml:",omitempty"`
	ShippingDetails       *ShippingDetails       `xml:",omitempty"`
	ProductListingDetails *ProductListingDetails `xml:",omitempty"`
	ItemSpecifics         []ItemSpecifics        `xml:",omitempty"`
}

func (c RelistFixedPriceItem) CallName() string {
	return "RelistFixedPriceItem"
}

func (c RelistFixedPriceItem) Body() interface{} {
	type Item struct {
		RelistFixedPriceItem
	}

	return Item{c}
}

func (c RelistFixedPriceItem) ParseResponse(r []byte) (EbayResponse, error) {
	var xmlResponse RelistFixedPriceItemResponse
	err := xml.Unmarshal(r, &xmlResponse)

	return xmlResponse, err
}

type RelistFixedPriceItemResponse struct {
	ebayResponse
}

func (r RelistFixedPriceItemResponse) ResponseErrors() ebayErrors {
	return r.ebayResponse.Errors
}

package ebay

import "encoding/xml"

type RelistFixedPriceItem struct {
	ItemID                string
	StartPrice            string                 `xml:",omitempty"`
	ConditionID           uint                   `xml:",omitempty"`
	Quantity              uint                   `xml:",omitempty"`
	Title                 string                 `xml:",omitempty"`
	Description           string                 `xml:",omitempty"`
	PayPalEmailAddress    string                 `xml:",omitempty"`
	PictureDetails        *PictureDetails        `xml:",omitempty"`
	ShippingDetails       *ShippingDetails       `xml:",omitempty"`
	ProductListingDetails *ProductListingDetails `xml:",omitempty"`
	ItemSpecifics         []ItemSpecifics        `xml:",omitempty"`
}

func (c RelistFixedPriceItem) CallName() string {
	return "RelistFixedPriceItem"
}

func (c RelistFixedPriceItem) Body() interface{} {
	type Item struct {
		RelistFixedPriceItem
	}

	return Item{c}
}

func (c RelistFixedPriceItem) ParseResponse(r []byte) (EbayResponse, error) {
	var xmlResponse RelistFixedPriceItemResponse
	err := xml.Unmarshal(r, &xmlResponse)

	return xmlResponse, err
}

type RelistFixedPriceItemResponse struct {
	ebayResponse

	ItemID string
}

func (r RelistFixedPriceItemResponse) ResponseErrors() ebayErrors {
	return r.ebayResponse.Errors
}

Add ItemID response field to relist fixed price item command


package controllers

import (
	"github.com/anonx/sunplate/skeleton/assets/views"

	"github.com/anonx/sunplate/action"
)

// App is a sample controller that is used for demonstration purposes.
type App struct {
	*Controller
}

// Before is a magic method that is executed before every request.
func (c *App) Before(name string, pages []int) action.Result {
	return nil
}

// Index is an action that is used for generation of a greeting form.
func (c *App) Index() action.Result {
	return c.RenderTemplate(views.Paths.App.IndexHTML)
}

// PostGreet prints received user fullname. If it is not valid,
// user is redirected back to index page.
func (c *App) PostGreet(name string) action.Result {
	c.Context["name"] = name
	return c.RenderTemplate(views.Paths.App.GreetHTML)
}

// After is a magic method that is executed after every request.
func (c *App) After() action.Result {
	return nil
}

// Finally is a magic method that is executed after every request
// no matter what.
func (c *App) Finally(name string) action.Result {
	return nil
}

package controllers

import (
	v "github.com/anonx/sunplate/skeleton/assets/views"

	"github.com/anonx/sunplate/action"
)

// App is a sample controller that is used for demonstration purposes.
type App struct {
	*Controller
}

// Before is a magic method that is executed before every request.
func (c *App) Before(name string, pages []int) action.Result {
	return nil
}

// Index is an action that is used for generation of a greeting form.
func (c *App) Index() action.Result {
	return c.RenderTemplate(v.Paths.App.IndexHTML)
}

// PostGreet prints received user fullname. If it is not valid,
// user is redirected back to index page.
func (c *App) PostGreet(name string) action.Result {
	c.Context["name"] = name
	return c.RenderTemplate(v.Paths.App.GreetHTML)
}

// After is a magic method that is executed after every request.
func (c *App) After() action.Result {
	return nil
}

// Finally is a magic method that is executed after every request
// no matter what.
func (c *App) Finally(name string) action.Result {
	return nil
}

Use v as a selector arther than views


package main_test

import (
	"net/http"
	"net/http/httptest"

	. "github.com/alphagov/publishing-api"
	. "github.com/alphagov/publishing-api/testhelpers"

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

var _ = Describe("GET /healthcheck", func() {
	var (
		testPublishingAPI *httptest.Server
	)

	BeforeEach(func() {
		testPublishingAPI = httptest.NewServer(BuildHTTPMux("", ""))
	})

	AfterEach(func() {
		testPublishingAPI.Close()
	})

	It("has a healthcheck endpoint which responds with a status of OK", func() {
		response, err := http.Get(testPublishingAPI.URL + "/healthcheck")
		Expect(err).To(BeNil())
		Expect(response.StatusCode).To(Equal(http.StatusOK))

		body, err := ReadResponseBody(response)
		Expect(err).To(BeNil())
		Expect(body).To(Equal(`{"status":"OK"}`))
	})
})

package main_test

import (
	"net/http"
	"net/http/httptest"

	. "github.com/alphagov/publishing-api"
	. "github.com/alphagov/publishing-api/testhelpers"

	. "github.com/onsi/ginkgo"
)

var _ = Describe("GET /healthcheck", func() {
	It("has a healthcheck endpoint which responds with a status of OK", func() {
		var testPublishingAPI = httptest.NewServer(BuildHTTPMux("", ""))

		actualResponse := DoRequest("GET", testPublishingAPI.URL+"/healthcheck", nil)

		var expectedResponse = HTTPTestResponse{Code: http.StatusOK, Body: `{"status":"OK"}`}
		AssertSameResponse(actualResponse, &expectedResponse)
	})
})

Use testhelpers to compact healthcheck test


package nv

import (
  "encoding/json"
  "time"
)

type NV_Event struct {
    ServerID    string
    Timestamp   time.Time
    ARI_Event   string
}

func Init(in chan []byte, out chan *NV_Event) {
  go func(in chan []byte, out chan *NV_Event) {
    for instring := range in {
      var e *NV_Event
      json.Unmarshal(instring, e)
      out <- e
    }
  }(in, out)
}

package nv

import (
  "encoding/json"
  "time"
)

type NV_Event struct {
  ServerID    string    `json:"server_id"`
  Timestamp   time.Time `json:"timestamp"`
  Type        string    `json:"type"`
  ARI_Event   string    `json:"ari_event"`
}

func Init(in chan []byte, out chan *NV_Event) {
  go func(in chan []byte, out chan *NV_Event) {
    for instring := range in {
      var e *NV_Event
      json.Unmarshal(instring, e)
      out <- e
    }
  }(in, out)
}

Update NV_Event struct to match proxy


package goldi

import "fmt"

type TypeRegistry map[string]*Type

func NewTypeRegistry() TypeRegistry {
	return TypeRegistry{}
}

func (r TypeRegistry) RegisterType(typeID string, generatorFunction interface{}) error {
	t, err := NewType(generatorFunction)
	if err != nil {
		return err
	}

	return r.Register(typeID, t)
}

func (r TypeRegistry) Register(typeID string, typeDef *Type) (err error) {
	_, typeHasAlreadyBeenRegistered := r[typeID]
	if typeHasAlreadyBeenRegistered {
		return fmt.Errorf("type %q has already been registered", typeID)
	}

	r[typeID] = typeDef
	return nil
}

package goldi

import "fmt"

type TypeRegistry map[string]*Type

func NewTypeRegistry() TypeRegistry {
	return TypeRegistry{}
}

func (r TypeRegistry) RegisterType(typeID string, generatorFunction interface{}, arguments ...interface{}) error {
	t, err := NewType(generatorFunction, arguments...)
	if err != nil {
		return err
	}

	return r.Register(typeID, t)
}

func (r TypeRegistry) Register(typeID string, typeDef *Type) (err error) {
	_, typeHasAlreadyBeenRegistered := r[typeID]
	if typeHasAlreadyBeenRegistered {
		return fmt.Errorf("type %q has already been registered", typeID)
	}

	r[typeID] = typeDef
	return nil
}

Add factory arguments to TypeRegistry.RegisterType


package armoredcrypt

import (
	"fmt"
	"encoding/base64"
	"strings"
)

const (
	_MAGIC_PREFIX = "saltybox"
	_V1_MAGIC = "saltybox1:"
)

func Wrap(body []byte) string {
	encoded := base64.RawURLEncoding.EncodeToString(body)

	return fmt.Sprintf("%s%s", _V1_MAGIC, encoded)
}

func Unwrap(varmoredBody string) ([]byte, error) {
	if len(varmoredBody) < len(_V1_MAGIC) {
		return nil, fmt.Errorf("input size smaller than magic marker; likely truncated")
	}

	if strings.HasPrefix(varmoredBody, _V1_MAGIC) {
		armoredBody := strings.TrimPrefix(varmoredBody, _V1_MAGIC)
		body, err := base64.RawURLEncoding.DecodeString(armoredBody)
		if err != nil {
			return nil, fmt.Errorf("base64 decoding failed: %s", err)
		}

		return body, nil
	} else if strings.HasPrefix(varmoredBody, _MAGIC_PREFIX) {
		return nil, fmt.Errorf("input claims to be saltybox, but not a version we support")
	} else {
		return nil, fmt.Errorf("input unrecognized as saltybox data")
	}
}

package armoredcrypt

import (
	"fmt"
	"encoding/base64"
	"strings"
	"errors"
)

const (
	_MAGIC_PREFIX = "saltybox"
	_V1_MAGIC = "saltybox1:"
)

func Wrap(body []byte) string {
	encoded := base64.RawURLEncoding.EncodeToString(body)

	return fmt.Sprintf("%s%s", _V1_MAGIC, encoded)
}

func Unwrap(varmoredBody string) ([]byte, error) {
	if len(varmoredBody) < len(_V1_MAGIC) {
		return nil, errors.New("input size smaller than magic marker; likely truncated")
	}

	if strings.HasPrefix(varmoredBody, _V1_MAGIC) {
		armoredBody := strings.TrimPrefix(varmoredBody, _V1_MAGIC)
		body, err := base64.RawURLEncoding.DecodeString(armoredBody)
		if err != nil {
			return nil, fmt.Errorf("base64 decoding failed: %s", err)
		}

		return body, nil
	} else if strings.HasPrefix(varmoredBody, _MAGIC_PREFIX) {
		return nil, errors.New("input claims to be saltybox, but not a version we support")
	} else {
		return nil, errors.New("input unrecognized as saltybox data")
	}
}

Use errors.New() instead of fmt.Errorf() where appropriate.


package lib

import (
	"github.com/BytemarkHosting/bytemark-client/lib/brain"
	"strconv"
)

// CreateBackupSchedule creates a new backup schedule starting at the given date, with backups occuring every interval seconds
func (c *bytemarkClient) CreateBackupSchedule(server VirtualMachineName, discLabel string, startDate string, interval int) (sched brain.BackupSchedule, err error) {
	r, err := c.BuildRequest("POST", BrainEndpoint, "/accounts/%s/groups/%s/virtual_machines/%s/discs/%s/backup_schedules", server.Account, server.Group, server.VirtualMachine, discLabel)
	if err != nil {
		return
	}
	inputSchedule := brain.BackupSchedule{
		StartDate: startDate,
		Interval:  interval,
	}
	_, _, err = r.MarshalAndRun(inputSchedule, &sched)
	return
}

// DeleteBackupSchedule deletes the given backup schedule
func (c *bytemarkClient) DeleteBackupSchedule(server VirtualMachineName, discLabel string, id int) (err error) {
	r, err := c.BuildRequest("DELETE", BrainEndpoint, "/accounts/%s/groups/%s/virtual_machines/%s/discs/%s/backup_schedules/%s", server.Account, server.Group, server.VirtualMachine, discLabel, strconv.Itoa(id))
	if err != nil {
		return
	}
	_, _, err = r.Run(nil, nil)
	return
}

package lib

import (
	"github.com/BytemarkHosting/bytemark-client/lib/brain"
	"strconv"
)

// CreateBackupSchedule creates a new backup schedule starting at the given date, with backups occuring every interval seconds
func (c *bytemarkClient) CreateBackupSchedule(server VirtualMachineName, discLabel string, startDate string, interval int) (sched brain.BackupSchedule, err error) {
	err = c.validateVirtualMachineName(&server)
	if err != nil {
		return
	}
	r, err := c.BuildRequest("POST", BrainEndpoint, "/accounts/%s/groups/%s/virtual_machines/%s/discs/%s/backup_schedules", server.Account, server.Group, server.VirtualMachine, discLabel)
	if err != nil {
		return
	}
	inputSchedule := brain.BackupSchedule{
		StartDate: startDate,
		Interval:  interval,
	}
	_, _, err = r.MarshalAndRun(inputSchedule, &sched)
	return
}

// DeleteBackupSchedule deletes the given backup schedule
func (c *bytemarkClient) DeleteBackupSchedule(server VirtualMachineName, discLabel string, id int) (err error) {
	err = c.validateVirtualMachineName(&server)
	if err != nil {
		return
	}
	r, err := c.BuildRequest("DELETE", BrainEndpoint, "/accounts/%s/groups/%s/virtual_machines/%s/discs/%s/backup_schedules/%s", server.Account, server.Group, server.VirtualMachine, discLabel, strconv.Itoa(id))
	if err != nil {
		return
	}
	_, _, err = r.Run(nil, nil)
	return
}

Fix ScheduleBackups and UnscheduleBackups not defaulting correctly


package blob

import (
	"bytes"
	"compress/gzip"
	"io"
	"log"
	"net/http"
)

const (
	TemplateFiles = "templates"
	StaticFiles   = "static"
)

func GetFile(bucket string, name string) ([]byte, error) {
	reader := bytes.NewReader(files[bucket][name])
	gz, err := gzip.NewReader(reader)
	if err != nil {
		return nil, err
	}

	var b bytes.Buffer
	io.Copy(&b, gz)
	gz.Close()

	return b.Bytes(), nil
}

type Handler struct{}

func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	name := r.URL.String()
	if name == "" {
		name = "index.html"
	}

	file, err := GetFile(StaticFiles, name)
	if err != nil {
		if err != io.EOF {
			log.Printf("Could not get file: %s", err)
		}
		w.WriteHeader(http.StatusNotFound)
		return
	}
	w.Header().Set("Content-Type", http.DetectContentType(file))
	w.Write(file)
}

package blob

import (
	"bytes"
	"compress/gzip"
	"io"
	"log"
	"net/http"
	"strings"
)

const (
	TemplateFiles = "templates"
	StaticFiles   = "static"
)

var mimeMap = map[string]string{
	"css": "text/css",
	"js":  "text/javascript",
}

func GetFile(bucket string, name string) ([]byte, error) {
	reader := bytes.NewReader(files[bucket][name])
	gz, err := gzip.NewReader(reader)
	if err != nil {
		return nil, err
	}

	var b bytes.Buffer
	io.Copy(&b, gz)
	gz.Close()

	return b.Bytes(), nil
}

type Handler struct{}

func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	name := r.URL.String()
	if name == "" {
		name = "index.html"
	}

	file, err := GetFile(StaticFiles, name)
	if err != nil {
		if err != io.EOF {
			log.Printf("Could not get file: %s", err)
		}
		w.WriteHeader(http.StatusNotFound)
		return
	}
	contentType := http.DetectContentType(file)
	if strings.Contains(contentType, "text/plain") || strings.Contains(contentType, "application/octet-stream") {
		parts := strings.Split(name, ".")
		contentType = mimeMap[parts[len(parts)-1]]
	}
	w.Header().Set("Content-Type", contentType)
	w.Write(file)
}

Use filename based type if DetectContentType fails.


package main

import (
	"regexp"
	"strconv"
	"strings"
)

var (
	sequenses = regexp.MustCompile(`(?:[^~\\]|\\.)*`)
	branches  = regexp.MustCompile(`(?:[^,\\]|\\.)*`)
)

func newMatcher(expr string) (m *regexp.Regexp, err error) {
	expr = strings.Replace(expr, `\,`, `\\,`, -1)
	expr = strings.Replace(expr, `\~`, `\\~`, -1)
	expr, err = strconv.Unquote(`"` + expr + `"`)
	if err != nil {
		return nil, err
	}

	sls := sequenses.FindAllString(expr, -1)
	for si := 0; si < len(sls); si++ {
		bls := branches.FindAllString(sls[si], -1)
		for bi := 0; bi < len(bls); bi++ {
			bls[bi] = strings.Replace(bls[bi], `\,`, `,`, -1)
			bls[bi] = strings.Replace(bls[bi], `\~`, `~`, -1)
			bls[bi] = regexp.QuoteMeta(bls[bi])
		}
		sls[si] = "(" + strings.Join(bls, "|") + ")"
	}
	return regexp.Compile(strings.Join(sls, ""))
}

package main

import (
	"regexp"
	"strconv"
	"strings"
)

var (
	sequenses = regexp.MustCompile(`(?:[^/\\]|\\.)*`)
	branches  = regexp.MustCompile(`(?:[^,\\]|\\.)*`)
)

func newMatcher(expr string) (m *regexp.Regexp, err error) {
	expr = strings.Replace(expr, `\,`, `\\,`, -1)
	expr = strings.Replace(expr, `\/`, `\\/`, -1)
	expr, err = strconv.Unquote(`"` + expr + `"`)
	if err != nil {
		return nil, err
	}

	sls := sequenses.FindAllString(expr, -1)
	for si := 0; si < len(sls); si++ {
		bls := branches.FindAllString(sls[si], -1)
		for bi := 0; bi < len(bls); bi++ {
			bls[bi] = strings.Replace(bls[bi], `\,`, `,`, -1)
			bls[bi] = strings.Replace(bls[bi], `\/`, `/`, -1)
			bls[bi] = regexp.QuoteMeta(bls[bi])
		}
		sls[si] = "(" + strings.Join(bls, "|") + ")"
	}
	return regexp.Compile(strings.Join(sls, ""))
}

Change separator of sequense from tilda to slash


package module3rd

import (
	"encoding/json"
	"fmt"
	"os"

	"github.com/cubicdaiya/nginx-build/util"
)

func Load(path string) ([]Module3rd, error) {
	var modules []Module3rd
	if len(path) > 0 {
		if !util.FileExists(path) {
			return modules, fmt.Errorf("modulesConfPath(%s) does not exist.", path)
		}
		data, err := os.ReadFile(path)
		if err != nil {
			return modules, err
		}
		if err := json.Unmarshal(data, &modules); err != nil {
			return modules, err
		}
		for i, _ := range modules {
			if modules[i].Form == "" {
				modules[i].Form = "git"
			}
		}
	}
	return modules, nil
}

package module3rd

import (
	"encoding/json"
	"fmt"
	"os"

	"github.com/cubicdaiya/nginx-build/util"
)

func Load(path string) ([]Module3rd, error) {
	var modules []Module3rd
	if len(path) > 0 {
		if !util.FileExists(path) {
			return modules, fmt.Errorf("modulesConfPath(%s) does not exist.", path)
		}
		data, err := os.ReadFile(path)
		if err != nil {
			return modules, err
		}
		if err := json.Unmarshal(data, &modules); err != nil {
			return modules, fmt.Errorf("modulesConfPath(%s) is invalid JSON.", path)
		}
		for i, _ := range modules {
			if modules[i].Form == "" {
				modules[i].Form = "git"
			}
		}
	}
	return modules, nil
}

Add more contextual information to error message