<commit_before>package main

import (
	"bufio"
	"flag"
	"log"
	"os"
	"regexp"
	"strings"
) //import

type CssRule struct {
	Rule  string
	Value string
} //struct

// Global variables
var (
	I_FILENAME string
	O_FILENAME string
) //var

func init() {
	// Retrieve flags & set globals
	flag.StringVar(&I_FILENAME, "ifile", "", "Unable to set I_FILENAME flag variable.")
	flag.StringVar(&O_FILENAME, "ofile", "", "Unable to set O_FILENAME flag variable.")
	flag.Parse()

	if I_FILENAME == "" {
		log.Fatalln("ifile parameter must be specificed.")
	} //if
} //init

func main() {
	var (
		err           error
		cssToAdd      string
		lines         []string
		allCssRules   = make(map[string][]CssRule)
		findInlineCSS = regexp.MustCompile("<(\\w+)\\s(.*?)style=\"([\\w\\-]+):([\\w]+);\"")
		findClasses   = regexp.MustCompile("class=\"(.*?)\"")
	) //var

	// Extract each line of the file
	if lines, err = readFile(I_FILENAME); err != nil {
		log.Fatalln(err)
	} //if
	ctr := 0
	for _, line := range lines {
		if ctr == 28 {
			// Determine if
			if allCssRules = extractInlineCSS(line, findInlineCSS, findClasses); err != nil {
				log.Println(err)
			} //if
		} //if

		ctr++
	} //for

	for element, rules := range allCssRules {
		log.Println(element)
		log.Println(rules)
		log.Println("")

		cssToAdd += element + "{"

		for _, val := range rules {
			cssToAdd += "\n\t" + val.Rule + ":\t" + val.Value
		} //for

		cssToAdd += "\n}\n"
	} //for

	log.Println("CSS to add:")
	log.Println(cssToAdd)

	if err = createCssFile(O_FILENAME, cssToAdd); err != nil {

	} //if
} //main

func extractInlineCSS(line string, findInlineCSS, findClasses *regexp.Regexp) (cssRules map[string][]CssRule) {
	//log.Println(line)
	cssRules = make(map[string][]CssRule)
	styles := findInlineCSS.FindAllStringSubmatch(line, -1)

	for _, v := range styles {
		var tag string

		for pos, _ := range v {
			// First position is entire capture
			if pos != 0 {
				// Second position is tag name
				if pos == 1 {
					tag = strings.TrimSpace(v[pos])
				} else if pos == 2 {
					log.Println(v[pos])
					classes := findClasses.FindAllStringSubmatch(v[pos], -1)

					for _, allClasses := range classes {
						for pos2, classes2 := range allClasses {
							if pos2 != 0 {
								var origTag string

								origTag = tag
								tag = ""

								eachClass := strings.Split(classes2, " ")

								for _, class := range eachClass {
									tag += " " + origTag + "." + class
								} //for
							} //for
						} //if
					} //for
				} else if pos%2 != 0 {
					// Odd positions are rules
					// Even positions are values
					cssRules[tag] = append(cssRules[tag],
						CssRule{
							Rule:  strings.TrimSpace(v[pos]),
							Value: strings.TrimSpace(v[pos+1]),
						}) //append
				} //elseif
			} //if
		} //for
	} //for

	return cssRules
} //extractInlineCSS

func readFile(filename string) (lines []string, err error) {
	var (
		iFile   *os.File
		scanner *bufio.Scanner
	) //var

	// Attempt to open the file
	if iFile, err = os.Open(I_FILENAME); err != nil {
		return lines, err
	} //if
	defer iFile.Close()

	scanner = bufio.NewScanner(iFile)

	// Read in each line of file
	for scanner.Scan() {
		lines = append(lines, scanner.Text())
	} //for

	return lines, scanner.Err()
} //readFile

func createCssFile(filename, css string) (err error) {
	var (
		oFile *os.File
	) //var

	// Attempt to create the file
	if oFile, err = os.Create(filename); err != nil {
		return err
	} //if
	defer oFile.Close()

	if _, err = oFile.Write([]byte(strings.TrimSpace(css))); err != nil {
		return err
	} //if

	return nil
} //writeCssFile

func addCssToHead(filename string) (err error) {

	return err
} //addCssToHead

func removeStyleTags(filename string) (err error) {

	return err
} //removeStyleTags
<commit_msg>Successfully parsing inline CSS.  Need to pull out IDs as well as auto-generate IDs for general rules like img tags<commit_after>package main

import (
	"bufio"
	"flag"
	"log"
	"os"
	"regexp"
	"strings"
) //import

type CssRule struct {
	Rule  string
	Value string
} //struct

// Global variables
var (
	I_FILENAME string
	O_FILENAME string
) //var

func init() {
	// Retrieve flags & set globals
	flag.StringVar(&I_FILENAME, "ifile", "", "Unable to set I_FILENAME flag variable.")
	flag.StringVar(&O_FILENAME, "ofile", "", "Unable to set O_FILENAME flag variable.")
	flag.Parse()

	if I_FILENAME == "" {
		log.Fatalln("ifile parameter must be specificed.")
	} //if

	if O_FILENAME == "" {
		log.Fatalln("ofile parameter must be specificed.")
	} //if
} //init

func main() {
	var (
		err         error
		cssToAdd    string
		lines       []string
		allCssRules = make(map[string][]CssRule)
		//findInlineCSS    = regexp.MustCompile("<(\\w+)\\s(.*?)style=\"([\\w\\-]+):\\s*([\\w]+);\"")
		findInlineCSS    = regexp.MustCompile("<(\\w+)\\s(.*?)style=\"(.*?)\"")
		findClasses      = regexp.MustCompile("class=\"(.*?)\"")
		replaceStyleTags = regexp.MustCompile("(.*?)style=\".*?\"(.*)")
	) //var

	// Extract each line of the file
	if lines, err = readFile(I_FILENAME); err != nil {
		log.Fatalln(err)
	} //if

	for _, line := range lines {
		temp := extractInlineCSS(line, findInlineCSS, findClasses)

		for k, v := range temp {
			if _, isSet := allCssRules[k]; isSet {
				allCssRules[k] = append(allCssRules[k], v...)
			} else {
				allCssRules[k] = v
			} //else
		} //for
	} //for

	for element, rules := range allCssRules {
		log.Println(element)
		log.Println(rules)
		log.Println("")

		cssToAdd += element + "{"

		for _, val := range rules {
			cssToAdd += "\n\t" + val.Rule + ":\t" + val.Value
		} //for

		cssToAdd += "\n}\n"
	} //for

	log.Println("CSS to add:")
	log.Println(cssToAdd)

	if err = createCssFile(O_FILENAME, cssToAdd); err != nil {
		log.Fatalln(err)
	} //if

	if err = removeStyleTags(I_FILENAME, lines, replaceStyleTags); err != nil {
		log.Fatalln(err)
	} //if
} //main

func extractInlineCSS(line string, findInlineCSS, findClasses *regexp.Regexp) (cssRules map[string][]CssRule) {
	cssRules = make(map[string][]CssRule)
	styles := findInlineCSS.FindAllStringSubmatch(line, -1)

	for _, v := range styles {
		var tag string

		for pos, _ := range v {
			// First position is entire capture
			if pos != 0 {
				// Second position is tag name
				if pos == 1 {
					tag = strings.TrimSpace(v[pos])
				} else if pos == 2 {
					classes := findClasses.FindAllStringSubmatch(v[pos], -1)

					for _, allClasses := range classes {
						for pos2, classes2 := range allClasses {
							if pos2 != 0 {
								var origTag string

								origTag = tag
								tag = ""

								eachClass := strings.Split(classes2, " ")

								for _, class := range eachClass {
									tag += " " + origTag + "." + class
								} //for
							} //for
						} //if
					} //for
				} else { // pos = 4 is the style tag
					var (
						items []string
					) //var

					items = strings.Split(v[pos], ";")

					for _, item := range items {
						if len(item) > 0 {
							log.Println("item:", item)

							rule := strings.Split(item, ":")
							log.Println("rule: ", rule)

							rule[0] = strings.TrimSpace(rule[0])
							rule[1] = strings.TrimSpace(rule[1])

							if rule[1][len(rule[1])-1:] != ";" {
								rule[1] += ";"
							} //if

							cssRules[tag] = append(cssRules[tag],
								CssRule{
									Rule:  rule[0],
									Value: rule[1],
								}) //append
						} //if
					} //for
				} //elseif
			} //if
		} //for
	} //for

	return cssRules
} //extractInlineCSS

func readFile(filename string) (lines []string, err error) {
	var (
		iFile   *os.File
		scanner *bufio.Scanner
	) //var

	// Attempt to open the file
	if iFile, err = os.Open(I_FILENAME); err != nil {
		return lines, err
	} //if
	defer iFile.Close()

	scanner = bufio.NewScanner(iFile)

	// Read in each line of file
	for scanner.Scan() {
		lines = append(lines, scanner.Text())
	} //for

	return lines, scanner.Err()
} //readFile

func createCssFile(filename, css string) (err error) {
	var (
		oFile *os.File
	) //var

	// Attempt to create the file
	if oFile, err = os.OpenFile(filename, os.O_CREATE|os.O_RDWR, 0660); err != nil {
		return err
	} //if
	defer oFile.Close()

	if _, err = oFile.Write([]byte(strings.TrimSpace(css))); err != nil {
		return err
	} //if

	return nil
} //writeCssFile

func removeStyleTags(filename string, lines []string, replaceStyleTags *regexp.Regexp) (err error) {
	var (
		oFile *os.File
	) //var

	log.Println("Output:", filename+"_backup")

	// Attempt to create the file
	if oFile, err = os.OpenFile(filename+"_backup", os.O_CREATE|os.O_RDWR|os.O_APPEND, 0660); err != nil {
		return err
	} //if
	defer oFile.Close()

	for _, line := range lines {
		styles := replaceStyleTags.FindAllStringSubmatch(line, -1)

		for _, v := range styles {
			for _, w := range v {
				line = w
			} //for
		} //for

		log.Println("LINE:", line)

		if len(line) > 1 {
			if line[len(line)-2:len(line)-1] != ">" {
				line += ">"
			} //if
		} //if

		if _, err = oFile.Write([]byte(strings.TrimSpace(line) + "\n")); err != nil {
			return err
		} //if
	} //for

	return err
} //removeStyleTags
<|endoftext|>


<commit_before>// Copyright 2015 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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.

// cputime runs its arguments as a command, then prints CPU usage information
// to stderr. It is like the shell builtin 'time' command, except with stable
// formatting that includes a total across user and system CPU time.
package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"syscall"
	"time"
)

func formatBytes(count int64) string {
	switch {
	case count < 1<<10:
		return fmt.Sprintf("%d bytes", count)

	case count < 1<<20:
		return fmt.Sprintf("%.2f KiB", float64(count)/(1<<10))

	case count < 1<<30:
		return fmt.Sprintf("%.2f MiB", float64(count)/(1<<20))

	default:
		fallthrough

	case count < 1<<40:
		return fmt.Sprintf("%.2f GiB", float64(count)/(1<<30))
	}
}

func main() {
	// Set up flags.
	flag.Usage = func() {
		fmt.Fprintf(
			os.Stderr,
			"Usage: %s [flags...] command [args...]\n",
			os.Args[0])

		fmt.Fprintf(os.Stderr, "\n")
		fmt.Fprintf(os.Stderr, "Flags:\n")
		flag.PrintDefaults()
	}

	flag.Parse()

	// Check usage.
	if flag.NArg() < 1 {
		flag.Usage()
		os.Exit(1)
	}

	// Run the command.
	args := flag.Args()

	cmd := exec.Command(args[0], args[1:]...)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	start := time.Now()
	err := cmd.Run()
	duration := time.Since(start)
	if err != nil {
		log.Fatalf("Run: %v", err)
		return
	}

	// Print usage info.
	rusage := cmd.ProcessState.SysUsage().(*syscall.Rusage)
	user := time.Duration(rusage.Utime.Nano()) * time.Nanosecond
	sys := time.Duration(rusage.Stime.Nano()) * time.Nanosecond

	fmt.Fprintf(
		os.Stderr,
		"\n"+
			"----------\n"+
			"Max RSS:   %v\n"+
			"Wall time: %v\n"+
			"\n"+
			"User  CPU: %v\n"+
			"Sys   CPU: %v\n"+
			"Total CPU: %v\n",
		formatBytes(rusage.Maxrss*1024),
		duration,
		user,
		sys,
		user+sys)
}
<commit_msg>Fixed max RSS reporting on OS X.<commit_after>// Copyright 2015 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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.

// cputime runs its arguments as a command, then prints CPU usage information
// to stderr. It is like the shell builtin 'time' command, except with stable
// formatting that includes a total across user and system CPU time.
package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"runtime"
	"syscall"
	"time"
)

func formatBytes(count int64) string {
	switch {
	case count < 1<<10:
		return fmt.Sprintf("%d bytes", count)

	case count < 1<<20:
		return fmt.Sprintf("%.2f KiB", float64(count)/(1<<10))

	case count < 1<<30:
		return fmt.Sprintf("%.2f MiB", float64(count)/(1<<20))

	default:
		fallthrough

	case count < 1<<40:
		return fmt.Sprintf("%.2f GiB", float64(count)/(1<<30))
	}
}

func main() {
	// Set up flags.
	flag.Usage = func() {
		fmt.Fprintf(
			os.Stderr,
			"Usage: %s [flags...] command [args...]\n",
			os.Args[0])

		fmt.Fprintf(os.Stderr, "\n")
		fmt.Fprintf(os.Stderr, "Flags:\n")
		flag.PrintDefaults()
	}

	flag.Parse()

	// Check usage.
	if flag.NArg() < 1 {
		flag.Usage()
		os.Exit(1)
	}

	// Run the command.
	args := flag.Args()

	cmd := exec.Command(args[0], args[1:]...)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	start := time.Now()
	err := cmd.Run()
	duration := time.Since(start)
	if err != nil {
		log.Fatalf("Run: %v", err)
		return
	}

	// Print usage info.
	rusage := cmd.ProcessState.SysUsage().(*syscall.Rusage)
	user := time.Duration(rusage.Utime.Nano()) * time.Nanosecond
	sys := time.Duration(rusage.Stime.Nano()) * time.Nanosecond

	maxRSS := rusage.Maxrss
	if runtime.GOOS == "linux" {
		// Linux uses KiB for this.
		maxRSS *= 1024
	}

	fmt.Fprintf(
		os.Stderr,
		"\n"+
			"----------\n"+
			"Max RSS:   %v\n"+
			"Wall time: %v\n"+
			"\n"+
			"User  CPU: %v\n"+
			"Sys   CPU: %v\n"+
			"Total CPU: %v\n",
		formatBytes(maxRSS),
		duration,
		user,
		sys,
		user+sys)
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"syscall"
)

func main() {

	// read yaml
	fmt.Println("[Reading .estafette.yaml file]")
	data, err := ioutil.ReadFile(".estafette.yaml")
	if err != nil {
		log.Fatal(err)
	}
	var estafetteManifest estafetteManifest
	if err := estafetteManifest.UnmarshalYAML(data); err != nil {
		log.Fatal(err)
	}

	fmt.Println("[Read .estafette.yaml file successfully]")

	// get current working directory
	dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
	if err != nil {
		log.Fatal(err)
	}

	for n, p := range estafetteManifest.Pipelines {

		fmt.Printf("[Starting pipeline %v]\n", n)

		// set default for shell path or override if set in yaml file
		shellPath := "/bin/bash"
		if p.Shell != "" {
			shellPath = p.Shell
		}

		// run docker with image and steps from yaml
		cmd := exec.Command("docker", "run", "--rm", "--entrypoint", "", "-v", fmt.Sprintf("%v:/estafette", dir), "-w", "/estafette", p.ContainerImage, shellPath, "-c", strings.Join(p.Commands, ";"))
		stdout, err := cmd.StdoutPipe()
		if err != nil {
			log.Fatal(err)
		}
		stderr, err := cmd.StderrPipe()
		if err != nil {
			log.Fatal(err)
		}
		if err := cmd.Start(); err != nil {
			log.Fatal(err)
		}

		// read command's stdout and stderr line by line
		multi := io.MultiReader(stdout, stderr)

		in := bufio.NewScanner(multi)

		for in.Scan() {
			log.Printf(in.Text()) // write each line to your log, or anything you need
		}
		if err := in.Err(); err != nil {
			log.Printf("error: %s", err)
		}

		if err := cmd.Wait(); err != nil {
			if exiterr, ok := err.(*exec.ExitError); ok {
				// The program has exited with an exit code != 0

				// This works on both Unix and Windows. Although package
				// syscall is generally platform dependent, WaitStatus is
				// defined for both Unix and Windows and in both cases has
				// an ExitStatus() method with the same signature.
				if status, ok := exiterr.Sys().(syscall.WaitStatus); ok && status.ExitStatus() > 0 {
					os.Exit(status.ExitStatus())
				}
			} else {
				log.Fatal(err)
			}
		}

		fmt.Printf("[Finished pipeline %v successfully]\n", n)
		os.Exit(0)
	}
}
<commit_msg>print docker command<commit_after>package main

import (
	"bufio"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"syscall"
)

func main() {

	// read yaml
	fmt.Println("[Reading .estafette.yaml file]")
	data, err := ioutil.ReadFile(".estafette.yaml")
	if err != nil {
		log.Fatal(err)
	}
	var estafetteManifest estafetteManifest
	if err := estafetteManifest.UnmarshalYAML(data); err != nil {
		log.Fatal(err)
	}

	fmt.Println("[Read .estafette.yaml file successfully]")

	// get current working directory
	dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
	if err != nil {
		log.Fatal(err)
	}

	for n, p := range estafetteManifest.Pipelines {

		fmt.Printf("[Starting pipeline %v]\n", n)

		// set default for shell path or override if set in yaml file
		shellPath := "/bin/bash"
		if p.Shell != "" {
			shellPath = p.Shell
		}

		// run docker with image and steps from yaml
		fmt.Printf("[Running command 'docker run --rm --entrypoint \"\" -v %v:/estafette -w /estafette %v %v -c %v']\n", dir, p.ContainerImage, shellPath, strings.Join(p.Commands, ";"))
		cmd := exec.Command("docker", "run", "--rm", "--entrypoint", "", "-v", fmt.Sprintf("%v:/estafette", dir), "-w", "/estafette", p.ContainerImage, shellPath, "-c", strings.Join(p.Commands, ";"))
		stdout, err := cmd.StdoutPipe()
		if err != nil {
			log.Fatal(err)
		}
		stderr, err := cmd.StderrPipe()
		if err != nil {
			log.Fatal(err)
		}
		if err := cmd.Start(); err != nil {
			log.Fatal(err)
		}

		// read command's stdout and stderr line by line
		multi := io.MultiReader(stdout, stderr)

		in := bufio.NewScanner(multi)

		for in.Scan() {
			log.Printf(in.Text()) // write each line to your log, or anything you need
		}
		if err := in.Err(); err != nil {
			log.Printf("error: %s", err)
		}

		if err := cmd.Wait(); err != nil {
			if exiterr, ok := err.(*exec.ExitError); ok {
				// The program has exited with an exit code != 0

				// This works on both Unix and Windows. Although package
				// syscall is generally platform dependent, WaitStatus is
				// defined for both Unix and Windows and in both cases has
				// an ExitStatus() method with the same signature.
				if status, ok := exiterr.Sys().(syscall.WaitStatus); ok && status.ExitStatus() > 0 {
					os.Exit(status.ExitStatus())
				}
			} else {
				log.Fatal(err)
			}
		}

		fmt.Printf("[Finished pipeline %v successfully]\n", n)
		os.Exit(0)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"github.com/ciarand/martini-fileindex"
	"github.com/codegangsta/martini"
	"log"
	"net/http"
	"os"
)

func main() {
	port, location := parseArgs()

	server := New(location)

	server.Logger.Println("listening on 127.0.0.1:" + port)
	server.Logger.Fatal(http.ListenAndServe(":"+port, server))
}

func parseArgs() (port string, loc string) {
	// setup, then parse flags
	flag.StringVar(&port, "port", "3000", "The port to bind to")
	flag.Parse()

	loc = flag.Arg(0)
	if loc == "" {
		loc = "."
	}

	return port, loc
}

type Deserv struct {
	*martini.ClassicMartini
	Logger *log.Logger
}

func New(location string) *Deserv {
	d := &Deserv{martini.Classic(), log.New(os.Stdout, "[deserv] ", 0)}

	d.Handlers(
		martini.Logger(),
		martini.Static(location),
		fileindex.ListFiles(location),
		martini.Recovery(),
	)

	d.Map(d.Logger)

	return d
}
<commit_msg>Add some comments n stuff to main.go<commit_after>package main

import (
	"flag"
	"github.com/ciarand/martini-fileindex"
	"github.com/codegangsta/martini"
	"log"
	"net/http"
	"os"
)

// Begin the madness
func main() {
	// Get the port and location from CLI arguments
	port, location := parseArgs()

	// Create a new server instance, heavily based on the Classic Martini, but
	// with some important differences
	server := New(location)

	// Print the start message
	server.Logger.Println("listening on 127.0.0.1:" + port)
	// If the http.ListenAndServe method fails, log it and bail
	server.Logger.Fatal(http.ListenAndServe(":"+port, server))
}

// Parse the CLI arguments and grab the port and location from them
func parseArgs() (port string, loc string) {
	// setup the flags
	flag.StringVar(&port, "port", "3000", "The port to bind to")
	// Parse the args array for the flags
	flag.Parse()

	// Location is the first non-flag argument after parsing
	loc = flag.Arg(0)
	// If we didn't get a location, set it to the current dir
	if loc == "" {
		loc = "."
	}

	// Return the port and location
	return port, loc
}

// A parent structure that "extends" the Classic Martini and also provides
// access to the Logger used
type Deserv struct {
	*martini.ClassicMartini
	Logger *log.Logger
}

// Create a new "Deserv" struct and init it
func New(location string) *Deserv {
	// It starts out as just a Classic Martini and a custom logger
	d := &Deserv{martini.Classic(), log.New(os.Stdout, "[deserv] ", 0)}

	// Setup the handlers (middlewars) used in Deserv
	d.Handlers(
		// We want a logger
		martini.Logger(),
		// And to serve static files from the location
		martini.Static(location),
		// And we want a file index when the URI is a dir
		fileindex.ListFiles(location),
		// Finally if anything goes wrong we want it to recover
		martini.Recovery(),
	)

	// Map the created logger to the log.Logger type. That means that whenever
	// a function requests a log.Logger it'll use ours instead of the normal
	// Martini one
	d.Map(d.Logger)

	// Finally return the struct
	return d
}
<|endoftext|>


<commit_before>// Wago (Watch, Go)
// A general purpose watch / build development tool.

// TODO: catch SIGINT and send dog.TR to ensure a clean term
// see https://askubuntu.com/questions/171449/shell-does-not-show-typed-in-commands-reset-works-but-what-happened

package main

import (
	"flag"
	"fmt"
	"github.com/JonahBraun/dog"
	"github.com/howeyc/fsnotify"
	"net/http"
	"os"
	"path/filepath"
	"regexp"
	"runtime"
	"sync"
)

var (
	log     = dog.NewDog(dog.DEBUG)
	verbose = flag.Bool("v", false, "Verbose")
	quiet   = flag.Bool("q", false, "Quiet, only warnings and errors")

	buildCmd      = flag.String("cmd", "", "Bash command to run on change, Wabo will wait for this command to finish")
	daemonCmd     = flag.String("daemon", "", "Bash command that starts a daemon, Wago will halt if the daemon exits before the trigger or timer")
	daemonTimer   = flag.Int("timer", 0, "Miliseconds to wait after starting daemon before continuing")
	daemonTrigger = flag.String("trigger", "", "A string the daemon will output that indicates it has started successfuly, Wago will continue on this trigger")
	exitWait      = flag.Int("exitwait", 0, "If 0, kills processes immediately, if >0, sends SIGINT and waits X ms for process to exit before killing")
	fiddle        = flag.Bool("fiddle", false, "CLI fiddle mode, starts a web server and opens url to targetDir/index.html")
	leader        = flag.String("leader", "", "Leader character for wago output (to differentiate from command output), defaults to emoji")
	postCmd       = flag.String("pcmd", "", "Bash command to run after the daemon has successfully started, use this to kick off your test suite")
	recursive     = flag.Bool("recursive", true, "Watch directory tree recursively")
	targetDir     = flag.String("dir", "", "Directory to watch, defaults to current")
	url           = flag.String("url", "", "URL to open")
	watchRegex    = flag.String("watch", `/\w[\w\.]*": (CREATE|MODIFY)`, "Regex to match watch event, use -v to see all events")
	webServer     = flag.String("web", "", "Start a web server at this address, e.g. :8420")
	shell         = flag.String("shell", "", "Shell used to run commands, defaults to $SHELL, fallback to /bin/sh")
)

type Watcher struct {
	Event chan fmt.Stringer
	Error chan error
}

func main() {
	// the following function calls merely serve to logically organize what
	// is otherwise a VERY lengthy setup

	// TODO: have configSetup return a config object so that the reliance on
	// config globals is removed
	configSetup()

	startWebServer()

	runChain(newWatcher(), make(chan struct{}))
}

func runChain(watcher *Watcher, quit chan struct{}) {
	chain := make([]Runnable, 0, 5)

	// build chain of runnables
	if len(*buildCmd) > 0 {
		chain = append(chain, NewRunWait(*buildCmd))
	}
	if len(*daemonCmd) > 0 {
		if len(*daemonTrigger) > 0 {
			chain = append(chain, NewDaemonTrigger(*daemonCmd, *daemonTrigger))
		} else {
			chain = append(chain, NewDaemonTimer(*daemonCmd, *daemonTimer))
		}
	}
	if len(*postCmd) > 0 {
		chain = append(chain, NewRunWait(*postCmd))
	}
	if *url != "" {
		chain = append(chain, NewBrowser(*url))
	}

	eventRegex, err := regexp.Compile(*watchRegex)
	if err != nil {
		log.Fatal("Watch regex compile error:", err)(1)
	}

	var wg sync.WaitGroup

	// main loop
	for {
		// all channels of struct{} are disposable, single use
		// kill is passed to all Runnable so they know when they should exit
		kill := make(chan struct{})
		// abort is to single the event loop that a Runnable did not succeed so cancel everything
		abort := make(chan struct{})

		var drain func()
		drain = func() {
			select {
			case ev := <-watcher.Event:
				log.Debug("Extra event ignored:", ev.String())
				drain()
			default:
			}
		}
		drain()

		// event loop
		go func() {
			for {
				select {
				case ev := <-watcher.Event:
					if eventRegex.MatchString(ev.String()) {
						log.Info("Matched event:", ev.String())
						close(kill)
						return
					} else {
						log.Debug("Ignored event:", ev.String())
					}
				case err = <-watcher.Error:
					log.Fatal("Watcher error:", err)(5)
				case <-abort:
					close(kill)
					return
				case <-quit:
					// currently only used by test suite
					close(kill)
					return
				}
			}
		}()

	RunLoop:
		for _, runnable := range chain {
			done, dead := runnable(kill)
			wg.Add(1)

			go func() {
				wg.Done()
				<-dead
			}()

			select {
			case d := <-done:
				if !d {
					// Runnable failed it's success metric
					close(abort)
					break RunLoop
				}
			case <-kill:
				break RunLoop
			}
		}

		// ensure an event has occured, we may be here because all runnables completed
		<-kill

		// ensure all runnables (procs) are dead before restarting the chain
		wg.Wait()

		// check if we should quit, currently only used by test suites for teardown
		select {
		case <-quit:
			log.Warn("Quitting run chain")
			return
		default:
		}
	}
}

func newWatcher() *Watcher {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		panic(err)
	}

	watchDir := func(path string, info os.FileInfo, err error) error {
		if !info.IsDir() {
			return nil
		}

		log.Debug("Watching dir:", path)

		if err != nil {
			log.Err("Skipping dir:", path, err)
			return filepath.SkipDir
		}

		err = watcher.Watch(path)
		if err != nil {
			panic(err)
		}

		return nil
	}

	if *recursive == true {
		err = filepath.Walk(*targetDir, watchDir)
		if err != nil {
			panic(err)
		}
	} else {
		err = watcher.Watch(*targetDir)
		if err != nil {
			panic(err)
		}
	}

	// To facilitate testing (which sends artifical events from a timer),
	// we have an abstracted struct Watcher that holds the applicable channels.
	// fsnotify.FileEvent is a fmt.Stringer, but channels cannot be converted.
	// Unfortunately, an extra channel is necessary to perform the conversion.
	event := make(chan fmt.Stringer)
	go func() {
		for {
			event <- <-watcher.Event
		}
	}()

	return &Watcher{event, watcher.Error}
}

func startWebServer() {
	if *webServer != "" {
		go func() {
			log.Info("Starting web server on port", *webServer)
			err := http.ListenAndServe(*webServer, http.FileServer(http.Dir(*targetDir)))
			if err != nil {
				log.Fatal("Error starting web server:", err)(2)
			}
		}()
	}
}

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

	flag.Usage = func() {
		fmt.Println("WaGo (Watch, Go) build tool. Usage:")
		flag.PrintDefaults()
	}

	// TODO: this should check for actions
	if len(os.Args) < 2 {
		flag.Usage()
		log.Fatal("You must specify an action")(1)
	}

	flag.Parse()

	if *verbose {
		log = dog.NewDog(dog.DEBUG)
	} else if *quiet {
		log = dog.NewDog(dog.WARN)
	} else {
		log = dog.NewDog(dog.INFO)
	}

	if len(*shell) == 0 {
		*shell = os.Getenv("SHELL")
		if len(*shell) == 0 {
			*shell = "/bin/sh"
		}
	}
	log.Debug("Using shell", *shell)

	if (len(*daemonTrigger) > 0) && (*daemonTimer > 0) {
		log.Fatal("Both daemon trigger and timer specified, use only one")(1)
	}

	if (len(*daemonTrigger) > 0 || *daemonTimer > 0) && len(*daemonCmd) == 0 {
		log.Fatal("Specify a daemon command to use the trigger or timer")(1)
	}

	if len(*buildCmd) == 0 && len(*daemonCmd) == 0 && !*fiddle && len(*postCmd) == 0 && len(*url) == 0 && len(*webServer) == 0 {
		flag.Usage()
		log.Fatal("You must specify an action")(1)
	}

	if *fiddle {
		if *webServer == "" {
			*webServer = ":9933"
		}
		if *url == "" {
			*url = "http://localhost" + *webServer + "/"
		}
	}

	if *targetDir == "" {
		cwd, err := os.Getwd()
		if err != nil {
			panic(err)
		}
		targetDir = &cwd
	}
	log.Debug("Target dir:", *targetDir)
}
<commit_msg>fix done implementation<commit_after>// Wago (Watch, Go)
// A general purpose watch / build development tool.

// TODO: catch SIGINT and send dog.TR to ensure a clean term
// see https://askubuntu.com/questions/171449/shell-does-not-show-typed-in-commands-reset-works-but-what-happened

package main

import (
	"flag"
	"fmt"
	"github.com/JonahBraun/dog"
	"github.com/howeyc/fsnotify"
	"net/http"
	"os"
	"path/filepath"
	"regexp"
	"runtime"
	"sync"
)

var (
	log     = dog.NewDog(dog.DEBUG)
	verbose = flag.Bool("v", false, "Verbose")
	quiet   = flag.Bool("q", false, "Quiet, only warnings and errors")

	buildCmd      = flag.String("cmd", "", "Bash command to run on change, Wabo will wait for this command to finish")
	daemonCmd     = flag.String("daemon", "", "Bash command that starts a daemon, Wago will halt if the daemon exits before the trigger or timer")
	daemonTimer   = flag.Int("timer", 0, "Miliseconds to wait after starting daemon before continuing")
	daemonTrigger = flag.String("trigger", "", "A string the daemon will output that indicates it has started successfuly, Wago will continue on this trigger")
	exitWait      = flag.Int("exitwait", 0, "If 0, kills processes immediately, if >0, sends SIGINT and waits X ms for process to exit before killing")
	fiddle        = flag.Bool("fiddle", false, "CLI fiddle mode, starts a web server and opens url to targetDir/index.html")
	leader        = flag.String("leader", "", "Leader character for wago output (to differentiate from command output), defaults to emoji")
	postCmd       = flag.String("pcmd", "", "Bash command to run after the daemon has successfully started, use this to kick off your test suite")
	recursive     = flag.Bool("recursive", true, "Watch directory tree recursively")
	targetDir     = flag.String("dir", "", "Directory to watch, defaults to current")
	url           = flag.String("url", "", "URL to open")
	watchRegex    = flag.String("watch", `/\w[\w\.]*": (CREATE|MODIFY)`, "Regex to match watch event, use -v to see all events")
	webServer     = flag.String("web", "", "Start a web server at this address, e.g. :8420")
	shell         = flag.String("shell", "", "Shell used to run commands, defaults to $SHELL, fallback to /bin/sh")
)

type Watcher struct {
	Event chan fmt.Stringer
	Error chan error
}

func main() {
	// the following function calls merely serve to logically organize what
	// is otherwise a VERY lengthy setup

	// TODO: have configSetup return a config object so that the reliance on
	// config globals is removed
	configSetup()

	startWebServer()

	runChain(newWatcher(), make(chan struct{}))
}

func runChain(watcher *Watcher, quit chan struct{}) {
	chain := make([]Runnable, 0, 5)

	// build chain of runnables
	if len(*buildCmd) > 0 {
		chain = append(chain, NewRunWait(*buildCmd))
	}
	if len(*daemonCmd) > 0 {
		if len(*daemonTrigger) > 0 {
			chain = append(chain, NewDaemonTrigger(*daemonCmd, *daemonTrigger))
		} else {
			chain = append(chain, NewDaemonTimer(*daemonCmd, *daemonTimer))
		}
	}
	if len(*postCmd) > 0 {
		chain = append(chain, NewRunWait(*postCmd))
	}
	if *url != "" {
		chain = append(chain, NewBrowser(*url))
	}

	eventRegex, err := regexp.Compile(*watchRegex)
	if err != nil {
		log.Fatal("Watch regex compile error:", err)(1)
	}

	var wg sync.WaitGroup

	// main loop
	for {
		// all channels of struct{} are disposable, single use
		// kill is passed to all Runnable so they know when they should exit
		kill := make(chan struct{})

		var drain func()
		drain = func() {
			select {
			case ev := <-watcher.Event:
				log.Debug("Extra event ignored:", ev.String())
				drain()
			default:
			}
		}
		drain()

		// event loop
		go func() {
			for {
				select {
				case ev := <-watcher.Event:
					if eventRegex.MatchString(ev.String()) {
						log.Info("Matched event:", ev.String())
						close(kill)
						return
					} else {
						log.Debug("Ignored event:", ev.String())
					}
				case err = <-watcher.Error:
					log.Fatal("Watcher error:", err)(5)
				case <-quit:
					// currently only used by test suite
					close(kill)
					return
				}
			}
		}()

	RunLoop:
		for _, runnable := range chain {
			done, dead := runnable(kill)
			wg.Add(1)

			go func() {
				wg.Done()
				<-dead
			}()

			select {
			case d := <-done:
				if !d {
					// Runnable's success metric failed, break out of the chain
					break RunLoop
				}
			case <-kill:
				break RunLoop
			}
		}

		// ensure an event has occured, we may be here because all runnables completed
		<-kill

		// ensure all runnables (procs) are dead before restarting the chain
		wg.Wait()

		// check if we should quit, currently only used by test suites for teardown
		select {
		case <-quit:
			log.Warn("Quitting run chain")
			return
		default:
		}
	}
}

func newWatcher() *Watcher {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		panic(err)
	}

	watchDir := func(path string, info os.FileInfo, err error) error {
		if !info.IsDir() {
			return nil
		}

		log.Debug("Watching dir:", path)

		if err != nil {
			log.Err("Skipping dir:", path, err)
			return filepath.SkipDir
		}

		err = watcher.Watch(path)
		if err != nil {
			panic(err)
		}

		return nil
	}

	if *recursive == true {
		err = filepath.Walk(*targetDir, watchDir)
		if err != nil {
			panic(err)
		}
	} else {
		err = watcher.Watch(*targetDir)
		if err != nil {
			panic(err)
		}
	}

	// To facilitate testing (which sends artifical events from a timer),
	// we have an abstracted struct Watcher that holds the applicable channels.
	// fsnotify.FileEvent is a fmt.Stringer, but channels cannot be converted.
	// Unfortunately, an extra channel is necessary to perform the conversion.
	event := make(chan fmt.Stringer)
	go func() {
		for {
			event <- <-watcher.Event
		}
	}()

	return &Watcher{event, watcher.Error}
}

func startWebServer() {
	if *webServer != "" {
		go func() {
			log.Info("Starting web server on port", *webServer)
			err := http.ListenAndServe(*webServer, http.FileServer(http.Dir(*targetDir)))
			if err != nil {
				log.Fatal("Error starting web server:", err)(2)
			}
		}()
	}
}

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

	flag.Usage = func() {
		fmt.Println("WaGo (Watch, Go) build tool. Usage:")
		flag.PrintDefaults()
	}

	// TODO: this should check for actions
	if len(os.Args) < 2 {
		flag.Usage()
		log.Fatal("You must specify an action")(1)
	}

	flag.Parse()

	if *verbose {
		log = dog.NewDog(dog.DEBUG)
	} else if *quiet {
		log = dog.NewDog(dog.WARN)
	} else {
		log = dog.NewDog(dog.INFO)
	}

	if len(*shell) == 0 {
		*shell = os.Getenv("SHELL")
		if len(*shell) == 0 {
			*shell = "/bin/sh"
		}
	}
	log.Debug("Using shell", *shell)

	if (len(*daemonTrigger) > 0) && (*daemonTimer > 0) {
		log.Fatal("Both daemon trigger and timer specified, use only one")(1)
	}

	if (len(*daemonTrigger) > 0 || *daemonTimer > 0) && len(*daemonCmd) == 0 {
		log.Fatal("Specify a daemon command to use the trigger or timer")(1)
	}

	if len(*buildCmd) == 0 && len(*daemonCmd) == 0 && !*fiddle && len(*postCmd) == 0 && len(*url) == 0 && len(*webServer) == 0 {
		flag.Usage()
		log.Fatal("You must specify an action")(1)
	}

	if *fiddle {
		if *webServer == "" {
			*webServer = ":9933"
		}
		if *url == "" {
			*url = "http://localhost" + *webServer + "/"
		}
	}

	if *targetDir == "" {
		cwd, err := os.Getwd()
		if err != nil {
			panic(err)
		}
		targetDir = &cwd
	}
	log.Debug("Target dir:", *targetDir)
}
<|endoftext|>


<commit_before>/*
 *
 * k6 - a next-generation load testing tool
 * Copyright (C) 2016 Load Impact
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package main

import (
	log "github.com/Sirupsen/logrus"
	"github.com/fatih/color"
	"github.com/mattn/go-isatty"
	"gopkg.in/urfave/cli.v1"
	"os"
)

var isTTY = isatty.IsTerminal(os.Stdout.Fd()) || isatty.IsCygwinTerminal(os.Stdout.Fd())

func main() {
	// This won't be needed in cli v2
	cli.VersionFlag.Name = "version"
	cli.HelpFlag.Name = "help"
	cli.HelpFlag.Hidden = true

	app := cli.NewApp()
	app.Name = "k6"
	app.Usage = "a next generation load generator"
	app.Version = "0.10.0"
	app.Commands = []cli.Command{
		commandRun,
		commandInspect,
		commandStatus,
		commandStats,
		commandScale,
		commandPause,
		commandResume,
	}
	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:  "verbose, v",
			Usage: "show debug messages",
		},
		cli.StringFlag{
			Name:   "address, a",
			Usage:  "address for the API",
			Value:  "127.0.0.1:6565",
			EnvVar: "K6_ADDRESS",
		},
		cli.BoolFlag{
			Name:   "no-color, n",
			Usage:  "disable colored output",
			EnvVar: "K6_NO_COLOR",
		},
	}
	app.Before = func(cc *cli.Context) error {
		if cc.Bool("verbose") {
			log.SetLevel(log.DebugLevel)
		}
		if cc.Bool("no-color") {
			color.NoColor = true
		}

		return nil
	}
	if err := app.Run(os.Args); err != nil {
		os.Exit(1)
	}
}
<commit_msg>v0.11.0<commit_after>/*
 *
 * k6 - a next-generation load testing tool
 * Copyright (C) 2016 Load Impact
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package main

import (
	log "github.com/Sirupsen/logrus"
	"github.com/fatih/color"
	"github.com/mattn/go-isatty"
	"gopkg.in/urfave/cli.v1"
	"os"
)

var isTTY = isatty.IsTerminal(os.Stdout.Fd()) || isatty.IsCygwinTerminal(os.Stdout.Fd())

func main() {
	// This won't be needed in cli v2
	cli.VersionFlag.Name = "version"
	cli.HelpFlag.Name = "help"
	cli.HelpFlag.Hidden = true

	app := cli.NewApp()
	app.Name = "k6"
	app.Usage = "a next generation load generator"
	app.Version = "0.11.0"
	app.Commands = []cli.Command{
		commandRun,
		commandInspect,
		commandStatus,
		commandStats,
		commandScale,
		commandPause,
		commandResume,
	}
	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:  "verbose, v",
			Usage: "show debug messages",
		},
		cli.StringFlag{
			Name:   "address, a",
			Usage:  "address for the API",
			Value:  "127.0.0.1:6565",
			EnvVar: "K6_ADDRESS",
		},
		cli.BoolFlag{
			Name:   "no-color, n",
			Usage:  "disable colored output",
			EnvVar: "K6_NO_COLOR",
		},
	}
	app.Before = func(cc *cli.Context) error {
		if cc.Bool("verbose") {
			log.SetLevel(log.DebugLevel)
		}
		if cc.Bool("no-color") {
			color.NoColor = true
		}

		return nil
	}
	if err := app.Run(os.Args); err != nil {
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

import (
    "bytes"
    "fmt"
    "path/filepath"
    "os"
    "os/exec"
    "os/user"
    "io/ioutil"

    "github.com/drone/drone-plugin-go/plugin"
)

var (
    buildCommit string
)

var netrcFile = `
machine %s
login %s
password %s
`

type Params struct {
    UpstreamName    string            `json:"upstream"`
    PagesDirectory  string            `json:"source"`
    TemporaryBase   string            `json:"temp"`
    TargetBranch    string            `json:"branch"`
}

func main() {
    fmt.Printf("Drone gh-pages deployment plugin built from %s\n", buildCommit)

    v := new(Params)
    r := new(plugin.Repo)
    b := new(plugin.Build)
    w := new(plugin.Workspace)
    plugin.Param("repo", r)
    plugin.Param("build", b)
    plugin.Param("workspace", w)
    plugin.Param("vargs", &v)
    plugin.MustParse()
    err := publishDocs(r, b, w, v)
    if err != nil {
        fmt.Printf("%s\n", err)
        os.Exit(1)
    }
}

func publishDocs(r *plugin.Repo, b *plugin.Build, w *plugin.Workspace, v *Params) error {
    if (v.UpstreamName == "") {
        v.UpstreamName = "origin"
    }
    if (v.TargetBranch == "") {
        v.TargetBranch = "gh-pages"
    }
    if (v.TemporaryBase == "") {
        v.TemporaryBase = ".tmp"
    }
    if (v.PagesDirectory == "") {
        v.PagesDirectory = "docs"
    }

    temporaryBaseDirectory := ""
    if filepath.IsAbs(v.TemporaryBase) {
        temporaryBaseDirectory = v.TemporaryBase
    } else {
        temporaryBaseDirectory = filepath.Join(w.Path, v.TemporaryBase)
    }
    temporaryPagesDirectory := filepath.Join(temporaryBaseDirectory, v.PagesDirectory)

    fullPagesDirectory := filepath.Join(w.Path, v.PagesDirectory)

    // generate the .netrc file
    if err := writeNetrc(w); err != nil {
        fmt.Fprintln(os.Stderr, err)
        return err
    }

    // write the rsa private key if provided
    if err := writeKey(w); err != nil {
        fmt.Fprintln(os.Stderr, err)
        return err
    }

    err := GlobalUser(b)
    if err != nil {
        return err
    }

    err = GlobalName(b)
    if err != nil {
        return err
    }

    err = os.MkdirAll(temporaryPagesDirectory, 0777)
    if err != nil {
        return err
    }
    defer os.RemoveAll(temporaryPagesDirectory)

    err = runPublishSteps(w.Path, temporaryBaseDirectory, temporaryPagesDirectory, fullPagesDirectory, v.TargetBranch, v.UpstreamName, r.Clone)
    if err != nil {
        return err
    }
    return nil
}

func runCommand(cmd *exec.Cmd, out *bytes.Buffer) error {
    if (out == nil) {
        if (cmd.Stdout == nil) {
            cmd.Stdout = os.Stdout
        }
    } else {
        cmd.Stdout = out
    }
    cmd.Stderr = os.Stderr;

    err := cmd.Run()
    if err != nil {
        fmt.Printf("Error: %+v %s\n", cmd, err)
        return err
    }
    return nil
}

func runPublishSteps(
    workspacePath string,
    temporaryBaseDirectory string,
    temporaryPagesDirectory string,
    fullPagesDirectory string,
    vargsTargetBranch string,
    vargsUpstreamName string,
    cloneUrl string) error {

    // Get the commit message
    msgRaw, err := commitMessage(workspacePath).Output()
    if err != nil {
        return err
    }
    msg := fmt.Sprintf("%s", msgRaw)
    fmt.Printf("%s\n", msg)

    // Set up git config (rsa, etc)
    fmt.Printf("about to clone\n");
    err = runCommand(cloneTarget(workspacePath, vargsTargetBranch, cloneUrl, temporaryPagesDirectory), nil);
    if (err != nil) {
        return err
    }

    fmt.Printf("about to rsync\n");
    err = runCommand(rsyncPages(workspacePath, fullPagesDirectory, temporaryBaseDirectory), nil);
    if (err != nil) {
        return err
    }

    fmt.Printf("about to add to clone\n");
    var addResult bytes.Buffer
    err = runCommand(addTemporaryFilesToClone(temporaryPagesDirectory), &addResult);
    if (err != nil) {
        fmt.Printf("Error on add: %s", addResult.String())
        return err
    }

    // For now, if the add resulted in a success, with output, we are assuming that there are
    // changes to commit and push
    if (addResult.Len() > 0) {
        fmt.Printf("about to commit\n");
        err = runCommand(commitTemporaryFilesToClone(temporaryPagesDirectory, msg), nil);
        if (err != nil) {
            return err
        }

        fmt.Printf("about to push\n");
        err = runCommand(pushTemporaryClone(temporaryPagesDirectory, vargsUpstreamName, vargsTargetBranch), nil);
        if (err != nil) {
            return err
        }
    }

    return nil
}

// Returns command to get the commit message for the gh-pages
// commit based on the last commit in the build
func commitMessage(workspacePath string) *exec.Cmd {
    cmd := exec.Command(
        "git",
        "show",
        "-q",
    )
    cmd.Dir = workspacePath
    return cmd
}

// Returns command to clone gh-pages into our temporary location.
// git clone -b gh-pages --single-branch repo .tmp/[pages directory]
func cloneTarget(workspacePath string, targetBranch string, repo string, temporaryPagesDirectory string) *exec.Cmd {
    cmd := exec.Command(
        "git",
        "clone",
        "-b",
        targetBranch,
        "--single-branch",
        repo,
        temporaryPagesDirectory,
    )
    cmd.Dir = workspacePath
    return cmd
}

// Copy the pages content to the temporary location
// rsync --delete --exclude .git -r docs .tmp
func rsyncPages(workspacePath string, pagesDirectory string, temporaryBaseDirectory string) *exec.Cmd {
    cmd := exec.Command(
        "rsync",
        "--delete",
        "--exclude",
        ".git",
        "-r",
        pagesDirectory,
        temporaryBaseDirectory,
    )
    cmd.Dir = workspacePath
    return cmd
}

// Add the files in the temporary directory to the commit
// we want to make in the clone.
func addTemporaryFilesToClone(temporaryPagesDirectory string) *exec.Cmd {
    cmd := exec.Command(
        "git",
        "add",
        "--verbose",
        ".",
    )
    cmd.Dir = temporaryPagesDirectory
    return cmd
}

// Commit the working version of the pages content to
// our clone
func commitTemporaryFilesToClone(temporaryPagesDirectory string, message string) *exec.Cmd {
    cmd := exec.Command(
        "git",
        "commit",
        "-m",
        message,
    )
    cmd.Dir = temporaryPagesDirectory
    return cmd
}

// Push our clone to the upstream
func pushTemporaryClone(temporaryPagesDirectory string, upstreamName string, targetBranch string) *exec.Cmd {
    cmd := exec.Command(
        "git",
        "push",
        upstreamName,
        targetBranch,
    )
    cmd.Dir = temporaryPagesDirectory
    return cmd
}

// Writes the netrc file.
func writeNetrc(in *plugin.Workspace) error {
    if in.Netrc == nil || len(in.Netrc.Machine) == 0 {
        return nil
    }
    out := fmt.Sprintf(
        netrcFile,
        in.Netrc.Machine,
        in.Netrc.Login,
        in.Netrc.Password,
    )
    home := "/root"
    u, err := user.Current()
    if err == nil {
        home = u.HomeDir
    }
    path := filepath.Join(home, ".netrc")
    return ioutil.WriteFile(path, []byte(out), 0600)
}

// Writes the RSA private key
func writeKey(in *plugin.Workspace) error {
    if in.Keys == nil || len(in.Keys.Private) == 0 {
        return nil
    }
    home := "/root"
    u, err := user.Current()
    if err == nil {
        home = u.HomeDir
    }
    sshpath := filepath.Join(home, ".ssh")
    if err := os.MkdirAll(sshpath, 0700); err != nil {
        return err
    }
    confpath := filepath.Join(sshpath, "config")
    privpath := filepath.Join(sshpath, "id_rsa")
    ioutil.WriteFile(confpath, []byte("StrictHostKeyChecking no\n"), 0700)
    return ioutil.WriteFile(privpath, []byte(in.Keys.Private), 0600)
}

func GlobalUser(build *plugin.Build) error {
    cmd := exec.Command(
        "git",
        "config",
        "--global",
        "user.email",
        build.Email)
    return cmd.Run()
}

func GlobalName(build *plugin.Build) error {
    cmd := exec.Command(
        "git",
        "config",
        "--global",
        "user.name",
        build.Author)
    return cmd.Run()
}
<commit_msg>Use drone-git-push/repo's version of functions<commit_after>package main

import (
    "bytes"
    "fmt"
    "path/filepath"
    "os"
    "os/exec"
    "os/user"
    "io/ioutil"

    "github.com/drone/drone-plugin-go/plugin"
    "github.com/drone/drone-go/drone"
    "github.com/drone-plugins/drone-git-push/repo"
)

var (
    buildCommit string
)

var netrcFile = `
machine %s
login %s
password %s
`

type Params struct {
    UpstreamName    string            `json:"upstream"`
    PagesDirectory  string            `json:"source"`
    TemporaryBase   string            `json:"temp"`
    TargetBranch    string            `json:"branch"`
}

func main() {
    fmt.Printf("Drone gh-pages deployment plugin built from %s\n", buildCommit)

    v := new(Params)
    r := new(drone.Repo)
    b := new(drone.Build)
    w := new(drone.Workspace)
    plugin.Param("repo", r)
    plugin.Param("build", b)
    plugin.Param("workspace", w)
    plugin.Param("vargs", &v)
    plugin.MustParse()
    err := publishDocs(r, b, w, v)
    if err != nil {
        fmt.Printf("%s\n", err)
        os.Exit(1)
    }
}

func publishDocs(r *drone.Repo, b *drone.Build, w *drone.Workspace, v *Params) error {
    if (v.UpstreamName == "") {
        v.UpstreamName = "origin"
    }
    if (v.TargetBranch == "") {
        v.TargetBranch = "gh-pages"
    }
    if (v.TemporaryBase == "") {
        v.TemporaryBase = ".tmp"
    }
    if (v.PagesDirectory == "") {
        v.PagesDirectory = "docs"
    }

    temporaryBaseDirectory := ""
    if filepath.IsAbs(v.TemporaryBase) {
        temporaryBaseDirectory = v.TemporaryBase
    } else {
        temporaryBaseDirectory = filepath.Join(w.Path, v.TemporaryBase)
    }
    temporaryPagesDirectory := filepath.Join(temporaryBaseDirectory, v.PagesDirectory)

    fullPagesDirectory := filepath.Join(w.Path, v.PagesDirectory)

    // generate the .netrc file
    if err := writeNetrc(w); err != nil {
        fmt.Fprintln(os.Stderr, err)
        return err
    }

    // write the rsa private key if provided
    if err := repo.WriteKey(w); err != nil {
        fmt.Fprintln(os.Stderr, err)
        return err
    }

    err := repo.GlobalUser(b).Run()
    if err != nil {
        return err
    }

    err = repo.GlobalName(b).Run()
    if err != nil {
        return err
    }

    err = os.MkdirAll(temporaryPagesDirectory, 0777)
    if err != nil {
        return err
    }
    defer os.RemoveAll(temporaryPagesDirectory)

    err = runPublishSteps(w.Path, temporaryBaseDirectory, temporaryPagesDirectory, fullPagesDirectory, v.TargetBranch, v.UpstreamName, r.Clone)
    if err != nil {
        return err
    }
    return nil
}

func runCommand(cmd *exec.Cmd, out *bytes.Buffer) error {
    if (out == nil) {
        if (cmd.Stdout == nil) {
            cmd.Stdout = os.Stdout
        }
    } else {
        cmd.Stdout = out
    }
    cmd.Stderr = os.Stderr;

    err := cmd.Run()
    if err != nil {
        fmt.Printf("Error: %+v %s\n", cmd, err)
        return err
    }
    return nil
}

func runPublishSteps(
    workspacePath string,
    temporaryBaseDirectory string,
    temporaryPagesDirectory string,
    fullPagesDirectory string,
    vargsTargetBranch string,
    vargsUpstreamName string,
    cloneUrl string) error {

    // Get the commit message
    msgRaw, err := commitMessage(workspacePath).Output()
    if err != nil {
        return err
    }
    msg := fmt.Sprintf("%s", msgRaw)
    fmt.Printf("%s\n", msg)

    // Set up git config (rsa, etc)
    fmt.Printf("about to clone\n");
    err = runCommand(cloneTarget(workspacePath, vargsTargetBranch, cloneUrl, temporaryPagesDirectory), nil);
    if (err != nil) {
        return err
    }

    fmt.Printf("about to rsync\n");
    err = runCommand(rsyncPages(workspacePath, fullPagesDirectory, temporaryBaseDirectory), nil);
    if (err != nil) {
        return err
    }

    fmt.Printf("about to add to clone\n");
    var addResult bytes.Buffer
    err = runCommand(addTemporaryFilesToClone(temporaryPagesDirectory), &addResult);
    if (err != nil) {
        fmt.Printf("Error on add: %s", addResult.String())
        return err
    }

    // For now, if the add resulted in a success, with output, we are assuming that there are
    // changes to commit and push
    if (addResult.Len() > 0) {
        fmt.Printf("about to commit\n");
        err = runCommand(commitTemporaryFilesToClone(temporaryPagesDirectory, msg), nil);
        if (err != nil) {
            return err
        }

        fmt.Printf("about to push\n");
        err = runCommand(pushTemporaryClone(temporaryPagesDirectory, vargsUpstreamName, vargsTargetBranch), nil);
        if (err != nil) {
            return err
        }
    }

    return nil
}

// Returns command to get the commit message for the gh-pages
// commit based on the last commit in the build
func commitMessage(workspacePath string) *exec.Cmd {
    cmd := exec.Command(
        "git",
        "show",
        "-q",
    )
    cmd.Dir = workspacePath
    return cmd
}

// Returns command to clone gh-pages into our temporary location.
// git clone -b gh-pages --single-branch repo .tmp/[pages directory]
func cloneTarget(workspacePath string, targetBranch string, repo string, temporaryPagesDirectory string) *exec.Cmd {
    cmd := exec.Command(
        "git",
        "clone",
        "-b",
        targetBranch,
        "--single-branch",
        repo,
        temporaryPagesDirectory,
    )
    cmd.Dir = workspacePath
    return cmd
}

// Copy the pages content to the temporary location
// rsync --delete --exclude .git -r docs .tmp
func rsyncPages(workspacePath string, pagesDirectory string, temporaryBaseDirectory string) *exec.Cmd {
    cmd := exec.Command(
        "rsync",
        "--delete",
        "--exclude",
        ".git",
        "-r",
        pagesDirectory,
        temporaryBaseDirectory,
    )
    cmd.Dir = workspacePath
    return cmd
}

// Add the files in the temporary directory to the commit
// we want to make in the clone.
func addTemporaryFilesToClone(temporaryPagesDirectory string) *exec.Cmd {
    cmd := exec.Command(
        "git",
        "add",
        "--verbose",
        ".",
    )
    cmd.Dir = temporaryPagesDirectory
    return cmd
}

// Commit the working version of the pages content to
// our clone
func commitTemporaryFilesToClone(temporaryPagesDirectory string, message string) *exec.Cmd {
    cmd := exec.Command(
        "git",
        "commit",
        "-m",
        message,
    )
    cmd.Dir = temporaryPagesDirectory
    return cmd
}

// Push our clone to the upstream
func pushTemporaryClone(temporaryPagesDirectory string, upstreamName string, targetBranch string) *exec.Cmd {
    cmd := repo.RemotePush(upstreamName, targetBranch, false)
    cmd.Dir = temporaryPagesDirectory
    return cmd
}

// Writes the netrc file.
func writeNetrc(in *drone.Workspace) error {
    if in.Netrc == nil || len(in.Netrc.Machine) == 0 {
        return nil
    }
    out := fmt.Sprintf(
        netrcFile,
        in.Netrc.Machine,
        in.Netrc.Login,
        in.Netrc.Password,
    )
    home := "/root"
    u, err := user.Current()
    if err == nil {
        home = u.HomeDir
    }
    path := filepath.Join(home, ".netrc")
    return ioutil.WriteFile(path, []byte(out), 0600)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"io/ioutil"
	"math/rand"
	"net"
	"os"
	"os/signal"
	"strconv"
	"strings"
	"syscall"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/miekg/dns"
)

var (
	debug       = flag.Bool("debug", false, "Debug")
	listen      = flag.String("listen", ":53", "Address to listen to (TCP and UDP)")
	answersFile = flag.String("answers", "./answers.json", "File containing the answers to respond with")
	defaultTtl  = flag.Uint("ttl", 600, "TTL for answers")
	logFile     = flag.String("log", "", "Log file")
	pidFile     = flag.String("pid-file", "", "PID to write to")

	answers Answers
)

func main() {
	log.Info("Starting rancher-dns")
	parseFlags()
	err := loadAnswers()
	if err != nil {
		log.Fatal("Cannot startup without a valid Answers file")
	}
	watchSignals()

	seed := time.Now().UTC().UnixNano()
	log.Debug("Set random seed to ", seed)
	rand.Seed(seed)

	udpServer := &dns.Server{Addr: *listen, Net: "udp"}
	tcpServer := &dns.Server{Addr: *listen, Net: "tcp"}

	dns.HandleFunc(".", route)

	go func() {
		log.Fatal(udpServer.ListenAndServe())
	}()
	log.Info("Listening on ", *listen)
	log.Fatal(tcpServer.ListenAndServe())
}

func parseFlags() {
	flag.Parse()

	if *debug {
		log.SetLevel(log.DebugLevel)
	}

	if *logFile != "" {
		if output, err := os.OpenFile(*logFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666); err != nil {
			log.Fatalf("Failed to log to file %s: %v", *logFile, err)
		} else {
			log.SetOutput(output)
		}
	}

	if *pidFile != "" {
		log.Infof("Writing pid %d to %s", os.Getpid(), *pidFile)
		if err := ioutil.WriteFile(*pidFile, []byte(strconv.Itoa(os.Getpid())), 0644); err != nil {
			log.Fatalf("Failed to write pid file %s: %v", *pidFile, err)
		}
	}
}

func loadAnswers() (err error) {
	temp, err := ParseAnswers(*answersFile)
	if err == nil {
		answers = temp
		log.Info("Loaded answers for ", len(answers), " IPs")
	} else {
		log.Errorf("Failed to load answers: %v", err)
	}

	return err
}

func watchSignals() {
	c := make(chan os.Signal, 1)
	signal.Notify(c, syscall.SIGHUP)

	go func() {
		for _ = range c {
			log.Info("Received HUP signal, reloading answers")
			loadAnswers()
		}
	}()
}

func route(w dns.ResponseWriter, req *dns.Msg) {
	// Setup reply
	m := new(dns.Msg)
	m.SetReply(req)
	m.Authoritative = true
	m.RecursionAvailable = true
	m.Compress = true

	clientIp, _, _ := net.SplitHostPort(w.RemoteAddr().String())

	// One question at a time please
	if len(req.Question) != 1 {
		dns.HandleFailed(w, req)
		log.WithFields(log.Fields{"client": clientIp}).Warn("Rejected multi-question query")
		return
	}

	question := req.Question[0]
	rrString := dns.Type(question.Qtype).String()

	// We are assuming the JSON config has all names as lower case
	fqdn := strings.ToLower(question.Name)

	// Internets only
	if question.Qclass != dns.ClassINET {
		m.Authoritative = false
		m.RecursionDesired = false
		m.RecursionAvailable = false
		m.Rcode = dns.RcodeNotImplemented
		w.WriteMsg(m)
		log.WithFields(log.Fields{"question": fqdn, "type": rrString, "client": clientIp}).Warn("Rejected non-inet query")
		return
	}

	// ANY queries are bad, mmmkay...
	if question.Qtype == dns.TypeANY {
		m.Authoritative = false
		m.RecursionDesired = false
		m.RecursionAvailable = false
		m.Rcode = dns.RcodeNotImplemented
		w.WriteMsg(m)
		log.WithFields(log.Fields{"question": fqdn, "type": rrString, "client": clientIp}).Warn("Rejected ANY query")
		return
	}

	proto := "UDP"
	if isTcp(w) {
		proto = "TCP"
	}

	log.WithFields(log.Fields{"question": fqdn, "type": rrString, "client": clientIp, "proto": proto}).Debug("Request")

	// A records may return CNAME answer(s) plus A answer(s)
	if question.Qtype == dns.TypeA {
		found, ok := answers.Addresses(clientIp, fqdn, nil, 1)
		if ok && len(found) > 0 {
			log.WithFields(log.Fields{"client": clientIp, "type": rrString, "question": fqdn, "answers": len(found)}).Debug("Answered locally")
			m.Answer = found
			Respond(w, req, m)
			return
		}
	} else {
		// Specific request for another kind of record
		keys := []string{clientIp, DEFAULT_KEY}
		for _, key := range keys {
			// Client-specific answers
			found, ok := answers.Matching(question.Qtype, key, fqdn)
			if ok {
				log.WithFields(log.Fields{"client": key, "type": rrString, "question": fqdn, "answers": len(found)}).Debug("Answered from config for ", key)
				m.Answer = found
				Respond(w, req, m)
				return
			}
		}

		log.Debug("No match found in config")
	}

	// Phone a friend - Forward original query
	msg, err := ResolveTryAll(req, answers.Recursers(clientIp))
	if err == nil {
		msg.Compress = true
		msg.Id = req.Id
		Respond(w, req, msg)
		log.WithFields(log.Fields{"client": clientIp, "type": rrString, "question": fqdn}).Debug("Sent recursive response")
		return
	}

	// I give up
	log.WithFields(log.Fields{"client": clientIp, "type": rrString, "question": fqdn}).Info("No answer found")
	dns.HandleFailed(w, req)
}

func isTcp(w dns.ResponseWriter) bool {
	_, ok := w.RemoteAddr().(*net.TCPAddr)
	return ok
}
<commit_msg>Fix recursive AAAA response code<commit_after>package main

import (
	"flag"
	"io/ioutil"
	"math/rand"
	"net"
	"os"
	"os/signal"
	"strconv"
	"strings"
	"syscall"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/miekg/dns"
)

var (
	debug       = flag.Bool("debug", false, "Debug")
	listen      = flag.String("listen", ":53", "Address to listen to (TCP and UDP)")
	answersFile = flag.String("answers", "./answers.json", "File containing the answers to respond with")
	defaultTtl  = flag.Uint("ttl", 600, "TTL for answers")
	logFile     = flag.String("log", "", "Log file")
	pidFile     = flag.String("pid-file", "", "PID to write to")

	answers Answers
)

func main() {
	log.Info("Starting rancher-dns")
	parseFlags()
	err := loadAnswers()
	if err != nil {
		log.Fatal("Cannot startup without a valid Answers file")
	}
	watchSignals()

	seed := time.Now().UTC().UnixNano()
	log.Debug("Set random seed to ", seed)
	rand.Seed(seed)

	udpServer := &dns.Server{Addr: *listen, Net: "udp"}
	tcpServer := &dns.Server{Addr: *listen, Net: "tcp"}

	dns.HandleFunc(".", route)

	go func() {
		log.Fatal(udpServer.ListenAndServe())
	}()
	log.Info("Listening on ", *listen)
	log.Fatal(tcpServer.ListenAndServe())
}

func parseFlags() {
	flag.Parse()

	if *debug {
		log.SetLevel(log.DebugLevel)
	}

	if *logFile != "" {
		if output, err := os.OpenFile(*logFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666); err != nil {
			log.Fatalf("Failed to log to file %s: %v", *logFile, err)
		} else {
			log.SetOutput(output)
		}
	}

	if *pidFile != "" {
		log.Infof("Writing pid %d to %s", os.Getpid(), *pidFile)
		if err := ioutil.WriteFile(*pidFile, []byte(strconv.Itoa(os.Getpid())), 0644); err != nil {
			log.Fatalf("Failed to write pid file %s: %v", *pidFile, err)
		}
	}
}

func loadAnswers() (err error) {
	temp, err := ParseAnswers(*answersFile)
	if err == nil {
		answers = temp
		log.Info("Loaded answers for ", len(answers), " IPs")
	} else {
		log.Errorf("Failed to load answers: %v", err)
	}

	return err
}

func watchSignals() {
	c := make(chan os.Signal, 1)
	signal.Notify(c, syscall.SIGHUP)

	go func() {
		for _ = range c {
			log.Info("Received HUP signal, reloading answers")
			loadAnswers()
		}
	}()
}

func route(w dns.ResponseWriter, req *dns.Msg) {
	// Setup reply
	m := new(dns.Msg)
	m.SetReply(req)
	m.Authoritative = true
	m.RecursionAvailable = true
	m.Compress = true

	clientIp, _, _ := net.SplitHostPort(w.RemoteAddr().String())

	// One question at a time please
	if len(req.Question) != 1 {
		dns.HandleFailed(w, req)
		log.WithFields(log.Fields{"client": clientIp}).Warn("Rejected multi-question query")
		return
	}

	question := req.Question[0]
	rrString := dns.Type(question.Qtype).String()

	// We are assuming the JSON config has all names as lower case
	fqdn := strings.ToLower(question.Name)

	// Internets only
	if question.Qclass != dns.ClassINET {
		m.Authoritative = false
		m.RecursionDesired = false
		m.RecursionAvailable = false
		m.Rcode = dns.RcodeNotImplemented
		w.WriteMsg(m)
		log.WithFields(log.Fields{"question": fqdn, "type": rrString, "client": clientIp}).Warn("Rejected non-inet query")
		return
	}

	// ANY queries are bad, mmmkay...
	if question.Qtype == dns.TypeANY {
		m.Authoritative = false
		m.RecursionDesired = false
		m.RecursionAvailable = false
		m.Rcode = dns.RcodeNotImplemented
		w.WriteMsg(m)
		log.WithFields(log.Fields{"question": fqdn, "type": rrString, "client": clientIp}).Warn("Rejected ANY query")
		return
	}

	proto := "UDP"
	if isTcp(w) {
		proto = "TCP"
	}

	log.WithFields(log.Fields{"question": fqdn, "type": rrString, "client": clientIp, "proto": proto}).Debug("Request")

	// A records may return CNAME answer(s) plus A answer(s)
	if question.Qtype == dns.TypeA {
		found, ok := answers.Addresses(clientIp, fqdn, nil, 1)
		if ok && len(found) > 0 {
			log.WithFields(log.Fields{"client": clientIp, "type": rrString, "question": fqdn, "answers": len(found)}).Debug("Answered locally")
			m.Answer = found
			Respond(w, req, m)
			return
		}
	} else {
		// Specific request for another kind of record
		keys := []string{clientIp, DEFAULT_KEY}
		for _, key := range keys {
			// Client-specific answers
			found, ok := answers.Matching(question.Qtype, key, fqdn)
			if ok {
				log.WithFields(log.Fields{"client": key, "type": rrString, "question": fqdn, "answers": len(found)}).Debug("Answered from config for ", key)
				m.Answer = found
				Respond(w, req, m)
				return
			}
		}

		log.Debug("No match found in config")
	}

	// Phone a friend - Forward original query
	msg, err := ResolveTryAll(req, answers.Recursers(clientIp))
	if err == nil {
		msg.Compress = true
		msg.Id = req.Id

		// We don't support AAAA, but an NXDOMAIN from the recursive resolver
		// doesn't necessarily mean there are never any records for that domain,
		// so rewrite the response code to NOERROR.
		if (question.Qtype == dns.TypeAAAA) && (msg.Rcode == dns.RcodeNameError) {
			log.WithFields(log.Fields{"client": clientIp, "type": rrString, "question": fqdn}).Debug("Rewrote AAAA NXDOMAIN to NOERROR")
			msg.Rcode = dns.RcodeSuccess
		}

		Respond(w, req, msg)
		log.WithFields(log.Fields{"client": clientIp, "type": rrString, "question": fqdn}).Debug("Sent recursive response")
		return
	}

	// I give up
	log.WithFields(log.Fields{"client": clientIp, "type": rrString, "question": fqdn}).Info("No answer found")
	dns.HandleFailed(w, req)
}

func isTcp(w dns.ResponseWriter) bool {
	_, ok := w.RemoteAddr().(*net.TCPAddr)
	return ok
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/google/go-github/github"
	"golang.org/x/oauth2"
	"os"
	"strings"
)

type source struct {
	myToken *oauth2.Token
}

func (t source) Token() (*oauth2.Token, error) {
	return t.myToken, nil
}

func main() {
	if len(os.Args) != 2 {
		fmt.Printf("missing github access token as avg 1\n")
		return
	}

	var NoContext oauth2.Context = nil
	src := source{
		myToken: &oauth2.Token{AccessToken: os.Args[1]},
	}

	client := oauth2.NewClient(NoContext, src)
	ghClient := github.NewClient(client)
	owner := "docker-library"
	repository := "official-images"

	err := labelPullsInRepo(ghClient, owner, repository, "all", "library/")
	if err != nil {
		fmt.Printf("%v", err)
		return
	}

	return
}

func labelPullsInRepo(ghClient *github.Client, owner string, repository string, state string, filePrefix string) error {
	options := &github.PullRequestListOptions{
		State: state,
		ListOptions: github.ListOptions{
			PerPage: 100,
		},
	}

	for {
		pulls, resp, err := ghClient.PullRequests.List(owner, repository, options)
		if err != nil {
			return err
		}

		for _, pr := range pulls {
			commitFiles, _, err := ghClient.PullRequests.ListFiles(owner, repository, *pr.Number, nil)
			if err != nil {
				fmt.Printf("%v", err)
				continue
			}

			labels := []string{}
			for _, commitFile := range commitFiles {
				if strings.HasPrefix(*commitFile.Filename, filePrefix) {
					labels = append(labels, *commitFile.Filename)
				}
			}
			fmt.Printf("%d: %v\n", *pr.Number, labels)

			// add labels
			labelObjs, _, err := ghClient.Issues.AddLabelsToIssue(owner, repository, *pr.Number, labels)
			if err != nil {
				fmt.Printf("%v", err)
				continue
			}
			fmt.Printf("%v\n", labelObjs)
		}

		if resp.NextPage == 0 {
			break
		}
		options.ListOptions.Page = resp.NextPage
	}

	return nil
}
<commit_msg>Only do open PRs now<commit_after>package main

import (
	"fmt"
	"github.com/google/go-github/github"
	"golang.org/x/oauth2"
	"os"
	"strings"
)

type source struct {
	myToken *oauth2.Token
}

func (t source) Token() (*oauth2.Token, error) {
	return t.myToken, nil
}

func main() {
	if len(os.Args) != 2 {
		fmt.Printf("missing github access token as avg 1\n")
		return
	}

	var NoContext oauth2.Context = nil
	src := source{
		myToken: &oauth2.Token{AccessToken: os.Args[1]},
	}

	client := oauth2.NewClient(NoContext, src)
	ghClient := github.NewClient(client)
	owner := "docker-library"
	repository := "official-images"

	err := labelPullsInRepo(ghClient, owner, repository, "open", "library/")
	if err != nil {
		fmt.Printf("%v", err)
		return
	}

	return
}

func labelPullsInRepo(ghClient *github.Client, owner string, repository string, state string, filePrefix string) error {
	options := &github.PullRequestListOptions{
		State: state,
		ListOptions: github.ListOptions{
			PerPage: 100,
		},
	}

	for {
		pulls, resp, err := ghClient.PullRequests.List(owner, repository, options)
		if err != nil {
			return err
		}

		for _, pr := range pulls {
			commitFiles, _, err := ghClient.PullRequests.ListFiles(owner, repository, *pr.Number, nil)
			if err != nil {
				fmt.Printf("%v", err)
				continue
			}

			labels := []string{}
			for _, commitFile := range commitFiles {
				if strings.HasPrefix(*commitFile.Filename, filePrefix) {
					labels = append(labels, *commitFile.Filename)
				}
			}
			fmt.Printf("%d: %v\n", *pr.Number, labels)

			// add labels
			labelObjs, _, err := ghClient.Issues.AddLabelsToIssue(owner, repository, *pr.Number, labels)
			if err != nil {
				fmt.Printf("%v", err)
				continue
			}
			fmt.Printf("%v\n", labelObjs)
		}

		if resp.NextPage == 0 {
			break
		}
		options.ListOptions.Page = resp.NextPage
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"path/filepath"

	"github.com/googollee/go-socket.io"

	"github.com/tiltfactor/toto/domain"
	"github.com/tiltfactor/toto/utils"

	"github.com/BurntSushi/toml"
	"github.com/jesusrmoreno/sad-squid"

	"github.com/codegangsta/cli"
)

// Version ...
var Version = "1.3.0"

// Events that are exposed to the client
const (
	groupAssignment = "group-assignment"
	roomMessage     = "room-message"
	leaveGroup      = "leave-group"
	joinGroup       = "join-group"
	joinGame        = "join-game"
	getPeers        = "get-peers"
	makeMove        = "make-move"
	moveMade        = "move-made"
	inQueue         = "in-queue"

	serverError = "server-error"
	clientError = "client-error"
)

// Response ...
type Response struct {
	Kind string                 `json:"kind"`
	Data map[string]interface{} `json:"data"`
}

// Method for creating errors more quickly.
func errorResponse(kind, err string) Response {
	d := map[string]interface{}{}
	d["error"] = err
	r := Response{
		Kind: kind,
		Data: d,
	}
	return r
}

// GamesInfo serves to store the metadata for different games
type GamesInfo struct {
	// These must be thread safe so we use the ConcurrentMap types
	TurnMap *utils.ConcurrentStringIntMap
	// Maps the player id to the room
	RoomMap *utils.ConcurrentStringMap
}

// ReadGameFiles reads the provided directory for files that conform to the
// game struct definition, these must be json files, and loads them into our
// game map.
func ReadGameFiles(gameDir string) (domain.GameMap, error) {
	files, err := filepath.Glob(gameDir + "/*.toml")
	gm := domain.GameMap{}
	if err != nil {
		return nil, err
	}
	for _, f := range files {
		raw, err := os.Open(f)
		defer raw.Close()
		if err != nil {
			return nil, err
		}
		r := io.Reader(raw)
		dummy := domain.Game{}
		if meta, err := toml.DecodeReader(r, &dummy); err != nil {
			log.Println(meta)
			return nil, errors.New("Invalid configuration in file: " + f)
		}
		g := domain.Game{
			Players: dummy.Players,
			Title:   dummy.Title,
			UUID:    dummy.UUID,
			Lobby:   domain.NewLobby(),
		}
		g.FileName = f
		if _, exists := gm[g.UUID]; exists {
			return nil, errors.New("uniqueKey conflict between: " + f + " and " + gm[g.UUID].FileName)
		}
		gm[g.UUID] = g
	}
	return gm, nil
}

// turnKey returns the generated key for storing turns
func turnKey(playerID, roomName string) string {
	return roomName + ":" + playerID
}

// QueuePlayers adds players to the game's lobby to wait for a partner.
// Players are queued on a first come first serve basis.
func QueuePlayers(g domain.Game, p domain.Player) bool {
	pq := g.Lobby
	if !pq.Contains(p.Comm.Id()) {
		pq.AddToQueue(p)
		return true
	}
	return false
}

// GroupPlayers attempts to creates groups of players of the size defined in the
// game files. It also sets the player turns.
// It returns the name of the room and true if it succeeded or
// an empty string and false if it did not.
func GroupPlayers(g domain.Game, gi *GamesInfo) (string, bool) {
	log.Println("Attempting to group players for game", g.UUID)
	pq := g.Lobby
	needed := g.Players
	available := pq.Size()
	if available >= needed {
		team := []domain.Player{}
		roomName := squid.GenerateSimpleID()
		for i := 0; i < needed; i++ {
			p := pq.PopFromQueue()
			team = append(team, p)

			// Place the player in the created room.
			p.Comm.Join(roomName)

			playerID := p.Comm.Id()
			gi.RoomMap.Set(playerID, roomName)

			// We generate a turn key composed of the room name and player id to store
			// the turn. turns are assigned based off of how they are popped from the
			// queue.
			tk := turnKey(playerID, roomName)
			gi.TurnMap.Set(tk, i)
		}
		return roomName, true
	}
	return "", false
}

func OldGroupPlayers(g domain.Game, server *socketio.Server, gi *GamesInfo) {
	log.Println("Attempting to group players")
	pq := g.Lobby
	n := g.Players
	if g.Lobby.Size() >= n {
		team := []domain.Player{}
		// Generate a room id
		roomName := squid.GenerateSimpleID()
		for i := 0; i < n; i++ {
			p := pq.PopFromQueue()
			pID := p.Comm.Id()
			team = append(team, p)

			// Set the metadata
			gi.RoomMap.Set(pID, roomName)
			gi.TurnMap.Set(roomName+":"+pID, i)

			// Create the response
			data := map[string]interface{}{}
			data["roomName"] = roomName
			data["turnNumber"] = i
			r := Response{
				Kind: groupAssignment,
				Data: data,
			}
			p.Comm.Emit(groupAssignment, r)
		}
		// Create the response
		data := map[string]interface{}{}
		data["message"] = fmt.Sprintf("Welcome to %s", roomName)
		r := Response{
			Kind: roomMessage,
			Data: data,
		}
		server.BroadcastTo(roomName, roomMessage, r)
		log.Println("Created room:", roomName, "for players", team)
	} else {
		log.Println("Not enough players in lobby to create group", pq.Size())
	}
}

// Cross origin server is used to add cross-origin request capabilities to the socket
// server. It wraps the socketio.Server
type crossOriginServer struct {
	Server *socketio.Server
}

// ServeHTTP is implemented to add the needed header for CORS in socketio.
// This must be named ServeHTTP and take the
// (http.ResponseWriter, r *http.Request) to satisfy the http.Handler interface
func (s crossOriginServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Access-Control-Allow-Credentials", "true")
	origin := r.Header.Get("Origin")
	w.Header().Set("Access-Control-Allow-Origin", origin)
	s.Server.ServeHTTP(w, r)
}

// StartServer ...
func StartServer(c *cli.Context) {
	games, err := ReadGameFiles("./games")
	for key, game := range games {
		log.Println("Loaded:", key, "from", game.FileName)
	}
	if err != nil {
		log.Fatal(err)
	}
	server, err := socketio.NewServer(nil)
	s := crossOriginServer{
		Server: server,
	}
	if err != nil {
		log.Fatal(err)
	}
	info := GamesInfo{
		RoomMap: utils.NewConcurrentStringMap(),
		TurnMap: utils.NewConcurrentStringIntMap(),
	}

	server.On("connection", func(so socketio.Socket) {
		// Makes it so that the player joins a room with his/her unique id.
		so.Join(so.Id())
		log.Println("Connection from", so.Id())
		so.On(joinGame, func(req json.RawMessage) {
			m := map[string]string{}
			if err := json.Unmarshal(req, &m); err != nil {
				log.Println("Invalid JSON from", so.Id())
				so.Emit(clientError, errorResponse(clientError, "Invalid JSON"))
			}
			gameID, exists := m["gameId"]
			if !exists {
				log.Println("No game included from", so.Id())
				so.Emit(clientError, errorResponse(clientError, "Must include GameID"))
			}
			log.Println(so.Id(), "attempted to join game", gameID)
			// If the player attempts to connect to a game we first have to make
			// sure that they are joining a game that is registered with our server.
			if g, exists := games[gameID]; exists {
				// First queue the player
				didQueue := QueuePlayers(g, domain.Player{
					Comm: so,
				})
				data := map[string]interface{}{}
				r := Response{
					Kind: inQueue,
					Data: data,
				}
				if didQueue {
					data["message"] = "You are in the queue for game: " + g.Title
					so.Emit(inQueue, r)
					// GroupPlayers(g, server, &info)
				} else {
					data["message"] = "Already in queue"
					so.Emit(clientError, r)
				}
				// Then attempt to form a group based off of this.

			} else {
				log.Println("Invalid GameId from", so.Id())
				so.Emit(clientError, errorResponse(clientError, "Invalid GameID"))
			}
		})
		so.On("disconnection", func() {
			// This is really really bad unfuture proof, slow code.
			// Please Refactor me
			for key := range games {
				g := games[key]
				g.Lobby.Remove(so.Id())
			}
		})
		so.On(makeMove, func(move json.RawMessage) {
			room, exists := info.RoomMap.Get(so.Id())
			log.Println(string(move))
			if exists {
				m := map[string]interface{}{}
				if err := json.Unmarshal(move, &m); err != nil {
					log.Println("Invalid JSON from", so.Id(), string(move))
					so.Emit(clientError, errorResponse(clientError, "Invalid JSON"))
				}
				turn, exists := info.TurnMap.Get(room + ":" + so.Id())
				if !exists {
					log.Println("No turn assigned", so.Id())
					so.Emit(serverError, errorResponse(serverError, "No turn assigned"))
				}
				// Overwrites who's turn it is using the turn map assigned at join.
				m["madeBy"] = turn
				m["madeById"] = so.Id()
				r := Response{
					Kind: moveMade,
					Data: m,
				}
				log.Println(r)
				so.BroadcastTo(room, moveMade, r)
			} else {
				log.Println("No room assigned for", so.Id())
				so.Emit(serverError, errorResponse(serverError, "Not in any Room"))
			}
		})
	})

	port := c.String("port")

	http.Handle("/socket.io/", s)
	http.Handle("/", http.FileServer(http.Dir("./asset")))
	log.Println("Serving at localhost:" + port)
	log.Fatal(http.ListenAndServe(":"+port, nil))
}

func main() {
	app := cli.NewApp()
	app.Name = "Toto"
	app.Usage = "a server for creating quick prototype websocket based games."
	app.Action = StartServer
	app.Version = Version
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "port, p",
			Value: "3000",
			Usage: "The port to run the server on",
		},
	}
	app.Run(os.Args)
}
<commit_msg>:hocho: Decoupled queue/group from messaging<commit_after>package main

import (
	"encoding/json"
	"errors"
	"io"
	"log"
	"net/http"
	"os"
	"path/filepath"

	"github.com/googollee/go-socket.io"

	"github.com/tiltfactor/toto/domain"
	"github.com/tiltfactor/toto/utils"

	"github.com/BurntSushi/toml"
	"github.com/jesusrmoreno/sad-squid"

	"github.com/codegangsta/cli"
)

// Version ...
var Version = "1.3.0"

// Events that are exposed to the client
const (
	groupAssignment = "group-assignment"
	roomMessage     = "room-message"
	leaveGroup      = "leave-group"
	joinGroup       = "join-group"
	joinGame        = "join-game"
	getPeers        = "get-peers"
	makeMove        = "make-move"
	moveMade        = "move-made"
	inQueue         = "in-queue"

	serverError = "server-error"
	clientError = "client-error"
)

// Response ...
type Response struct {
	Kind string                 `json:"kind"`
	Data map[string]interface{} `json:"data"`
}

// Method for creating errors more quickly.
func errorResponse(kind, err string) Response {
	d := map[string]interface{}{}
	d["error"] = err
	r := Response{
		Kind: kind,
		Data: d,
	}
	return r
}

// GamesInfo serves to store the metadata for different games
type GamesInfo struct {
	// These must be thread safe so we use the ConcurrentMap types
	TurnMap *utils.ConcurrentStringIntMap
	// Maps the player id to the room
	RoomMap *utils.ConcurrentStringMap
}

// ReadGameFiles reads the provided directory for files that conform to the
// game struct definition, these must be json files, and loads them into our
// game map.
func ReadGameFiles(gameDir string) (domain.GameMap, error) {
	files, err := filepath.Glob(gameDir + "/*.toml")
	gm := domain.GameMap{}
	if err != nil {
		return nil, err
	}
	for _, f := range files {
		raw, err := os.Open(f)
		defer raw.Close()
		if err != nil {
			return nil, err
		}
		r := io.Reader(raw)
		dummy := domain.Game{}
		if meta, err := toml.DecodeReader(r, &dummy); err != nil {
			log.Println(meta)
			return nil, errors.New("Invalid configuration in file: " + f)
		}
		g := domain.Game{
			Players: dummy.Players,
			Title:   dummy.Title,
			UUID:    dummy.UUID,
			Lobby:   domain.NewLobby(),
		}
		g.FileName = f
		if _, exists := gm[g.UUID]; exists {
			return nil, errors.New("uniqueKey conflict between: " + f + " and " +
				gm[g.UUID].FileName)
		}
		gm[g.UUID] = g
	}
	return gm, nil
}

// turnKey returns the generated key for storing turns
func turnKey(playerID, roomName string) string {
	return roomName + ":" + playerID
}

// QueuePlayers adds players to the game's lobby to wait for a partner.
// Players are queued on a first come first serve basis.
func QueuePlayers(g domain.Game, p domain.Player) bool {
	pq := g.Lobby
	if !pq.Contains(p.Comm.Id()) {
		pq.AddToQueue(p)
		return true
	}
	return false
}

// GroupPlayers attempts to creates groups of players of the size defined in the
// game files. It also sets the player turns.
// It returns the name of the room and true if it succeeded or
// an empty string and false if it did not.
func GroupPlayers(g domain.Game, gi *GamesInfo) (string, []domain.Player) {
	log.Println("Attempting to group players for game", g.UUID)
	pq := g.Lobby
	needed := g.Players
	available := pq.Size()
	if available >= needed {
		team := []domain.Player{}
		roomName := squid.GenerateSimpleID()
		for i := 0; i < needed; i++ {
			p := pq.PopFromQueue()
			team = append(team, p)

			// Place the player in the created room.
			p.Comm.Join(roomName)

			playerID := p.Comm.Id()
			gi.RoomMap.Set(playerID, roomName)

			// We generate a turn key composed of the room name and player id to store
			// the turn. turns are assigned based off of how they are popped from the
			// queue.
			tk := turnKey(playerID, roomName)
			gi.TurnMap.Set(tk, i)
		}
		return roomName, team
	}
	return "", nil
}

// Cross origin server is used to add cross-origin request capabilities to the
// socket server. It wraps the socketio.Server
type crossOriginServer struct {
	Server *socketio.Server
}

// ServeHTTP is implemented to add the needed header for CORS in socketio.
// This must be named ServeHTTP and take the
// (http.ResponseWriter, r *http.Request) to satisfy the http.Handler interface
func (s crossOriginServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Access-Control-Allow-Credentials", "true")
	origin := r.Header.Get("Origin")
	w.Header().Set("Access-Control-Allow-Origin", origin)
	s.Server.ServeHTTP(w, r)
}

func handlePlayerJoin(so socketio.Socket, req json.RawMessage,
	games domain.GameMap, info GamesInfo) {
	m := map[string]string{}
	if err := json.Unmarshal(req, &m); err != nil {
		log.Println("Invalid JSON from", so.Id())
		so.Emit(clientError, errorResponse(clientError, "Invalid JSON"))
	}
	gameID, exists := m["gameId"]
	if !exists {
		log.Println("No game included from", so.Id())
		so.Emit(clientError, errorResponse(clientError, "Must include GameID"))
	}

	log.Println(so.Id(), "attempting to join game", gameID)
	// If the player attempts to connect to a game we first have to make
	// sure that they are joining a game that is registered with our server.
	if g, exists := games[gameID]; exists {
		// First queue the player
		newPlayer := domain.Player{
			Comm: so,
		}
		if didQueue := QueuePlayers(g, newPlayer); didQueue {
			// Create the response we're going to send
			data := map[string]interface{}{}
			r := Response{
				Kind: inQueue,
				Data: data,
			}
			data["message"] = "You are in the queue for game: " + g.Title
			so.Emit(inQueue, r)
			if rn, group := GroupPlayers(g, &info); group != nil && rn != "" {
				// Tell each member what their room name is as well as their turn
				for i, p := range group {
					data := map[string]interface{}{}
					data["roomName"] = rn
					r := Response{
						Kind: groupAssignment,
						Data: data,
					}
					data["turnNumber"] = i
					p.Comm.Emit(groupAssignment, r)
				}
			}
		} else {
			// Create the response we're going to send
			data := map[string]interface{}{}
			r := Response{
				Kind: inQueue,
				Data: data,
			}
			data["message"] = "Already in queue"
			so.Emit(clientError, r)
		}
		// Then attempt to form a group based off of this.

	} else {
		log.Println("Invalid GameId from", so.Id())
		so.Emit(clientError, errorResponse(clientError, "Invalid GameID"))
	}
}

// StartServer ...
func StartServer(c *cli.Context) {
	games, err := ReadGameFiles("./games")
	for key, game := range games {
		log.Println("Loaded:", key, "from", game.FileName)
	}
	if err != nil {
		log.Fatal(err)
	}
	server, err := socketio.NewServer(nil)
	s := crossOriginServer{
		Server: server,
	}
	if err != nil {
		log.Fatal(err)
	}
	info := GamesInfo{
		RoomMap: utils.NewConcurrentStringMap(),
		TurnMap: utils.NewConcurrentStringIntMap(),
	}

	server.On("connection", func(so socketio.Socket) {
		log.Println("Connection from", so.Id())

		// Makes it so that the player joins a room with his/her unique id.
		so.Join(so.Id())
		so.On(joinGame, func(r json.RawMessage) {
			handlePlayerJoin(so, r, games, info)
		})

		so.On("disconnection", func() {
			// This is really really bad unfuture proof, slow code.
			// Please Refactor me
			for key := range games {
				g := games[key]
				g.Lobby.Remove(so.Id())
			}
		})
		so.On(makeMove, func(move json.RawMessage) {
			room, exists := info.RoomMap.Get(so.Id())
			log.Println(string(move))
			if exists {
				m := map[string]interface{}{}
				if err := json.Unmarshal(move, &m); err != nil {
					log.Println("Invalid JSON from", so.Id(), string(move))
					so.Emit(clientError, errorResponse(clientError, "Invalid JSON"))
				}
				turn, exists := info.TurnMap.Get(room + ":" + so.Id())
				if !exists {
					log.Println("No turn assigned", so.Id())
					so.Emit(serverError, errorResponse(serverError, "No turn assigned"))
				}
				// Overwrites who's turn it is using the turn map assigned at join.
				m["madeBy"] = turn
				m["madeById"] = so.Id()
				r := Response{
					Kind: moveMade,
					Data: m,
				}
				log.Println(r)
				so.BroadcastTo(room, moveMade, r)
			} else {
				log.Println("No room assigned for", so.Id())
				so.Emit(serverError, errorResponse(serverError, "Not in any Room"))
			}
		})
	})

	port := c.String("port")

	http.Handle("/socket.io/", s)
	http.Handle("/", http.FileServer(http.Dir("./asset")))
	log.Println("Serving at localhost:" + port)
	log.Fatal(http.ListenAndServe(":"+port, nil))
}

func main() {
	app := cli.NewApp()
	app.Name = "Toto"
	app.Usage = "a server for creating quick prototype websocket based games."
	app.Action = StartServer
	app.Version = Version
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "port, p",
			Value: "3000",
			Usage: "The port to run the server on",
		},
	}
	app.Run(os.Args)
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"crypto/tls"
	"fmt"
	"github.com/drone/drone-plugin-go/plugin"
	"io/ioutil"
	"net/http"
	"os"
)

func createArtifact(artifact string, url string, token string, workspace string) {
	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}

	file, e := ioutil.ReadFile(workspace + artifact)
	fmt.Println(file)
	if e != nil {
		fmt.Println(e)
		os.Exit(1)
	}
	// post payload to each artifact
	req, err := http.NewRequest("POST", url, bytes.NewBuffer(file))
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", "Bearer "+token)
	client := &http.Client{Transport: tr}
	resp, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()
	contents, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		os.Exit(1)
	}
	fmt.Printf("%s\n", string(contents))

}

func main() {
	var vargs = struct {
		ReplicationControllers []string `json:"replicationcontrollers"`
		Services               []string `json:"services"`
		ApiServer              string   `json:apiserver`
		Token                  string   `json:token`
		Namespace              string   `json:namespace`
	}{}

	workspace := plugin.Workspace{}
	plugin.Param("workspace", &workspace)
	plugin.Param("vargs", &vargs)
	plugin.Parse()

	rc_url := fmt.Sprintf("%s/api/v1/namespaces/%s/replicationcontrollers", vargs.ApiServer, vargs.Namespace)
	svc_url := fmt.Sprintf("%s/api/v1/namespaces/%s/services", vargs.ApiServer, vargs.Namespace)

	// Iterate over rcs and svcs
	for _, rc := range vargs.ReplicationControllers {
		createArtifact(rc, rc_url, vargs.Token, workspace.Path)
	}
	for _, rc := range vargs.Services {
		createArtifact(rc, svc_url, vargs.Token, workspace.Path)
	}
}
<commit_msg>path typo<commit_after>package main

import (
	"bytes"
	"crypto/tls"
	"fmt"
	"github.com/drone/drone-plugin-go/plugin"
	"io/ioutil"
	"net/http"
	"os"
)

func createArtifact(artifact string, url string, token string, workspace string) {
	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}

	file, e := ioutil.ReadFile(workspace + "/" + artifact)
	fmt.Println(file)
	if e != nil {
		fmt.Println(e)
		os.Exit(1)
	}
	// post payload to each artifact
	req, err := http.NewRequest("POST", url, bytes.NewBuffer(file))
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", "Bearer "+token)
	client := &http.Client{Transport: tr}
	resp, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()
	contents, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		os.Exit(1)
	}
	fmt.Printf("%s\n", string(contents))

}

func main() {
	var vargs = struct {
		ReplicationControllers []string `json:"replicationcontrollers"`
		Services               []string `json:"services"`
		ApiServer              string   `json:apiserver`
		Token                  string   `json:token`
		Namespace              string   `json:namespace`
	}{}

	workspace := plugin.Workspace{}
	plugin.Param("workspace", &workspace)
	plugin.Param("vargs", &vargs)
	plugin.Parse()

	rc_url := fmt.Sprintf("%s/api/v1/namespaces/%s/replicationcontrollers", vargs.ApiServer, vargs.Namespace)
	svc_url := fmt.Sprintf("%s/api/v1/namespaces/%s/services", vargs.ApiServer, vargs.Namespace)

	// Iterate over rcs and svcs
	for _, rc := range vargs.ReplicationControllers {
		createArtifact(rc, rc_url, vargs.Token, workspace.Path)
	}
	for _, rc := range vargs.Services {
		createArtifact(rc, svc_url, vargs.Token, workspace.Path)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"log"
	"net"
	"net/http"
	"net/url"
	"strconv"
	"strings"
)

var MaxAgeVal string

func AbortTLSListener(conn net.Conn) {
	// This sends a TLS v1.2 alert packet regardless of query.
	// We respond the certificate authority (CA) that issued
	// the requesters certificate is unknown to us. This is possibly
	// the shortest response to a TLS (HTTPS) connection which
	// initiates a graceful shutdown on both ends.
	//
	// Note: This isn't TLS 1.3 compatible. Once browsers start
	//       deprecating 1.2 this will need to be overhauled. The
	//       1.3 specification is nothing like 1.2.
	//
	// The original idea came from h0tw1r3. Relevant projects:
	//  https://github.com/kvic-z/pixelserv-tls/wiki/Command-Line-Options
	//  https://github.com/h0tw1r3/pixelserv/blob/master/pixelserv.c
	conn.Write([]byte{
		'\x15',         // Alert protocol header (21)
		'\x03', '\x03', // TLS v1.2 (RFC 5246)
		'\x00', '\x02', // Message length (2)
		'\x02',  // Alert level fatal (2)
		'\x30'}) // Unknown Certificate Authority (48)
	conn.Close()
}

func NullHandler(w http.ResponseWriter, r *http.Request) {
	u, _ := url.QueryUnescape(r.URL.String())

	// RFC 3986, Section 3 lists '?' as a query delimiter,
	// '#' as a fragment delimiter, and ';' as a sub-delimiter.
	// All three cannot be part of the path. Remove them.
	for _, value := range []string{"?", ";", "#"} {
		if strings.Contains(u, value) {
			u = strings.Split(u, value)[0]
		}
	}

	// Obtain the file suffix in the URI, if any.
	suffix := ""
	if idx := strings.LastIndex(u, "."); idx != -1 {
		suffix = u[idx+1 : len(u)]
	}

	// If this is an alternate suffix, replace with the real one.
	if realSuffix, ok := AltSuffix[suffix]; ok == true {
		suffix = realSuffix
	}

	// These are suffixes where we return 404, not found.
	if _, ok := NotFoundFiles[suffix]; ok == true {
		http.NotFound(w, r)
		return
	}

	// Fetch the null file for this suffix. Use HTML as the default case.
	f, ok := NullFiles[suffix]
	if ok != true {
		f = NullFiles["html"]
	}
	w.Header().Set("Cache-Control", MaxAgeVal)
	w.Header().Set("Content-Type", f.content)
	if f.data != nil {
		w.Write(f.data)
	}
}

func main() {
	// Parse command line arguments
	httpAddr := flag.String("a", "", "http address (default '' = all)")
	httpPort := flag.Int("p", 80, "http port")
	httpsAddr := flag.String("A", "", "https address (default '' = all)")
	httpsPort := flag.Int("P", 443, "https port")
	maxAge := flag.Int("m", 31536000, "content cache age in secs")
	flag.Parse()
	MaxAgeVal = "public, max-age=" + strconv.Itoa(*maxAge)

	// Starting HTTP server
	addr := *httpAddr + ":" + strconv.Itoa(*httpPort)
	http.HandleFunc("/", NullHandler)
	go func() {
		if err := http.ListenAndServe(addr, nil); err != nil {
			log.Fatal("HTTP service error: " + err.Error())
		}
	}()

	// Starting the abort TLS (HTTPS) server
	sslAddr := *httpsAddr + ":" + strconv.Itoa(*httpsPort)
	l, err := net.Listen("tcp", sslAddr)
	if err != nil {
		log.Fatal("Abort TLS listen error: " + err.Error())
	}
	defer l.Close()
	for {
		conn, err := l.Accept()
		if err != nil {
			log.Println("Abort TLS accept error: " + err.Error())
		}
		go AbortTLSListener(conn)
	}
}
<commit_msg>add concurrent-safe stat counters<commit_after>package main

import (
	"encoding/json"
	"flag"
	"log"
	"net"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"sync"
)

type SafeCounter struct {
	v   map[string]uint64
	mux sync.Mutex
}

var MaxAgeVal string
var Stats SafeCounter

func AbortTLSListener(conn net.Conn) {
	// This sends a TLS v1.2 alert packet regardless of query.
	// We respond the certificate authority (CA) that issued
	// the requesters certificate is unknown to us. This is possibly
	// the shortest response to a TLS (HTTPS) connection which
	// initiates a graceful shutdown on both ends.
	//
	// Note: This isn't TLS 1.3 compatible. Once browsers start
	//       deprecating 1.2 this will need to be overhauled. The
	//       1.3 specification is nothing like 1.2.
	//
	// The original idea came from h0tw1r3. Relevant projects:
	//  https://github.com/kvic-z/pixelserv-tls/wiki/Command-Line-Options
	//  https://github.com/h0tw1r3/pixelserv/blob/master/pixelserv.c
	conn.Write([]byte{
		'\x15',         // Alert protocol header (21)
		'\x03', '\x03', // TLS v1.2 (RFC 5246)
		'\x00', '\x02', // Message length (2)
		'\x02',  // Alert level fatal (2)
		'\x30'}) // Unknown Certificate Authority (48)
	conn.Close()

	Stats.mux.Lock()
	defer Stats.mux.Unlock()
	Stats.v["_transport_https"]++
}

func NullHandler(w http.ResponseWriter, r *http.Request) {
	u, _ := url.QueryUnescape(r.URL.String())

	// RFC 3986, Section 3 lists '?' as a query delimiter,
	// '#' as a fragment delimiter, and ';' as a sub-delimiter.
	// All three cannot be part of the path. Remove them.
	for _, value := range []string{"?", ";", "#"} {
		if strings.Contains(u, value) {
			u = strings.Split(u, value)[0]
		}
	}

	// Obtain the file suffix in the URI, if any.
	suffix := ""
	if idx := strings.LastIndex(u, "."); idx != -1 {
		suffix = u[idx+1 : len(u)]
	}

	// If this is an alternate suffix, replace with the real one.
	if realSuffix, ok := AltSuffix[suffix]; ok == true {
		suffix = realSuffix
	}

	Stats.mux.Lock()
	defer Stats.mux.Unlock()
	Stats.v["_transport_http"]++
	Stats.v[suffix]++

	// Special suffix "stats" emits stats about nullsrv as JSON.
	if suffix == "stats" {
		w.Header().Set("Cache-Control", "max-age=0")
		w.Header().Set("Content-Type", "application/json")
		json, err := json.MarshalIndent(Stats.v, "", "    ")
		if err != nil {
			w.Write([]byte("{}"))
		} else {
			w.Write(json)
		}
		return
	}

	// These are suffixes where we return 404, not found.
	if _, ok := NotFoundFiles[suffix]; ok == true {
		http.NotFound(w, r)
		return
	}

	// Fetch the null file for this suffix. Use HTML as the default case.
	f, ok := NullFiles[suffix]
	if ok != true {
		f = NullFiles["html"]
	}
	w.Header().Set("Cache-Control", MaxAgeVal)
	w.Header().Set("Content-Type", f.content)
	if f.data != nil {
		w.Write(f.data)
	}
}

func main() {
	// Parse command line arguments
	httpAddr := flag.String("a", "", "http address (default '' = all)")
	httpPort := flag.Int("p", 80, "http port")
	httpsAddr := flag.String("A", "", "https address (default '' = all)")
	httpsPort := flag.Int("P", 443, "https port")
	maxAge := flag.Int("m", 31536000, "content cache age in secs")
	flag.Parse()

	// Initialize globals
	MaxAgeVal = "public, max-age=" + strconv.Itoa(*maxAge)
	Stats = SafeCounter{v: make(map[string]uint64)}

	// Starting HTTP server
	addr := *httpAddr + ":" + strconv.Itoa(*httpPort)
	http.HandleFunc("/", NullHandler)
	go func() {
		if err := http.ListenAndServe(addr, nil); err != nil {
			log.Fatal("HTTP service error: " + err.Error())
		}
	}()

	// Starting the abort TLS (HTTPS) server
	sslAddr := *httpsAddr + ":" + strconv.Itoa(*httpsPort)
	l, err := net.Listen("tcp", sslAddr)
	if err != nil {
		log.Fatal("Abort TLS listen error: " + err.Error())
	}
	defer l.Close()
	for {
		conn, err := l.Accept()
		if err != nil {
			log.Println("Abort TLS accept error: " + err.Error())
		}
		go AbortTLSListener(conn)
	}
}
<|endoftext|>