<commit_before>package envconf

import (
	"fmt"
	"reflect"
	"runtime"
)

// StdListSeparator is default list separator.
// It can be changed only by NewConfig add SetListSeparator call.
var StdListSeparator = ","

var std = &Config{"", StdListSeparator, &decoder{StdListSeparator}}

// SetValues sets config value based on enviroment variable.
func SetValues(v interface{}) error {
	return std.SetValues(v)
}

// Config for process config reading from envrioment variables.
type Config struct {
	prefix    string
	separator string

	d *decoder
}

// NewConfig creates new config with given prefix.
// The PREFIX_ will be add to every enviroment variable name.
func NewConfig(prefix string) *Config {
	return &Config{
		prefix,
		StdListSeparator,
		&decoder{StdListSeparator},
	}
}

// SetListSeparator changes the list separator.
func (c *Config) SetListSeparator(separator string) {
	c.separator = separator
	c.d.separator = separator
}

// SetValues sets config value based on enviroment variable.
func (c *Config) SetValues(v interface{}) (err error) {

	defer func() {
		if r := recover(); r != nil {
			if _, ok := r.(runtime.Error); ok {
				panic(r)
			}
			err = r.(error)
		}
	}()

	rv := reflect.ValueOf(v)
	if err := c.isValidValue(rv); err != nil {
		return err
	}
	rv = rv.Elem()
	tv := rv.Type()

	for i := 0; i < rv.NumField(); i++ {
		tagval := tv.Field(i).Tag.Get("envconf")
		if tagval == "" {
			continue
		}

		t, err := newTag(c, tagval, tv.Field(i).Type)
		if err != nil {
			return fmt.Errorf("envconf: field %s %s", tv.Field(i).Name, err)
		}

		if err := c.d.decode(rv.Field(i), t.value); err != nil {
			return fmt.Errorf("envconf: field %s %s", tv.Field(i).Name, err)
		}
	}
	return nil
}

func (c *Config) isValidValue(v reflect.Value) error {
	if v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Struct || v.IsNil() {
		if v.Type() == nil {
			return fmt.Errorf("envconf: nil")
		}

		if v.Type().Kind() != reflect.Ptr {
			return fmt.Errorf("envconf: non-pointer %s", v.Type())
		}
		if v.Type().Kind() != reflect.Struct {
			return fmt.Errorf("envconf: non-struct %s", v.Type())
		}
		return fmt.Errorf("envconf: nil %s", v.Type())
	}
	return nil
}
<commit_msg>Fix typo in godocs<commit_after>package envconf

import (
	"fmt"
	"reflect"
	"runtime"
)

// StdListSeparator is default list separator.
// It can be changed only by NewConfig add SetListSeparator call.
var StdListSeparator = ","

var std = &Config{"", StdListSeparator, &decoder{StdListSeparator}}

// SetValues sets config value based on environment variable.
func SetValues(v interface{}) error {
	return std.SetValues(v)
}

// Config for process config reading from envrioment variables.
type Config struct {
	prefix    string
	separator string

	d *decoder
}

// NewConfig creates new config with given prefix.
// The PREFIX_ will be add to every environment variable name.
func NewConfig(prefix string) *Config {
	return &Config{
		prefix,
		StdListSeparator,
		&decoder{StdListSeparator},
	}
}

// SetListSeparator changes the list separator.
func (c *Config) SetListSeparator(separator string) {
	c.separator = separator
	c.d.separator = separator
}

// SetValues sets config value based on environment variable.
func (c *Config) SetValues(v interface{}) (err error) {

	defer func() {
		if r := recover(); r != nil {
			if _, ok := r.(runtime.Error); ok {
				panic(r)
			}
			err = r.(error)
		}
	}()

	rv := reflect.ValueOf(v)
	if err := c.isValidValue(rv); err != nil {
		return err
	}
	rv = rv.Elem()
	tv := rv.Type()

	for i := 0; i < rv.NumField(); i++ {
		tagval := tv.Field(i).Tag.Get("envconf")
		if tagval == "" {
			continue
		}

		t, err := newTag(c, tagval, tv.Field(i).Type)
		if err != nil {
			return fmt.Errorf("envconf: field %s %s", tv.Field(i).Name, err)
		}

		if err := c.d.decode(rv.Field(i), t.value); err != nil {
			return fmt.Errorf("envconf: field %s %s", tv.Field(i).Name, err)
		}
	}
	return nil
}

func (c *Config) isValidValue(v reflect.Value) error {
	if v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Struct || v.IsNil() {
		if v.Type() == nil {
			return fmt.Errorf("envconf: nil")
		}

		if v.Type().Kind() != reflect.Ptr {
			return fmt.Errorf("envconf: non-pointer %s", v.Type())
		}
		if v.Type().Kind() != reflect.Struct {
			return fmt.Errorf("envconf: non-struct %s", v.Type())
		}
		return fmt.Errorf("envconf: nil %s", v.Type())
	}
	return nil
}
<|endoftext|>


<commit_before>package presilo

import (
  "fmt"
  "bytes"
  "strings"
)

/*
  Generates valid Go code for a given schema.
*/
func GenerateGo(schema *ObjectSchema, module string) string {

  var ret bytes.Buffer

  ret.WriteString("package " + module)
  ret.WriteString("\n")
  ret.WriteString(generateGoImports(schema))
  ret.WriteString("\n")
  ret.WriteString(generateGoTypeDeclaration(schema))
  ret.WriteString("\n")
  ret.WriteString(generateGoConstructor(schema))
  ret.WriteString("\n")
  ret.WriteString(generateGoFunctions(schema))
  ret.WriteString("\n")

  return ret.String()
}

func generateGoImports(schema *ObjectSchema) string {

    var ret bytes.Buffer
    return ret.String()
}

func generateGoTypeDeclaration(schema *ObjectSchema) string {

    var ret bytes.Buffer
    var subschema TypeSchema
    var propertyName string
    var isRequired bool

    ret.WriteString("type ")
    ret.WriteString(schema.GetTitle())
    ret.WriteString(" struct {\n")

    // write all required fields as unexported fields.
    for _, propertyName = range schema.RequiredProperties {

      subschema = schema.Properties[propertyName]

      ret.WriteString(generateVariableDeclaration(subschema, propertyName, ToCamelCase))
    }

    // write all non-required fields as exported fields.
    for propertyName, subschema = range schema.Properties {

      isRequired = false

      for _, requiredName := range schema.RequiredProperties {
        if(requiredName == propertyName) {
          isRequired = true
          break
        }
      }

      if(isRequired) {
        continue
      }

      ret.WriteString(generateVariableDeclaration(subschema, propertyName, ToJavaCase))
    }

    ret.WriteString("}\n")
    return ret.String()
}

func generateGoFunctions(schema *ObjectSchema) string {

    var ret bytes.Buffer
    return ret.String()
}

func generateGoConstructor(schema *ObjectSchema) string {

  var subschema TypeSchema
  var ret bytes.Buffer
  var parameters, parameterNames []string
  var title, signature, parameterDefinition string

  for _, propertyName := range schema.RequiredProperties {

    subschema = schema.Properties[propertyName]
    propertyName = ToJavaCase(propertyName)

    ret.WriteString(propertyName)
    ret.WriteString(" ")
    ret.WriteString(generateGoTypeForSchema(subschema))

    parameterNames = append(parameterNames, propertyName)
    parameters = append(parameters, ret.String())
    ret.Reset()

  }

  // signature
  title = ToCamelCase(schema.Title)
  signature = fmt.Sprintf("func New%s(%s)(*%s) {\n", title, strings.Join(parameters, ","), title)
  ret.WriteString(signature)

  // body
  parameterDefinition = fmt.Sprintf("\tret := new(%s)\n", title)
  ret.WriteString(parameterDefinition)

  for _, propertyName := range parameterNames {

    parameterDefinition = fmt.Sprintf("\tret.%s = %s\n", propertyName, propertyName)
    ret.WriteString(parameterDefinition)
  }

  ret.WriteString("\treturn ret\n}\n\n")
  return ret.String()
}

func generateGoIntegerFunctions(schema *IntegerSchema) string {

  var ret bytes.Buffer

  if(!schema.HasConstraints()) {
    return ""
  }

  if(schema.Minimum != nil) {

  }

  return ret.String()
}

func generateGoStringFunctions(schema *StringSchema) string {

  var ret bytes.Buffer

  return ret.String()
}

func generateGoTypeForSchema(schema TypeSchema) string {

  switch schema.GetSchemaType() {
  case SCHEMATYPE_STRING:
    return "string"
  case SCHEMATYPE_INTEGER:
    return "int"
  case SCHEMATYPE_OBJECT:
    return "*" + ToCamelCase(schema.GetTitle())
  }

  return "interface{}"
}

func generateVariableDeclaration(subschema TypeSchema, propertyName string, casing func(string)(string)) (string) {

  var structTag string
  var ret bytes.Buffer

  structTag = fmt.Sprintf(" `json:\"%s\";`", ToJavaCase(propertyName))

  // TODO: this means unexported fields will have json deserialization struct tags,
  // which won't work.
  ret.WriteString("\tvar " + casing(propertyName) + " ")
  ret.WriteString(generateGoTypeForSchema(subschema))
  ret.WriteString(structTag)
  ret.WriteString("\n")

  return ret.String()
}
<commit_msg>Implemented golang getters<commit_after>package presilo

import (
  "fmt"
  "bytes"
  "strings"
)

/*
  Generates valid Go code for a given schema.
*/
func GenerateGo(schema *ObjectSchema, module string) string {

  var ret bytes.Buffer

  ret.WriteString("package " + module)
  ret.WriteString("\n")
  ret.WriteString(generateGoImports(schema))
  ret.WriteString("\n")
  ret.WriteString(generateGoTypeDeclaration(schema))
  ret.WriteString("\n")
  ret.WriteString(generateGoConstructor(schema))
  ret.WriteString("\n")
  ret.WriteString(generateGoFunctions(schema))
  ret.WriteString("\n")

  return ret.String()
}

func generateGoImports(schema *ObjectSchema) string {

    var ret bytes.Buffer
    return ret.String()
}

func generateGoTypeDeclaration(schema *ObjectSchema) string {

    var ret bytes.Buffer
    var subschema TypeSchema
    var propertyName string
    var isRequired bool

    ret.WriteString("type ")
    ret.WriteString(schema.GetTitle())
    ret.WriteString(" struct {\n")

    // write all required fields as unexported fields.
    for _, propertyName = range schema.RequiredProperties {

      subschema = schema.Properties[propertyName]

      ret.WriteString(generateVariableDeclaration(subschema, propertyName, ToJavaCase))
    }

    // write all non-required fields as exported fields.
    for propertyName, subschema = range schema.Properties {

      isRequired = false

      for _, requiredName := range schema.RequiredProperties {
        if(requiredName == propertyName) {
          isRequired = true
          break
        }
      }

      if(isRequired) {
        continue
      }

      ret.WriteString(generateVariableDeclaration(subschema, propertyName, ToCamelCase))
    }

    ret.WriteString("}\n")
    return ret.String()
}

func generateGoFunctions(schema *ObjectSchema) string {

    var ret bytes.Buffer
    var subschema TypeSchema
    var signature, body string
    var propertyName, casedJavaName, casedCamelName string

    for _, propertyName = range schema.RequiredProperties {

      casedJavaName = ToJavaCase(propertyName)
      casedCamelName = ToCamelCase(propertyName)

      subschema = schema.Properties[propertyName]

      signature = fmt.Sprintf("func (this *%s)Get%s()(%s){\n", schema.GetTitle(), casedCamelName, generateGoTypeForSchema(subschema))
      body = fmt.Sprintf("\treturn this.%s\n}\n\n", casedJavaName)

      ret.WriteString(signature)
      ret.WriteString(body)
    }

    return ret.String()
}

func generateGoConstructor(schema *ObjectSchema) string {

  var subschema TypeSchema
  var ret bytes.Buffer
  var parameters, parameterNames []string
  var title, signature, parameterDefinition string

  for _, propertyName := range schema.RequiredProperties {

    subschema = schema.Properties[propertyName]
    propertyName = ToJavaCase(propertyName)

    ret.WriteString(propertyName)
    ret.WriteString(" ")
    ret.WriteString(generateGoTypeForSchema(subschema))

    parameterNames = append(parameterNames, propertyName)
    parameters = append(parameters, ret.String())
    ret.Reset()

  }

  // signature
  title = ToCamelCase(schema.Title)
  signature = fmt.Sprintf("func New%s(%s)(*%s) {\n", title, strings.Join(parameters, ","), title)
  ret.WriteString(signature)

  // body
  parameterDefinition = fmt.Sprintf("\tret := new(%s)\n", title)
  ret.WriteString(parameterDefinition)

  for _, propertyName := range parameterNames {

    parameterDefinition = fmt.Sprintf("\tret.%s = %s\n", propertyName, propertyName)
    ret.WriteString(parameterDefinition)
  }

  ret.WriteString("\treturn ret\n}\n\n")
  return ret.String()
}

func generateGoIntegerFunctions(schema *IntegerSchema) string {

  var ret bytes.Buffer

  if(!schema.HasConstraints()) {
    return ""
  }

  if(schema.Minimum != nil) {

  }

  return ret.String()
}

func generateGoStringFunctions(schema *StringSchema) string {

  var ret bytes.Buffer

  return ret.String()
}

func generateGoTypeForSchema(schema TypeSchema) string {

  switch schema.GetSchemaType() {
  case SCHEMATYPE_STRING:
    return "string"
  case SCHEMATYPE_INTEGER:
    return "int"
  case SCHEMATYPE_OBJECT:
    return "*" + ToCamelCase(schema.GetTitle())
  }

  return "interface{}"
}

func generateVariableDeclaration(subschema TypeSchema, propertyName string, casing func(string)(string)) (string) {

  var structTag string
  var ret bytes.Buffer

  structTag = fmt.Sprintf(" `json:\"%s\";`", ToJavaCase(propertyName))

  // TODO: this means unexported fields will have json deserialization struct tags,
  // which won't work.
  ret.WriteString("\tvar " + casing(propertyName) + " ")
  ret.WriteString(generateGoTypeForSchema(subschema))
  ret.WriteString(structTag)
  ret.WriteString("\n")

  return ret.String()
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"syscall"

	gossh "github.com/coreos/fleet/third_party/code.google.com/p/go.crypto/ssh"
	"github.com/coreos/fleet/third_party/github.com/codegangsta/cli"

	"github.com/coreos/fleet/ssh"
)

func newJournalCommand() cli.Command {
	return cli.Command{
		Name:	"journal",
		Usage:	"Print the journal of a unit in the cluster to stdout",
		Action:	journalAction,
		Description: `Outputs the journal of a unit by connecting to the machine that the unit
occupies.

Read the last 10 lines:
fleetctl journal foo.service

Read the last 100 lines:
fleetctl journal --lines 100 foo.service`,
		Flags: []cli.Flag{
			cli.IntFlag{"lines, n", 10, "Number of recent log lines to return."},
		},
	}
}

func journalAction(c *cli.Context) {
	if len(c.Args()) != 1 {
		fmt.Println("One unit file must be provided.")
		syscall.Exit(1)
	}
	jobName := c.Args()[0]

	r := getRegistry()
	js := r.GetJobState(jobName)

	if js == nil {
		fmt.Printf("%s does not appear to be running\n", jobName)
		syscall.Exit(1)
	}

	addr := fmt.Sprintf("%s:22", js.MachineState.PublicIP)

	var err error
	var sshClient *gossh.ClientConn
	if tun := getTunnelFlag(); tun != "" {
		sshClient, err = ssh.NewTunnelledSSHClient("core", tun, addr)
	} else {
		sshClient, err = ssh.NewSSHClient("core", addr)
	}
	if err != nil {
		log.Fatal(err.Error())
	}

	defer sshClient.Close()

	cmd := fmt.Sprintf("journalctl -u %s --no-pager -l -n %d", jobName, c.Int("lines"))
	stdout, err := ssh.Execute(sshClient, cmd)
	if err != nil {
		log.Fatalf("Unable to run command over SSH: %s", err.Error())
	}

	for true {
		bytes, prefix, err := stdout.ReadLine()
		if err != nil {
			break
		}

		print(string(bytes))
		if !prefix {
			print("\n")
		}
	}
}
<commit_msg>feat(fleetctl/journal): Add flag -f to follow journal<commit_after>package main

import (
	"fmt"
	"log"
	"syscall"

	gossh "github.com/coreos/fleet/third_party/code.google.com/p/go.crypto/ssh"
	"github.com/coreos/fleet/third_party/github.com/codegangsta/cli"

	"github.com/coreos/fleet/ssh"
)

func newJournalCommand() cli.Command {
	return cli.Command{
		Name:	"journal",
		Usage:	"Print the journal of a unit in the cluster to stdout",
		Action:	journalAction,
		Description: `Outputs the journal of a unit by connecting to the machine that the unit
occupies.

Read the last 10 lines:
fleetctl journal foo.service

Read the last 100 lines:
fleetctl journal --lines 100 foo.service`,
		Flags: []cli.Flag{
			cli.IntFlag{"lines, n", 10, "Number of recent log lines to return."},
			cli.BoolFlag{"follow, f", "Continuously print new entries as they are appended to the journal."},
		},
	}
}

func journalAction(c *cli.Context) {
	if len(c.Args()) != 1 {
		fmt.Println("One unit file must be provided.")
		syscall.Exit(1)
	}
	jobName := c.Args()[0]

	r := getRegistry()
	js := r.GetJobState(jobName)

	if js == nil {
		fmt.Printf("%s does not appear to be running\n", jobName)
		syscall.Exit(1)
	}

	addr := fmt.Sprintf("%s:22", js.MachineState.PublicIP)

	var err error
	var sshClient *gossh.ClientConn
	if tun := getTunnelFlag(); tun != "" {
		sshClient, err = ssh.NewTunnelledSSHClient("core", tun, addr)
	} else {
		sshClient, err = ssh.NewSSHClient("core", addr)
	}
	if err != nil {
		log.Fatal(err.Error())
	}

	defer sshClient.Close()

	cmd := fmt.Sprintf("journalctl -u %s --no-pager -l -n %d", jobName, c.Int("lines"))
	if c.Bool("follow") {
		cmd += " -f"
	}
	stdout, err := ssh.Execute(sshClient, cmd)
	if err != nil {
		log.Fatalf("Unable to run command over SSH: %s", err.Error())
	}

	for true {
		bytes, prefix, err := stdout.ReadLine()
		if err != nil {
			break
		}

		print(string(bytes))
		if !prefix {
			print("\n")
		}
	}
}
<|endoftext|>


<commit_before>package vmClient

import (
	"encoding/xml"
)

type VMDeployment struct {
	XMLName   		xml.Name `xml:"Deployment"`
	Xmlns	  		string `xml:"xmlns,attr"`
	Name	  		string
	DeploymentSlot 	string
	Status 			string	`xml:",omitempty"`
	Label 			string
	Url 			string	`xml:",omitempty"`
	RoleList 		RoleList
}

type HostedServiceDeployment struct {
	XMLName   		xml.Name `xml:"CreateHostedService"`
	Xmlns	  		string `xml:"xmlns,attr"`
	ServiceName		string
	Label			string
	Description		string
	Location		string
}

type RoleList struct {
	Role	[]*Role
}

type Role struct {
	RoleName      				string
	RoleType	  				string
	ConfigurationSets			ConfigurationSets
	ResourceExtensionReferences ResourceExtensionReferences `xml:",omitempty"`
	OSVirtualHardDisk 			OSVirtualHardDisk
	RoleSize	  				string
	ProvisionGuestAgent			bool
	UseCertAuth 				bool `xml:"-"`
	CertPath 					string `xml:"-"`
}

type ConfigurationSets struct {
	ConfigurationSet []ConfigurationSet
}

type ResourceExtensionReferences struct {
	ResourceExtensionReference	[]ResourceExtensionReference
}

type InputEndpoints struct {
	InputEndpoint []InputEndpoint
}

type SubnetNames struct {
	SubnetName []SubnetName
}

type ResourceExtensionReference struct {
	ReferenceName						string
	Publisher							string
	Name								string
	Version								string
	ResourceExtensionParameterValues 	ResourceExtensionParameterValues `xml:",omitempty"`
	State								string
}

type ResourceExtensionParameterValues struct {
	ResourceExtensionParameterValue	[]ResourceExtensionParameter
}

type ResourceExtensionParameter struct {
	Key		    string
	Value		string
	Type		string
}

type OSVirtualHardDisk struct {
	MediaLink			string
	SourceImageName		string
	HostCaching			string	`xml:",omitempty"`
	DiskName			string	`xml:",omitempty"`
	OS					string	`xml:",omitempty"`
}

type ConfigurationSet struct {
	ConfigurationSetType				string
	HostName							string	`xml:",omitempty"`
	UserName							string	`xml:",omitempty"`
	UserPassword						string	`xml:",omitempty"`
	DisableSshPasswordAuthentication 	bool
	InputEndpoints						InputEndpoints	`xml:",omitempty"`
	SubnetNames							SubnetNames		`xml:",omitempty"`
	SSH									SSH		`xml:",omitempty"`
}

type SSH struct {
	PublicKeys PublicKeyList
}

type PublicKeyList struct {
	PublicKey []PublicKey
}

type PublicKey struct {
	Fingerprint			string
	Path				string
}

type InputEndpoint struct {
	LocalPort		int
	Name			string
	Port			int
	Protocol		string
	Vip				string
}

//!TODO
type SubnetName struct {
}

type ServiceCertificate struct {
	XMLName   			xml.Name `xml:"CertificateFile"`
	Xmlns	  			string `xml:"xmlns,attr"`
	Data				string
	CertificateFormat	string
	Password			string	`xml:",omitempty"`
}

type StartRoleOperation struct {
	Xmlns	  		string `xml:"xmlns,attr"`
	OperationType 	string
}

type ShutdownRoleOperation struct {
	Xmlns	  		string `xml:"xmlns,attr"`
	OperationType 	string
}

type RestartRoleOperation struct {
	Xmlns	  		string `xml:"xmlns,attr"`
	OperationType 	string
}
<commit_msg>Added RoleInstance entity to vmClient<commit_after>package vmClient

import (
	"encoding/xml"
)

type VMDeployment struct {
	XMLName   			xml.Name `xml:"Deployment"`
	Xmlns	  			string `xml:"xmlns,attr"`
	Name	  			string
	DeploymentSlot 		string
	Status 				string	`xml:",omitempty"`
	Label 				string
	Url 				string	`xml:",omitempty"`
	RoleList 			RoleList
	RoleInstanceList	RoleInstanceList `xml:",omitempty"`
}

type HostedServiceDeployment struct {
	XMLName   		xml.Name `xml:"CreateHostedService"`
	Xmlns	  		string `xml:"xmlns,attr"`
	ServiceName		string
	Label			string
	Description		string
	Location		string
}

type RoleList struct {
	Role	[]*Role
}

type RoleInstanceList struct {
	RoleInstance	[]*RoleInstance
}

type RoleInstance struct {
	RoleName		string
	InstanceName	string
	InstanceStatus  string
	InstanceSize	string
	PowerState		string
}

type Role struct {
	RoleName      				string
	RoleType	  				string
	ConfigurationSets			ConfigurationSets
	ResourceExtensionReferences ResourceExtensionReferences `xml:",omitempty"`
	OSVirtualHardDisk 			OSVirtualHardDisk
	RoleSize	  				string
	ProvisionGuestAgent			bool
	UseCertAuth 				bool `xml:"-"`
	CertPath 					string `xml:"-"`
}

type ConfigurationSets struct {
	ConfigurationSet []ConfigurationSet
}

type ResourceExtensionReferences struct {
	ResourceExtensionReference	[]ResourceExtensionReference
}

type InputEndpoints struct {
	InputEndpoint []InputEndpoint
}

type SubnetNames struct {
	SubnetName []SubnetName
}

type ResourceExtensionReference struct {
	ReferenceName						string
	Publisher							string
	Name								string
	Version								string
	ResourceExtensionParameterValues 	ResourceExtensionParameterValues `xml:",omitempty"`
	State								string
}

type ResourceExtensionParameterValues struct {
	ResourceExtensionParameterValue	[]ResourceExtensionParameter
}

type ResourceExtensionParameter struct {
	Key		    string
	Value		string
	Type		string
}

type OSVirtualHardDisk struct {
	MediaLink			string
	SourceImageName		string
	HostCaching			string	`xml:",omitempty"`
	DiskName			string	`xml:",omitempty"`
	OS					string	`xml:",omitempty"`
}

type ConfigurationSet struct {
	ConfigurationSetType				string
	HostName							string	`xml:",omitempty"`
	UserName							string	`xml:",omitempty"`
	UserPassword						string	`xml:",omitempty"`
	DisableSshPasswordAuthentication 	bool
	InputEndpoints						InputEndpoints	`xml:",omitempty"`
	SubnetNames							SubnetNames		`xml:",omitempty"`
	SSH									SSH		`xml:",omitempty"`
}

type SSH struct {
	PublicKeys PublicKeyList
}

type PublicKeyList struct {
	PublicKey []PublicKey
}

type PublicKey struct {
	Fingerprint			string
	Path				string
}

type InputEndpoint struct {
	LocalPort		int
	Name			string
	Port			int
	Protocol		string
	Vip				string
}

//!TODO
type SubnetName struct {
}

type ServiceCertificate struct {
	XMLName   			xml.Name `xml:"CertificateFile"`
	Xmlns	  			string `xml:"xmlns,attr"`
	Data				string
	CertificateFormat	string
	Password			string	`xml:",omitempty"`
}

type StartRoleOperation struct {
	Xmlns	  		string `xml:"xmlns,attr"`
	OperationType 	string
}

type ShutdownRoleOperation struct {
	Xmlns	  		string `xml:"xmlns,attr"`
	OperationType 	string
}

type RestartRoleOperation struct {
	Xmlns	  		string `xml:"xmlns,attr"`
	OperationType 	string
}
<|endoftext|>


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

package value

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/opentracing/opentracing-go"
	"github.com/shawnfeng/sutil/cache/redis"
	"github.com/shawnfeng/sutil/slog/slog"
	"time"
)

// key类型只支持int（包含有无符号，8，16，32，64位）和string
type LoadFunc func(key interface{}) (value interface{}, err error)

type Cache struct {
	namespace string
	prefix    string
	load      LoadFunc
	expire    time.Duration
}

func NewCache(namespace, prefix string, expire time.Duration, load LoadFunc) *Cache {
	return &Cache{
		namespace: namespace,
		prefix:    prefix,
		load:      load,
		expire:    expire,
	}
}

func (m *Cache) Get(ctx context.Context, key, value interface{}) error {
	fun := "Cache.Get -->"

	span, ctx := opentracing.StartSpanFromContext(ctx, "cache.value.Get")
	if span != nil {
		defer span.Finish()
	}

	err := m.getValueFromCache(ctx, key, value)
	if err == nil {
		return nil
	}
	if err != nil && err.Error() != redis.RedisNil {
		slog.Errorf(ctx, "%s cache key: %s err: %s", fun, key, err)
		return fmt.Errorf("%s cache key: %s err: %s", fun, key, err)
	}

	slog.Infof(ctx, "%s miss key: %v, err: %s", fun, key, err)

	err = m.loadValueToCache(ctx, key)
	if err != nil {
		slog.Errorf(ctx, "%s loadValueToCache key: %s err: %s", fun, key, err)
		return err
	}

	//简单处理interface对象构造的问题
	return m.getValueFromCache(ctx, key, value)
}

func (m *Cache) Del(ctx context.Context, key interface{}) error {
	fun := "Cache.Del -->"

	span, ctx := opentracing.StartSpanFromContext(ctx, "cache.value.Del")
	if span != nil {
		defer span.Finish()
	}

	skey, err := m.fixKey(key)
	if err != nil {
		slog.Errorf(ctx, "%s fixkey, key: %v err: %s", fun, key, err)
		return err
	}

	client := redis.DefaultInstanceManager.GetInstance(ctx, m.namespace)
	if client == nil {
		slog.Errorf(ctx, "%s get instance err, namespace: %s", fun, m.namespace)
		return fmt.Errorf("get instance err, namespace: %s", m.namespace)
	}

	err = client.Del(skey).Err()
	if err != nil {
		return fmt.Errorf("del cache key: %v err: %s", key, err.Error())
	}

	return nil
}

func (m *Cache) keyToString(key interface{}) (string, error) {
	switch t := key.(type) {
	case string:
		return t, nil
	case int8:
		return fmt.Sprintf("%d", key), nil
	case int16:
		return fmt.Sprintf("%d", key), nil
	case int32:
		return fmt.Sprintf("%d", key), nil
	case int64:
		return fmt.Sprintf("%d", key), nil
	case uint8:
		return fmt.Sprintf("%d", key), nil
	case uint16:
		return fmt.Sprintf("%d", key), nil
	case uint32:
		return fmt.Sprintf("%d", key), nil
	case uint64:
		return fmt.Sprintf("%d", key), nil
	case int:
		return fmt.Sprintf("%d", key), nil
	default:
		return "", errors.New("key err: unsupported type")
	}
}

func (m *Cache) fixKey(key interface{}) (string, error) {
	fun := "Cache.fixKey -->"

	skey, err := m.keyToString(key)
	if err != nil {
		slog.Errorf(context.TODO(), "%s key: %v err:%s", fun, key, err)
		return "", err
	}

	if len(m.prefix) > 0 {
		return fmt.Sprintf("%s.%s", m.prefix, skey), nil
	}

	return skey, nil
}

func (m *Cache) getValueFromCache(ctx context.Context, key, value interface{}) error {
	fun := "Cache.getValueFromCache -->"

	skey, err := m.fixKey(key)
	if err != nil {
		return err
	}

	client := redis.DefaultInstanceManager.GetInstance(ctx, m.namespace)
	if client == nil {
		slog.Errorf(ctx, "%s get instance err, namespace: %s", fun, m.namespace)
		return fmt.Errorf("get instance err, namespace: %s", m.namespace)
	}

	data, err := client.Get(skey).Bytes()
	if err != nil {
		return err
	}

	slog.Infof(ctx, "%s key: %v data: %s", fun, key, string(data))

	err = json.Unmarshal(data, value)
	if err != nil {
		return err
	}

	return nil
}

func (m *Cache) loadValueToCache(ctx context.Context, key interface{}) error {
	fun := "Cache.loadValueToCache -->"

	var data []byte
	value, err := m.load(key)
	if err != nil {
		slog.Warnf(ctx, "%s load err, cache key:%s err:%s", fun, key, err)
		data = []byte(err.Error())

	} else {
		data, err = json.Marshal(value)
		if err != nil {
			slog.Errorf(ctx, "%s marshal err, cache key: %s err:%s", fun, key, err)
			data = []byte(err.Error())
		}
	}

	skey, err := m.fixKey(key)
	if err != nil {
		slog.Errorf(ctx, "%s fixkey, key: %s err:%s", fun, key, err)
		return err
	}

	client := redis.DefaultInstanceManager.GetInstance(ctx, m.namespace)
	if client == nil {
		slog.Errorf(ctx, "%s get instance err, namespace: %s", fun, m.namespace)
		return fmt.Errorf("get instance err, namespace: %s", m.namespace)
	}

	rerr := client.Set(skey, data, m.expire*time.Second).Err()
	if rerr != nil {
		slog.Errorf(ctx, "%s set err, cache key: %v rerr: %s", fun, key, rerr)
	}

	if err != nil {
		return err
	}

	return rerr
}
<commit_msg>add span log to cache lib<commit_after>// Copyright 2014 The mqrouter Author. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package value

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/opentracing/opentracing-go"
	"github.com/opentracing/opentracing-go/log"
	"github.com/shawnfeng/sutil/cache/redis"
	"github.com/shawnfeng/sutil/slog/slog"
	"time"
)

const (
	spanLogKeyKey = "key"
)

// key类型只支持int（包含有无符号，8，16，32，64位）和string
type LoadFunc func(key interface{}) (value interface{}, err error)

type Cache struct {
	namespace string
	prefix    string
	load      LoadFunc
	expire    time.Duration
}

func NewCache(namespace, prefix string, expire time.Duration, load LoadFunc) *Cache {
	return &Cache{
		namespace: namespace,
		prefix:    prefix,
		load:      load,
		expire:    expire,
	}
}

func (m *Cache) Get(ctx context.Context, key, value interface{}) error {
	fun := "Cache.Get -->"

	span, ctx := opentracing.StartSpanFromContext(ctx, "cache.value.Get")
	defer span.Finish()
	if skey, err := m.fixKey(key); err != nil {
		span.LogFields(
			log.String(spanLogKeyKey, skey))
	}

	err := m.getValueFromCache(ctx, key, value)
	if err == nil {
		return nil
	}
	if err != nil && err.Error() != redis.RedisNil {
		slog.Errorf(ctx, "%s cache key: %s err: %s", fun, key, err)
		return fmt.Errorf("%s cache key: %s err: %s", fun, key, err)
	}

	slog.Infof(ctx, "%s miss key: %v, err: %s", fun, key, err)

	err = m.loadValueToCache(ctx, key)
	if err != nil {
		slog.Errorf(ctx, "%s loadValueToCache key: %s err: %s", fun, key, err)
		return err
	}

	//简单处理interface对象构造的问题
	return m.getValueFromCache(ctx, key, value)
}

func (m *Cache) Del(ctx context.Context, key interface{}) error {
	fun := "Cache.Del -->"

	span, ctx := opentracing.StartSpanFromContext(ctx, "cache.value.Del")
	defer span.Finish()

	skey, err := m.fixKey(key)
	if err != nil {
		slog.Errorf(ctx, "%s fixkey, key: %v err: %s", fun, key, err)
		return err
	}

	span.LogFields(log.String(spanLogKeyKey, skey))

	client := redis.DefaultInstanceManager.GetInstance(ctx, m.namespace)
	if client == nil {
		slog.Errorf(ctx, "%s get instance err, namespace: %s", fun, m.namespace)
		return fmt.Errorf("get instance err, namespace: %s", m.namespace)
	}

	err = client.Del(skey).Err()
	if err != nil {
		return fmt.Errorf("del cache key: %v err: %s", key, err.Error())
	}

	return nil
}

func (m *Cache) keyToString(key interface{}) (string, error) {
	switch t := key.(type) {
	case string:
		return t, nil
	case int8:
		return fmt.Sprintf("%d", key), nil
	case int16:
		return fmt.Sprintf("%d", key), nil
	case int32:
		return fmt.Sprintf("%d", key), nil
	case int64:
		return fmt.Sprintf("%d", key), nil
	case uint8:
		return fmt.Sprintf("%d", key), nil
	case uint16:
		return fmt.Sprintf("%d", key), nil
	case uint32:
		return fmt.Sprintf("%d", key), nil
	case uint64:
		return fmt.Sprintf("%d", key), nil
	case int:
		return fmt.Sprintf("%d", key), nil
	default:
		return "", errors.New("key err: unsupported type")
	}
}

func (m *Cache) fixKey(key interface{}) (string, error) {
	fun := "Cache.fixKey -->"

	skey, err := m.keyToString(key)
	if err != nil {
		slog.Errorf(context.TODO(), "%s key: %v err:%s", fun, key, err)
		return "", err
	}

	if len(m.prefix) > 0 {
		return fmt.Sprintf("%s.%s", m.prefix, skey), nil
	}

	return skey, nil
}

func (m *Cache) getValueFromCache(ctx context.Context, key, value interface{}) error {
	fun := "Cache.getValueFromCache -->"

	skey, err := m.fixKey(key)
	if err != nil {
		return err
	}

	client := redis.DefaultInstanceManager.GetInstance(ctx, m.namespace)
	if client == nil {
		slog.Errorf(ctx, "%s get instance err, namespace: %s", fun, m.namespace)
		return fmt.Errorf("get instance err, namespace: %s", m.namespace)
	}

	data, err := client.Get(skey).Bytes()
	if err != nil {
		return err
	}

	slog.Infof(ctx, "%s key: %v data: %s", fun, key, string(data))

	err = json.Unmarshal(data, value)
	if err != nil {
		return err
	}

	return nil
}

func (m *Cache) loadValueToCache(ctx context.Context, key interface{}) error {
	fun := "Cache.loadValueToCache -->"

	var data []byte
	value, err := m.load(key)
	if err != nil {
		slog.Warnf(ctx, "%s load err, cache key:%s err:%s", fun, key, err)
		data = []byte(err.Error())

	} else {
		data, err = json.Marshal(value)
		if err != nil {
			slog.Errorf(ctx, "%s marshal err, cache key: %s err:%s", fun, key, err)
			data = []byte(err.Error())
		}
	}

	skey, err := m.fixKey(key)
	if err != nil {
		slog.Errorf(ctx, "%s fixkey, key: %s err:%s", fun, key, err)
		return err
	}

	client := redis.DefaultInstanceManager.GetInstance(ctx, m.namespace)
	if client == nil {
		slog.Errorf(ctx, "%s get instance err, namespace: %s", fun, m.namespace)
		return fmt.Errorf("get instance err, namespace: %s", m.namespace)
	}

	rerr := client.Set(skey, data, m.expire*time.Second).Err()
	if rerr != nil {
		slog.Errorf(ctx, "%s set err, cache key: %v rerr: %s", fun, key, rerr)
	}

	if err != nil {
		return err
	}

	return rerr
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/workfit/tester/assert"
	"testing"
)

func TestEnumParent(t *testing.T) {
	tests := []struct {
		description string
		strValues   map[string]string
		//If nil, expect no change from strValues
		expectedValues  map[string]string
		expectedParents map[string]string
	}{
		{
			"Single layer",
			map[string]string{
				"Phase":         "",
				"PhaseAnother":  "Another",
				"PhaseOverride": "Heyo",
			},
			nil,
			map[string]string{
				"Phase":         "Phase",
				"PhaseAnother":  "Phase",
				"PhaseOverride": "Phase",
			},
		},
		{
			"No Tree",
			map[string]string{
				"ColorBlue":  "Blue",
				"ColorGreen": "Green",
				"ColorRed":   "Red",
			},
			nil,
			nil,
		},
		{
			"Two layers",
			map[string]string{
				"Color":          "",
				"ColorBlue":      "Blue",
				"ColorBlue_One":  "Blue > One",
				"ColorBlue_Two":  "Blue > Two",
				"ColorGreen":     "Green",
				"ColorGreen_One": "Green > One",
			},
			map[string]string{
				"Color":          "",
				"ColorBlue":      "Blue",
				"ColorBlue_One":  "One",
				"ColorBlue_Two":  "Two",
				"ColorGreen":     "Green",
				"ColorGreen_One": "One",
			},
			map[string]string{
				"Color":          "Color",
				"ColorBlue":      "Color",
				"ColorBlue_One":  "ColorBlue",
				"ColorBlue_Two":  "ColorBlue",
				"ColorGreen":     "Color",
				"ColorGreen_One": "ColorGreen",
			},
		},
		{
			"Three layers",
			map[string]string{
				"Color":             "",
				"ColorBlue":         "Blue",
				"ColorBlue_One":     "Blue > One",
				"ColorBlue_Two":     "Blue > Two",
				"ColorBlue_One_One": "Blue > One > One",
				"ColorBlue_One_Two": "Blue > One > Two",
			},
			map[string]string{
				"Color":             "",
				"ColorBlue":         "Blue",
				"ColorBlue_One":     "One",
				"ColorBlue_Two":     "Two",
				"ColorBlue_One_One": "One",
				"ColorBlue_One_Two": "Two",
			},
			map[string]string{
				"Color":             "Color",
				"ColorBlue":         "Color",
				"ColorBlue_One":     "ColorBlue",
				"ColorBlue_Two":     "ColorBlue",
				"ColorBlue_One_One": "ColorBlue_One",
				"ColorBlue_One_Two": "ColorBlue_One",
			},
		},
		{
			"Single implied layer",
			map[string]string{
				"Color":         "",
				"ColorBlue_One": "Blue > One",
			},
			map[string]string{
				"Color":                "",
				"-9223372036854775808": "Blue",
				"ColorBlue_One":        "One",
			},
			map[string]string{
				"Color":                "Color",
				"-9223372036854775808": "Color",
				"ColorBlue_One":        "-9223372036854775808",
			},
		},
		{
			"Two implied layers",
			map[string]string{
				"Color":            "",
				"ColorGreen_One_A": "Green > One > A",
			},
			map[string]string{
				"Color":                "",
				"-9223372036854775808": "Green",
				"-9223372036854775807": "One",
				"ColorGreen_One_A":     "A",
			},
			map[string]string{
				"Color":                "Color",
				"-9223372036854775808": "Color",
				"-9223372036854775807": "-9223372036854775808",
				"ColorGreen_One_A":     "-9223372036854775807",
			},
		},
		/*
			{
				"Single word implied nesting",
				map[string]string{
					"Color":        "",
					"ColorBlue":    "Blue",
					"ColorBlueOne": "Blue One",
					"ColorBlueTwo": "Blue Two",
				},
				map[string]string{
					"Color":        "",
					"ColorBlue":    "Blue",
					"ColorBlueOne": "Blue > One",
					"ColorBlueTwo": "Blue > Two",
				},
				map[string]string{
					"Color":        "Color",
					"ColorBlue":    "Color",
					"ColorBlueOne": "ColorBlue",
					"ColorBlueTwo": "ColorBlue",
				},
			},
			{
				"Multi-Word implied nesting",
				map[string]string{
					"Color":             "",
					"ColorBlueGreen":    "Blue Green",
					"ColorBlueGreenOne": "Blue Green One",
					"ColorBlueGreenTwo": "Blue Green Two",
				},
				map[string]string{
					"Color":             "",
					"ColorBlueGreen":    "Blue Green",
					"ColorBlueGreenOne": "Blue Green > One",
					"ColorBlueGreenTwo": "Blue Green > Two",
				},
				map[string]string{
					"Color":             "Color",
					"ColorBlueGreen":    "Color",
					"ColorBlueGreenOne": "ColorBlueGreen",
					"ColorBlueGreenTwo": "ColorBlueGreen",
				},
			},
			{
				"Implied node with implied nesting",
				map[string]string{
					"Color":             "",
					"ColorBlueGreenOne": "Blue Green One",
					"ColorBlueGreenTwo": "Blue Green Two",
				},
				map[string]string{
					"Color":                "",
					"-9223372036854775808": "Blue Green",
					"ColorBlueGreenOne":    "Blue Green > One",
					"ColorBlueGreenTwo":    "Blue Green > Two",
				},
				map[string]string{
					"Color":                "Color",
					"-9223372036854775808": "Color",
					"ColorBlueGreenOne":    "-9223372036854775808",
					"ColorBlueGreenTwo":    "-9223372036854775808",
				},
			},
			{
				"Multiple implied layers",
				map[string]string{
					"Color":              "",
					"ColorBlueGreen":     "Blue Green",
					"ColorBlueGreenOne":  "Blue Green One",
					"ColorBlueGreenOneA": "Blue Green One A",
					"ColorBlueGreenOneB": "Blue Green One B",
					"ColorBlueGreenTwo":  "Blue Green Two",
				},
				map[string]string{
					"Color":              "",
					"ColorBlueGreen":     "Blue Green",
					"ColorBlueGreenOne":  "Blue Green > One",
					"ColorBlueGreenOneA": "Blue Green > One > A",
					"ColorBlueGreenOneB": "Blue Green > One > B",
					"ColorBlueGreenTwo":  "Blue Green > Two",
				},
				map[string]string{
					"Color":              "Color",
					"ColorBlueGreen":     "Color",
					"ColorBlueGreenOne":  "ColorBlueGreen",
					"ColorBlueGreenOneA": "ColorBlueGreenOne",
					"ColorBlueGreenOneB": "ColorBlueGreenOne",
					"ColorBlueGreenTwo":  "ColorBlueGreen",
				},
			},
			{
				"Multiple implied layers with implied node",
				map[string]string{
					"Color":              "",
					"ColorBlueGreen":     "Blue Green",
					"ColorBlueGreenOneA": "Blue Green One A",
					"ColorBlueGreenOneB": "Blue Green One B",
					"ColorBlueGreenTwo":  "Blue Green Two",
				},
				map[string]string{
					"Color":                "",
					"ColorBlueGreen":       "Blue Green",
					"-9223372036854775808": "Blue Green > One",
					"ColorBlueGreenOneA":   "Blue Green > One > A",
					"ColorBlueGreenOneB":   "Blue Green > One > B",
					"ColorBlueGreenTwo":    "Blue Green > Two",
				},
				map[string]string{
					"Color":                "Color",
					"ColorBlueGreen":       "Color",
					"-9223372036854775808": "ColorBlueGreen",
					"ColorBlueGreenOneA":   "-9223372036854775808",
					"ColorBlueGreenOneB":   "-9223372036854775808",
					"ColorBlueGreenTwo":    "ColorBlueGreen",
				},
			},
			{
				"Mix implicit and explicit layers",
				map[string]string{
					"Color":               "",
					"ColorBlueGreen":      "Blue Green",
					"ColorBlueGreenOne":   "Blue Green One",
					"ColorBlueGreenOne_A": "Blue Green One > A",
					"ColorBlueGreenOne_B": "Blue Green One > B",
					"ColorBlueGreenTwo":   "Blue Green Two",
				},
				map[string]string{
					"Color":              "",
					"ColorBlueGreen":     "Blue Green",
					"ColorBlueGreenOne":  "Blue Green > One",
					"ColorBlueGreenOneA": "Blue Green > One > A",
					"ColorBlueGreenOneB": "Blue Green > One > B",
					"ColorBlueGreenTwo":  "Blue Green > Two",
				},
				map[string]string{
					"Color":              "Color",
					"ColorBlueGreen":     "Color",
					"ColorBlueGreenOne":  "ColorBlueGreen",
					"ColorBlueGreenOneA": "ColorBlueGreenOne",
					"ColorBlueGreenOneB": "ColorBlueGreenOne",
					"ColorBlueGreenTwo":  "ColorBlueGreen",
				},
			},
		*/
	}

	for i, test := range tests {

		e := newEnum("test", transformNone)

		for key, val := range test.strValues {
			e.AddTransformKey(key, true, val, transformNone)
		}

		err := e.Process()
		assert.For(t, i).ThatActual(err).IsNil()

		actualValues := e.ValueMap()
		actualParents := e.Parents()
		if test.expectedValues == nil {
			//Expect no change from test.strValues
			assert.For(t, i).ThatActual(actualValues).Equals(test.strValues).ThenDiffOnFail()
		} else {
			assert.For(t, i).ThatActual(actualValues).Equals(test.expectedValues).ThenDiffOnFail()
		}
		assert.For(t, i).ThatActual(actualParents).Equals(test.expectedParents).ThenDiffOnFail()
	}
}
<commit_msg>Enable another test that works (fix it because test expectations was wrong). part of #628.<commit_after>package main

import (
	"github.com/workfit/tester/assert"
	"testing"
)

func TestEnumParent(t *testing.T) {
	tests := []struct {
		description string
		strValues   map[string]string
		//If nil, expect no change from strValues
		expectedValues  map[string]string
		expectedParents map[string]string
	}{
		{
			"Single layer",
			map[string]string{
				"Phase":         "",
				"PhaseAnother":  "Another",
				"PhaseOverride": "Heyo",
			},
			nil,
			map[string]string{
				"Phase":         "Phase",
				"PhaseAnother":  "Phase",
				"PhaseOverride": "Phase",
			},
		},
		{
			"No Tree",
			map[string]string{
				"ColorBlue":  "Blue",
				"ColorGreen": "Green",
				"ColorRed":   "Red",
			},
			nil,
			nil,
		},
		{
			"Two layers",
			map[string]string{
				"Color":          "",
				"ColorBlue":      "Blue",
				"ColorBlue_One":  "Blue > One",
				"ColorBlue_Two":  "Blue > Two",
				"ColorGreen":     "Green",
				"ColorGreen_One": "Green > One",
			},
			map[string]string{
				"Color":          "",
				"ColorBlue":      "Blue",
				"ColorBlue_One":  "One",
				"ColorBlue_Two":  "Two",
				"ColorGreen":     "Green",
				"ColorGreen_One": "One",
			},
			map[string]string{
				"Color":          "Color",
				"ColorBlue":      "Color",
				"ColorBlue_One":  "ColorBlue",
				"ColorBlue_Two":  "ColorBlue",
				"ColorGreen":     "Color",
				"ColorGreen_One": "ColorGreen",
			},
		},
		{
			"Three layers",
			map[string]string{
				"Color":             "",
				"ColorBlue":         "Blue",
				"ColorBlue_One":     "Blue > One",
				"ColorBlue_Two":     "Blue > Two",
				"ColorBlue_One_One": "Blue > One > One",
				"ColorBlue_One_Two": "Blue > One > Two",
			},
			map[string]string{
				"Color":             "",
				"ColorBlue":         "Blue",
				"ColorBlue_One":     "One",
				"ColorBlue_Two":     "Two",
				"ColorBlue_One_One": "One",
				"ColorBlue_One_Two": "Two",
			},
			map[string]string{
				"Color":             "Color",
				"ColorBlue":         "Color",
				"ColorBlue_One":     "ColorBlue",
				"ColorBlue_Two":     "ColorBlue",
				"ColorBlue_One_One": "ColorBlue_One",
				"ColorBlue_One_Two": "ColorBlue_One",
			},
		},
		{
			"Single implied layer",
			map[string]string{
				"Color":         "",
				"ColorBlue_One": "Blue > One",
			},
			map[string]string{
				"Color":                "",
				"-9223372036854775808": "Blue",
				"ColorBlue_One":        "One",
			},
			map[string]string{
				"Color":                "Color",
				"-9223372036854775808": "Color",
				"ColorBlue_One":        "-9223372036854775808",
			},
		},
		{
			"Two implied layers",
			map[string]string{
				"Color":            "",
				"ColorGreen_One_A": "Green > One > A",
			},
			map[string]string{
				"Color":                "",
				"-9223372036854775808": "Green",
				"-9223372036854775807": "One",
				"ColorGreen_One_A":     "A",
			},
			map[string]string{
				"Color":                "Color",
				"-9223372036854775808": "Color",
				"-9223372036854775807": "-9223372036854775808",
				"ColorGreen_One_A":     "-9223372036854775807",
			},
		},
		{
			"Single word implied nesting",
			map[string]string{
				"Color":        "",
				"ColorBlue":    "Blue",
				"ColorBlueOne": "Blue One",
				"ColorBlueTwo": "Blue Two",
			},
			map[string]string{
				"Color":        "",
				"ColorBlue":    "Blue",
				"ColorBlueOne": "One",
				"ColorBlueTwo": "Two",
			},
			map[string]string{
				"Color":        "Color",
				"ColorBlue":    "Color",
				"ColorBlueOne": "ColorBlue",
				"ColorBlueTwo": "ColorBlue",
			},
		},
		/*
			{
				"Multi-Word implied nesting",
				map[string]string{
					"Color":             "",
					"ColorBlueGreen":    "Blue Green",
					"ColorBlueGreenOne": "Blue Green One",
					"ColorBlueGreenTwo": "Blue Green Two",
				},
				map[string]string{
					"Color":             "",
					"ColorBlueGreen":    "Blue Green",
					"ColorBlueGreenOne": "Blue Green > One",
					"ColorBlueGreenTwo": "Blue Green > Two",
				},
				map[string]string{
					"Color":             "Color",
					"ColorBlueGreen":    "Color",
					"ColorBlueGreenOne": "ColorBlueGreen",
					"ColorBlueGreenTwo": "ColorBlueGreen",
				},
			},
			{
				"Implied node with implied nesting",
				map[string]string{
					"Color":             "",
					"ColorBlueGreenOne": "Blue Green One",
					"ColorBlueGreenTwo": "Blue Green Two",
				},
				map[string]string{
					"Color":                "",
					"-9223372036854775808": "Blue Green",
					"ColorBlueGreenOne":    "Blue Green > One",
					"ColorBlueGreenTwo":    "Blue Green > Two",
				},
				map[string]string{
					"Color":                "Color",
					"-9223372036854775808": "Color",
					"ColorBlueGreenOne":    "-9223372036854775808",
					"ColorBlueGreenTwo":    "-9223372036854775808",
				},
			},
			{
				"Multiple implied layers",
				map[string]string{
					"Color":              "",
					"ColorBlueGreen":     "Blue Green",
					"ColorBlueGreenOne":  "Blue Green One",
					"ColorBlueGreenOneA": "Blue Green One A",
					"ColorBlueGreenOneB": "Blue Green One B",
					"ColorBlueGreenTwo":  "Blue Green Two",
				},
				map[string]string{
					"Color":              "",
					"ColorBlueGreen":     "Blue Green",
					"ColorBlueGreenOne":  "Blue Green > One",
					"ColorBlueGreenOneA": "Blue Green > One > A",
					"ColorBlueGreenOneB": "Blue Green > One > B",
					"ColorBlueGreenTwo":  "Blue Green > Two",
				},
				map[string]string{
					"Color":              "Color",
					"ColorBlueGreen":     "Color",
					"ColorBlueGreenOne":  "ColorBlueGreen",
					"ColorBlueGreenOneA": "ColorBlueGreenOne",
					"ColorBlueGreenOneB": "ColorBlueGreenOne",
					"ColorBlueGreenTwo":  "ColorBlueGreen",
				},
			},
			{
				"Multiple implied layers with implied node",
				map[string]string{
					"Color":              "",
					"ColorBlueGreen":     "Blue Green",
					"ColorBlueGreenOneA": "Blue Green One A",
					"ColorBlueGreenOneB": "Blue Green One B",
					"ColorBlueGreenTwo":  "Blue Green Two",
				},
				map[string]string{
					"Color":                "",
					"ColorBlueGreen":       "Blue Green",
					"-9223372036854775808": "Blue Green > One",
					"ColorBlueGreenOneA":   "Blue Green > One > A",
					"ColorBlueGreenOneB":   "Blue Green > One > B",
					"ColorBlueGreenTwo":    "Blue Green > Two",
				},
				map[string]string{
					"Color":                "Color",
					"ColorBlueGreen":       "Color",
					"-9223372036854775808": "ColorBlueGreen",
					"ColorBlueGreenOneA":   "-9223372036854775808",
					"ColorBlueGreenOneB":   "-9223372036854775808",
					"ColorBlueGreenTwo":    "ColorBlueGreen",
				},
			},
			{
				"Mix implicit and explicit layers",
				map[string]string{
					"Color":               "",
					"ColorBlueGreen":      "Blue Green",
					"ColorBlueGreenOne":   "Blue Green One",
					"ColorBlueGreenOne_A": "Blue Green One > A",
					"ColorBlueGreenOne_B": "Blue Green One > B",
					"ColorBlueGreenTwo":   "Blue Green Two",
				},
				map[string]string{
					"Color":              "",
					"ColorBlueGreen":     "Blue Green",
					"ColorBlueGreenOne":  "Blue Green > One",
					"ColorBlueGreenOneA": "Blue Green > One > A",
					"ColorBlueGreenOneB": "Blue Green > One > B",
					"ColorBlueGreenTwo":  "Blue Green > Two",
				},
				map[string]string{
					"Color":              "Color",
					"ColorBlueGreen":     "Color",
					"ColorBlueGreenOne":  "ColorBlueGreen",
					"ColorBlueGreenOneA": "ColorBlueGreenOne",
					"ColorBlueGreenOneB": "ColorBlueGreenOne",
					"ColorBlueGreenTwo":  "ColorBlueGreen",
				},
			},
		*/
	}

	for i, test := range tests {

		e := newEnum("test", transformNone)

		for key, val := range test.strValues {
			e.AddTransformKey(key, true, val, transformNone)
		}

		err := e.Process()
		assert.For(t, i).ThatActual(err).IsNil()

		actualValues := e.ValueMap()
		actualParents := e.Parents()
		if test.expectedValues == nil {
			//Expect no change from test.strValues
			assert.For(t, i).ThatActual(actualValues).Equals(test.strValues).ThenDiffOnFail()
		} else {
			assert.For(t, i).ThatActual(actualValues).Equals(test.expectedValues).ThenDiffOnFail()
		}
		assert.For(t, i).ThatActual(actualParents).Equals(test.expectedParents).ThenDiffOnFail()
	}
}
<|endoftext|>


<commit_before>package main

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

func BatteryInfo() (int, bool, error) {
	f, err := os.Open("/sys/class/power_supply/BAT0/uevent")
	if err != nil {
		return 0, false, err
	}
	defer f.Close()
	scanner := bufio.NewScanner(f)

	var full, now float64
	var present bool
	for scanner.Scan() {
		tokens := strings.SplitN(scanner.Text(), "=", 2)
		if len(tokens) != 2 {
			continue
		}
		switch tokens[0] {
		case "POWER_SUPPLY_ENERGY_FULL_DESIGN":
			full, _ = strconv.ParseFloat(tokens[1], 64)
		case "POWER_SUPPLY_ENERGY_NOW":
			now, _ = strconv.ParseFloat(tokens[1], 64)
		case "POWER_SUPPLY_STATUS":
			present = tokens[1] == "Full"
		}
	}
	return int(now/full) * 100, present, nil
}
<commit_msg>fix anytime display zero on linux<commit_after>package main

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

func BatteryInfo() (int, bool, error) {
	f, err := os.Open("/sys/class/power_supply/BAT0/uevent")
	if err != nil {
		return 0, false, err
	}
	defer f.Close()
	scanner := bufio.NewScanner(f)

	var full, now float64
	var present bool
	for scanner.Scan() {
		tokens := strings.SplitN(scanner.Text(), "=", 2)
		if len(tokens) != 2 {
			continue
		}
		switch tokens[0] {
		case "POWER_SUPPLY_ENERGY_FULL_DESIGN":
			full, _ = strconv.ParseFloat(tokens[1], 64)
		case "POWER_SUPPLY_ENERGY_NOW":
			now, _ = strconv.ParseFloat(tokens[1], 64)
		case "POWER_SUPPLY_STATUS":
			present = tokens[1] == "Full"
		}
	}
	return int(now / full * 100), present, nil
}
<|endoftext|>


<commit_before>package wincred

import (
	"bytes"
	"net/url"
	"strings"

	winc "github.com/danieljoos/wincred"
	"github.com/docker/docker-credential-helpers/credentials"
	"github.com/docker/docker-credential-helpers/registryurl"
)

// Wincred handles secrets using the Windows credential service.
type Wincred struct{}

// Add adds new credentials to the windows credentials manager.
func (h Wincred) Add(creds *credentials.Credentials) error {
	credsLabels := []byte(credentials.CredsLabel)
	g := winc.NewGenericCredential(creds.ServerURL)
	g.UserName = creds.Username
	g.CredentialBlob = []byte(creds.Secret)
	g.Persist = winc.PersistLocalMachine
	g.Attributes = []winc.CredentialAttribute{{Keyword: "label", Value: credsLabels}}

	return g.Write()
}

// Delete removes credentials from the windows credentials manager.
func (h Wincred) Delete(serverURL string) error {
	g, err := winc.GetGenericCredential(serverURL)
	if g == nil {
		return nil
	}
	if err != nil {
		return err
	}
	return g.Delete()
}

// Get retrieves credentials from the windows credentials manager.
func (h Wincred) Get(serverURL string) (string, string, error) {
	target, err := getTarget(serverURL)
	if err != nil {
		return "", "", err
	} else if target == "" {
		return "", "", credentials.NewErrCredentialsNotFound()
	}

	g, _ := winc.GetGenericCredential(target)
	if g == nil {
		return "", "", credentials.NewErrCredentialsNotFound()
	}

	for _, attr := range g.Attributes {
		if strings.Compare(attr.Keyword, "label") == 0 &&
			bytes.Compare(attr.Value, []byte(credentials.CredsLabel)) == 0 {

			return g.UserName, string(g.CredentialBlob), nil
		}
	}
	return "", "", credentials.NewErrCredentialsNotFound()
}

func getTarget(serverURL string) (string, error) {
	s, err := registryurl.Parse(serverURL)
	if err != nil {
		return serverURL, nil
	}

	creds, err := winc.List()
	if err != nil {
		return "", err
	}

	targets := make([]string, 0)
	for i := range creds {
		attrs := creds[i].Attributes
		for _, attr := range attrs {
			if strings.Compare(attr.Keyword, "label") == 0 &&
				bytes.Compare(attr.Value, []byte(credentials.CredsLabel)) == 0 {
				targets = append(targets, creds[i].TargetName)
			}
		}
	}

	if target, found := findMatch(s, targets, exactMatch); found {
		return target, nil
	}

	if target, found := findMatch(s, targets, approximateMatch); found {
		return target, nil
	}

	return "", nil
}

func findMatch(serverUrl *url.URL, targets []string, matches func(url.URL, url.URL) bool) (string, bool) {
	for _, target := range targets {
		tURL, err := registryurl.Parse(target)
		if err != nil {
			continue
		}
		if matches(*serverUrl, *tURL) {
			return target, true
		}
	}
	return "", false
}

func exactMatch(serverURL, target url.URL) bool {
	return serverURL.String() == target.String()
}

func approximateMatch(serverURL, target url.URL) bool {
	//if scheme is missing assume it is the same as target
	if serverURL.Scheme == "" {
		serverURL.Scheme = target.Scheme
	}
	//if port is missing assume it is the same as target
	if serverURL.Port() == "" && target.Port() != "" {
		serverURL.Host = serverURL.Host + ":" + target.Port()
	}
	//if path is missing assume it is the same as target
	if serverURL.Path == "" {
		serverURL.Path = target.Path
	}
	return serverURL.String() == target.String()
}

// List returns the stored URLs and corresponding usernames for a given credentials label.
func (h Wincred) List() (map[string]string, error) {
	creds, err := winc.List()
	if err != nil {
		return nil, err
	}

	resp := make(map[string]string)
	for i := range creds {
		attrs := creds[i].Attributes
		for _, attr := range attrs {
			if strings.Compare(attr.Keyword, "label") == 0 &&
				bytes.Compare(attr.Value, []byte(credentials.CredsLabel)) == 0 {

				resp[creds[i].TargetName] = creds[i].UserName
			}
		}

	}

	return resp, nil
}
<commit_msg>Style fixes - incorporates PR feedback<commit_after>package wincred

import (
	"bytes"
	"net/url"
	"strings"

	winc "github.com/danieljoos/wincred"
	"github.com/docker/docker-credential-helpers/credentials"
	"github.com/docker/docker-credential-helpers/registryurl"
)

// Wincred handles secrets using the Windows credential service.
type Wincred struct{}

// Add adds new credentials to the windows credentials manager.
func (h Wincred) Add(creds *credentials.Credentials) error {
	credsLabels := []byte(credentials.CredsLabel)
	g := winc.NewGenericCredential(creds.ServerURL)
	g.UserName = creds.Username
	g.CredentialBlob = []byte(creds.Secret)
	g.Persist = winc.PersistLocalMachine
	g.Attributes = []winc.CredentialAttribute{{Keyword: "label", Value: credsLabels}}

	return g.Write()
}

// Delete removes credentials from the windows credentials manager.
func (h Wincred) Delete(serverURL string) error {
	g, err := winc.GetGenericCredential(serverURL)
	if g == nil {
		return nil
	}
	if err != nil {
		return err
	}
	return g.Delete()
}

// Get retrieves credentials from the windows credentials manager.
func (h Wincred) Get(serverURL string) (string, string, error) {
	target, err := getTarget(serverURL)
	if err != nil {
		return "", "", err
	} else if target == "" {
		return "", "", credentials.NewErrCredentialsNotFound()
	}

	g, _ := winc.GetGenericCredential(target)
	if g == nil {
		return "", "", credentials.NewErrCredentialsNotFound()
	}

	for _, attr := range g.Attributes {
		if strings.Compare(attr.Keyword, "label") == 0 &&
			bytes.Compare(attr.Value, []byte(credentials.CredsLabel)) == 0 {

			return g.UserName, string(g.CredentialBlob), nil
		}
	}
	return "", "", credentials.NewErrCredentialsNotFound()
}

func getTarget(serverURL string) (string, error) {
	s, err := registryurl.Parse(serverURL)
	if err != nil {
		return serverURL, nil
	}

	creds, err := winc.List()
	if err != nil {
		return "", err
	}

	var targets []string
	for i := range creds {
		attrs := creds[i].Attributes
		for _, attr := range attrs {
			if attr.Keyword == "label" && bytes.Equal(attr.Value, []byte(credentials.CredsLabel)) {
				targets = append(targets, creds[i].TargetName)
			}
		}
	}

	if target, found := findMatch(s, targets, exactMatch); found {
		return target, nil
	}

	if target, found := findMatch(s, targets, approximateMatch); found {
		return target, nil
	}

	return "", nil
}

func findMatch(serverUrl *url.URL, targets []string, matches func(url.URL, url.URL) bool) (string, bool) {
	for _, target := range targets {
		tURL, err := registryurl.Parse(target)
		if err != nil {
			continue
		}
		if matches(*serverUrl, *tURL) {
			return target, true
		}
	}
	return "", false
}

func exactMatch(serverURL, target url.URL) bool {
	return serverURL.String() == target.String()
}

func approximateMatch(serverURL, target url.URL) bool {
	//if scheme is missing assume it is the same as target
	if serverURL.Scheme == "" {
		serverURL.Scheme = target.Scheme
	}
	//if port is missing assume it is the same as target
	if serverURL.Port() == "" && target.Port() != "" {
		serverURL.Host = serverURL.Host + ":" + target.Port()
	}
	//if path is missing assume it is the same as target
	if serverURL.Path == "" {
		serverURL.Path = target.Path
	}
	return serverURL.String() == target.String()
}

// List returns the stored URLs and corresponding usernames for a given credentials label.
func (h Wincred) List() (map[string]string, error) {
	creds, err := winc.List()
	if err != nil {
		return nil, err
	}

	resp := make(map[string]string)
	for i := range creds {
		attrs := creds[i].Attributes
		for _, attr := range attrs {
			if strings.Compare(attr.Keyword, "label") == 0 &&
				bytes.Compare(attr.Value, []byte(credentials.CredsLabel)) == 0 {

				resp[creds[i].TargetName] = creds[i].UserName
			}
		}

	}

	return resp, nil
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"strings"
	"testing"
)

func TestWriteManpage(t *testing.T) {
	table := []struct {
		src           string
		manpage       string
		want          string
		wantRefs      []string
		pkg           pkgEntry
		contentByPath map[string][]contentEntry
	}{
		{
			src:           "/usr/share/man/man1/noref.1",
			manpage:       "no ref in here\n",
			want:          "no ref in here\n",
			wantRefs:      nil,
			pkg:           pkgEntry{},
			contentByPath: make(map[string][]contentEntry),
		},

		{
			src:           "/usr/share/man/man1/unresolved.1",
			manpage:       ".so notfound.1\n",
			want:          ".so notfound.1\n",
			wantRefs:      nil,
			pkg:           pkgEntry{},
			contentByPath: make(map[string][]contentEntry),
		},

		{
			src:      "/usr/share/man/man1/samepkg.1",
			manpage:  ".so man1/samepkg.1\n",
			want:     ".so jessie/bash/samepkg.1.en.gz\n",
			wantRefs: nil,
			pkg: pkgEntry{
				binarypkg: "bash",
				suite:     "jessie",
			},
			contentByPath: map[string][]contentEntry{
				"/usr/share/man/man1/samepkg.1.gz": []contentEntry{
					{
						binarypkg: "bash",
						suite:     "jessie",
					},
				},
			},
		},

		{
			src:     "/usr/share/man/man1/samepkgaux.1",
			manpage: ".so man1/samepkgaux.inc\n",
			want:    ".so jessie/bash/aux/usr/share/man/man1/samepkgaux.inc.gz\n",
			wantRefs: []string{
				"/usr/share/man/man1/samepkgaux.inc.gz",
			},
			pkg: pkgEntry{
				binarypkg: "bash",
				suite:     "jessie",
			},
			contentByPath: map[string][]contentEntry{
				"/usr/share/man/man1/samepkgaux.inc.gz": []contentEntry{
					{
						binarypkg: "bash",
						suite:     "jessie",
					},
				},
			},
		},

		{
			src:     "/usr/share/man/man1/samedir.1",
			manpage: ".so samedir.inc\n",
			want:    ".so jessie/bash/aux/usr/share/man/man1/samedir.inc.gz\n",
			wantRefs: []string{
				"/usr/share/man/man1/samedir.inc.gz",
			},
			pkg: pkgEntry{
				binarypkg: "bash",
				suite:     "jessie",
			},
			contentByPath: map[string][]contentEntry{
				"/usr/share/man/man1/samedir.inc.gz": []contentEntry{
					{
						binarypkg: "bash",
						suite:     "jessie",
					},
				},
			},
		},

		// example for an absolute path: isdnutils-base/isdnctrl.8.en.gz uses .so /usr/share/man/man8/.isdnctrl_conf.8
		{
			src:      "/usr/share/man/man1/absolute.1",
			manpage:  ".so /usr/share/man/man8/absolute.8\n",
			want:     ".so jessie/extra/absolute.8.en.gz\n",
			wantRefs: nil,
			pkg: pkgEntry{
				binarypkg: "bash",
				suite:     "jessie",
			},
			contentByPath: map[string][]contentEntry{
				"/usr/share/man/man8/absolute.8.gz": []contentEntry{
					{
						binarypkg: "extra",
						suite:     "jessie",
					},
				},
			},
		},

		{
			src:      "/usr/share/man/man1/absolutenotfound.1",
			manpage:  ".so /usr/share/man/man8/absolute.8\n",
			want:     ".so /usr/share/man/man8/absolute.8\n",
			wantRefs: nil,
			pkg: pkgEntry{
				binarypkg: "bash",
				suite:     "jessie",
			},
			contentByPath: map[string][]contentEntry{},
		},

		{
			src:      "/usr/share/man/fr/man7/bash-builtins.7",
			manpage:  ".so man1/bash.1\n",
			want:     ".so jessie/manpages-fr-extra/bash.1.fr.gz\n",
			wantRefs: nil,
			pkg: pkgEntry{
				binarypkg: "manpages-fr-extra",
				suite:     "jessie",
			},
			contentByPath: map[string][]contentEntry{
				"/usr/share/man/man1/bash.1.gz": []contentEntry{
					{
						binarypkg: "bash",
						suite:     "jessie",
					},
				},
				"/usr/share/man/fr/man1/bash.1.gz": []contentEntry{
					{
						binarypkg: "manpages-fr-extra",
						suite:     "jessie",
					},
				},
			},
		},
	}
	for _, entry := range table {
		entry := entry // capture
		t.Run(entry.src, func(t *testing.T) {
			t.Parallel()

			r := strings.NewReader(entry.manpage)
			var buf bytes.Buffer
			refs, err := soElim(entry.src, r, &buf, entry.pkg, entry.contentByPath)
			if err != nil {
				t.Fatal(err)
			}
			if got, want := buf.String(), entry.want; got != want {
				t.Fatalf("Unexpected soElim() result: got %q, want %q", got, want)
			}
			if got, want := len(refs), len(entry.wantRefs); got != want {
				t.Fatalf("Unexpected number of soElim() ref results: got %d, want %d", got, want)
			}
			for i := 0; i < len(refs); i++ {
				if got, want := refs[i], entry.wantRefs[i]; got != want {
					t.Fatalf("soElim() ref differs in entry %d: got %q, want %q", i, got, want)
				}
			}
		})
	}
}
<commit_msg>download_test: fix for behavior change of commit 2d1dfc92<commit_after>package main

import (
	"bytes"
	"strings"
	"testing"
)

func TestWriteManpage(t *testing.T) {
	table := []struct {
		src           string
		manpage       string
		want          string
		wantRefs      []string
		pkg           pkgEntry
		contentByPath map[string][]contentEntry
	}{
		{
			src:           "/usr/share/man/man1/noref.1",
			manpage:       "no ref in here\n",
			want:          "no ref in here\n",
			wantRefs:      nil,
			pkg:           pkgEntry{},
			contentByPath: make(map[string][]contentEntry),
		},

		{
			src:           "/usr/share/man/man1/unresolved.1",
			manpage:       ".so notfound.1\n",
			want:          "",
			wantRefs:      nil,
			pkg:           pkgEntry{},
			contentByPath: make(map[string][]contentEntry),
		},

		{
			src:      "/usr/share/man/man1/samepkg.1",
			manpage:  ".so man1/samepkg.1\n",
			want:     ".so jessie/bash/samepkg.1.en.gz\n",
			wantRefs: nil,
			pkg: pkgEntry{
				binarypkg: "bash",
				suite:     "jessie",
			},
			contentByPath: map[string][]contentEntry{
				"/usr/share/man/man1/samepkg.1.gz": []contentEntry{
					{
						binarypkg: "bash",
						suite:     "jessie",
					},
				},
			},
		},

		{
			src:     "/usr/share/man/man1/samepkgaux.1",
			manpage: ".so man1/samepkgaux.inc\n",
			want:    ".so jessie/bash/aux/usr/share/man/man1/samepkgaux.inc.gz\n",
			wantRefs: []string{
				"/usr/share/man/man1/samepkgaux.inc.gz",
			},
			pkg: pkgEntry{
				binarypkg: "bash",
				suite:     "jessie",
			},
			contentByPath: map[string][]contentEntry{
				"/usr/share/man/man1/samepkgaux.inc.gz": []contentEntry{
					{
						binarypkg: "bash",
						suite:     "jessie",
					},
				},
			},
		},

		{
			src:     "/usr/share/man/man1/samedir.1",
			manpage: ".so samedir.inc\n",
			want:    ".so jessie/bash/aux/usr/share/man/man1/samedir.inc.gz\n",
			wantRefs: []string{
				"/usr/share/man/man1/samedir.inc.gz",
			},
			pkg: pkgEntry{
				binarypkg: "bash",
				suite:     "jessie",
			},
			contentByPath: map[string][]contentEntry{
				"/usr/share/man/man1/samedir.inc.gz": []contentEntry{
					{
						binarypkg: "bash",
						suite:     "jessie",
					},
				},
			},
		},

		// example for an absolute path: isdnutils-base/isdnctrl.8.en.gz uses .so /usr/share/man/man8/.isdnctrl_conf.8
		{
			src:      "/usr/share/man/man1/absolute.1",
			manpage:  ".so /usr/share/man/man8/absolute.8\n",
			want:     ".so jessie/extra/absolute.8.en.gz\n",
			wantRefs: nil,
			pkg: pkgEntry{
				binarypkg: "bash",
				suite:     "jessie",
			},
			contentByPath: map[string][]contentEntry{
				"/usr/share/man/man8/absolute.8.gz": []contentEntry{
					{
						binarypkg: "extra",
						suite:     "jessie",
					},
				},
			},
		},

		{
			src:      "/usr/share/man/man1/absolutenotfound.1",
			manpage:  ".so /usr/share/man/man8/absolute.8\n",
			want:     "",
			wantRefs: nil,
			pkg: pkgEntry{
				binarypkg: "bash",
				suite:     "jessie",
			},
			contentByPath: map[string][]contentEntry{},
		},

		{
			src:      "/usr/share/man/fr/man7/bash-builtins.7",
			manpage:  ".so man1/bash.1\n",
			want:     ".so jessie/manpages-fr-extra/bash.1.fr.gz\n",
			wantRefs: nil,
			pkg: pkgEntry{
				binarypkg: "manpages-fr-extra",
				suite:     "jessie",
			},
			contentByPath: map[string][]contentEntry{
				"/usr/share/man/man1/bash.1.gz": []contentEntry{
					{
						binarypkg: "bash",
						suite:     "jessie",
					},
				},
				"/usr/share/man/fr/man1/bash.1.gz": []contentEntry{
					{
						binarypkg: "manpages-fr-extra",
						suite:     "jessie",
					},
				},
			},
		},
	}
	for _, entry := range table {
		entry := entry // capture
		t.Run(entry.src, func(t *testing.T) {
			t.Parallel()

			r := strings.NewReader(entry.manpage)
			var buf bytes.Buffer
			refs, err := soElim(entry.src, r, &buf, entry.pkg, entry.contentByPath)
			if err != nil {
				t.Fatal(err)
			}
			if got, want := buf.String(), entry.want; got != want {
				t.Fatalf("Unexpected soElim() result: got %q, want %q", got, want)
			}
			if got, want := len(refs), len(entry.wantRefs); got != want {
				t.Fatalf("Unexpected number of soElim() ref results: got %d, want %d", got, want)
			}
			for i := 0; i < len(refs); i++ {
				if got, want := refs[i], entry.wantRefs[i]; got != want {
					t.Fatalf("soElim() ref differs in entry %d: got %q, want %q", i, got, want)
				}
			}
		})
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 The DER ASCII Authors. 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 main

import (
	"testing"

	"github.com/google/der-ascii/lib"
)

var isMadeOfElementsTests = []struct {
	in  []byte
	out bool
}{
	{[]byte{}, true},
	{[]byte{0x00, 0x00}, false},
	{[]byte{0x30, 0x00, 0x02, 0x01, 0x01}, true},
	{[]byte{0x30, 0x80, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00}, true},
	{[]byte{0x30, 0x80, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01}, false},
}

func TestIsMadeOfElements(t *testing.T) {
	for i, tt := range isMadeOfElementsTests {
		if out := isMadeOfElements(tt.in); out != tt.out {
			t.Errorf("%d. isMadeOfElements(%v) = %v, want %v.", i, tt.in, out, tt.out)
		}
	}
}

var tagToStringTests = []struct {
	in  lib.Tag
	out string
}{
	{lib.Tag{lib.ClassUniversal, 16, true}, "SEQUENCE"},
	{lib.Tag{lib.ClassUniversal, 16, false}, "[SEQUENCE PRIMITIVE]"},
	{lib.Tag{lib.ClassUniversal, 2, true}, "[INTEGER CONSTRUCTED]"},
	{lib.Tag{lib.ClassUniversal, 2, false}, "INTEGER"},
	{lib.Tag{lib.ClassUniversal, 1234, true}, "[UNIVERSAL 1234]"},
	{lib.Tag{lib.ClassContextSpecific, 0, true}, "[0]"},
	{lib.Tag{lib.ClassContextSpecific, 0, false}, "[0 PRIMITIVE]"},
	{lib.Tag{lib.ClassApplication, 0, true}, "[APPLICATION 0]"},
	{lib.Tag{lib.ClassApplication, 0, false}, "[APPLICATION 0 PRIMITIVE]"},
	{lib.Tag{lib.ClassPrivate, 0, true}, "[PRIVATE 0]"},
	{lib.Tag{lib.ClassPrivate, 0, false}, "[PRIVATE 0 PRIMITIVE]"},
}

func TestTagToString(t *testing.T) {
	for i, tt := range tagToStringTests {
		if out := tagToString(tt.in); out != tt.out {
			t.Errorf("%d. tagToString(%v) = %v, want %v.", i, tt.in, out, tt.out)
		}
	}

}

type convertFuncTest struct {
	in  []byte
	out string
}

func testConvertFunc(t *testing.T, name string, convertFunc func(in []byte) string, tests []convertFuncTest) {
	for i, tt := range tests {
		if out := convertFunc(tt.in); out != tt.out {
			t.Errorf("%d. %s(%v) = %v, want %v.", i, name, tt.in, out, tt.out)
		}
	}
}

var bytesToStringTests = []convertFuncTest{
	// Empty strings are empty.
	{nil, ""},
	// Mostly-ASCII strings are encoded in ASCII.
	{[]byte("hello\nworld\n\xff\"\\"), `"hello\nworld\n\xff\"\\"`},
	// Otherwise, encoded in hex.
	{[]byte{0x01, 0x02, 0x03, 0x04, 0x05}, "`0102030405`"},
}

func TestBytesToString(t *testing.T) {
	testConvertFunc(t, "bytesToString", bytesToString, bytesToStringTests)
}

var integerToStringTests = []convertFuncTest{
	// Valid and reasonably-sized integers are encoded as integers.
	{[]byte{42}, "42"},
	{[]byte{0xff}, "-1"},
	// Overly large integers are encoded in hex.
	{[]byte{0xff, 0xff, 0xff, 0xff}, "`ffffffff`"},
	{[]byte{0x00, 0xff, 0xff, 0xff, 0xff}, "`00ffffffff`"},
	// Invalid (non-minimal) integers are encoded in hex.
	{[]byte{0x00, 0x00}, "`0000`"},
}

func TestIntegerToString(t *testing.T) {
	testConvertFunc(t, "integerToString", integerToString, integerToStringTests)
}

var objectIdentifierToStringTests = []convertFuncTest{
	// Prefer to encode OIDs as OIDs.
	{[]byte{42, 3, 4, 5}, "1.2.3.4.5"},
	// Invalid OIDs are encoded in hex.
	{[]byte{0x80, 0x00}, "`8000`"},
}

func TestObjectIdentifierToString(t *testing.T) {
	testConvertFunc(t, "objectIdentifierToString", objectIdentifierToString, objectIdentifierToStringTests)
}

var derToASCIITests = []convertFuncTest{
	// Sample input that tests various difficult cases.
	{
		[]byte{0x30, 0x07, 0x67, 0x61, 0x72, 0x62, 0x61, 0x67, 0x65, 0x04, 0x0a, 0xa0, 0x80, 0x02, 0x01, 0x01, 0x02, 0x01, 0xff, 0x00, 0x00, 0x04, 0x0b, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x30, 0x16, 0xa0, 0x80, 0x02, 0x01, 0x01, 0x02, 0x02, 0x00, 0x00, 0x30, 0x80, 0x05, 0x00, 0x06, 0x03, 0x2a, 0x03, 0x04, 0x06, 0x02, 0x80, 0x00, 0x03, 0x03, 0x00, 0x30, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x03, 0x05, 0x01, 0x30, 0x80, 0x00, 0x00, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0xff, 0x01, 0x02, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff},
		`SEQUENCE {
  "garbage"
}
OCTET_STRING {
  [0] ` + "`80`" + `
    INTEGER { 1 }
    INTEGER { -1 }
  ` + "`0000`" + `
}
OCTET_STRING { "hello world" }
SEQUENCE {
  [0] ` + "`80`" + `
    INTEGER { 1 }
    INTEGER { ` + "`0000`" + ` }
    SEQUENCE ` + "`80`" + `
      NULL {}
      OBJECT_IDENTIFIER { 1.2.3.4 }
      OBJECT_IDENTIFIER { ` + "`8000`" + ` }
}
BIT_STRING {
  ` + "`00`" + `
  SEQUENCE {}
}
BIT_STRING { ` + "`000000`" + ` }
BIT_STRING { ` + "`0130800000`" + ` }
# sha256
OBJECT_IDENTIFIER { 2.16.840.1.101.3.4.2.1 }
BOOLEAN { FALSE }
BOOLEAN { TRUE }
BOOLEAN { ` + "`0000`" + ` }
` + "`ffffffff`" + `
`,
	},
}

func TestDERToASCII(t *testing.T) {
	testConvertFunc(t, "derToASCII", derToASCII, derToASCIITests)
}
<commit_msg>Split up der2ascii tests into several cases.<commit_after>// Copyright 2015 The DER ASCII Authors. 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 main

import (
	"testing"

	"github.com/google/der-ascii/lib"
)

var isMadeOfElementsTests = []struct {
	in  []byte
	out bool
}{
	{[]byte{}, true},
	{[]byte{0x00, 0x00}, false},
	{[]byte{0x30, 0x00, 0x02, 0x01, 0x01}, true},
	{[]byte{0x30, 0x80, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00}, true},
	{[]byte{0x30, 0x80, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01}, false},
}

func TestIsMadeOfElements(t *testing.T) {
	for i, tt := range isMadeOfElementsTests {
		if out := isMadeOfElements(tt.in); out != tt.out {
			t.Errorf("%d. isMadeOfElements(%v) = %v, want %v.", i, tt.in, out, tt.out)
		}
	}
}

var tagToStringTests = []struct {
	in  lib.Tag
	out string
}{
	{lib.Tag{lib.ClassUniversal, 16, true}, "SEQUENCE"},
	{lib.Tag{lib.ClassUniversal, 16, false}, "[SEQUENCE PRIMITIVE]"},
	{lib.Tag{lib.ClassUniversal, 2, true}, "[INTEGER CONSTRUCTED]"},
	{lib.Tag{lib.ClassUniversal, 2, false}, "INTEGER"},
	{lib.Tag{lib.ClassUniversal, 1234, true}, "[UNIVERSAL 1234]"},
	{lib.Tag{lib.ClassContextSpecific, 0, true}, "[0]"},
	{lib.Tag{lib.ClassContextSpecific, 0, false}, "[0 PRIMITIVE]"},
	{lib.Tag{lib.ClassApplication, 0, true}, "[APPLICATION 0]"},
	{lib.Tag{lib.ClassApplication, 0, false}, "[APPLICATION 0 PRIMITIVE]"},
	{lib.Tag{lib.ClassPrivate, 0, true}, "[PRIVATE 0]"},
	{lib.Tag{lib.ClassPrivate, 0, false}, "[PRIVATE 0 PRIMITIVE]"},
}

func TestTagToString(t *testing.T) {
	for i, tt := range tagToStringTests {
		if out := tagToString(tt.in); out != tt.out {
			t.Errorf("%d. tagToString(%v) = %v, want %v.", i, tt.in, out, tt.out)
		}
	}

}

type convertFuncTest struct {
	in  []byte
	out string
}

func testConvertFunc(t *testing.T, name string, convertFunc func(in []byte) string, tests []convertFuncTest) {
	for i, tt := range tests {
		if out := convertFunc(tt.in); out != tt.out {
			t.Errorf("%d. %s(%v) = %v, want %v.", i, name, tt.in, out, tt.out)
		}
	}
}

var bytesToStringTests = []convertFuncTest{
	// Empty strings are empty.
	{nil, ""},
	// Mostly-ASCII strings are encoded in ASCII.
	{[]byte("hello\nworld\n\xff\"\\"), `"hello\nworld\n\xff\"\\"`},
	// Otherwise, encoded in hex.
	{[]byte{0x01, 0x02, 0x03, 0x04, 0x05}, "`0102030405`"},
}

func TestBytesToString(t *testing.T) {
	testConvertFunc(t, "bytesToString", bytesToString, bytesToStringTests)
}

var integerToStringTests = []convertFuncTest{
	// Valid and reasonably-sized integers are encoded as integers.
	{[]byte{42}, "42"},
	{[]byte{0xff}, "-1"},
	// Overly large integers are encoded in hex.
	{[]byte{0xff, 0xff, 0xff, 0xff}, "`ffffffff`"},
	{[]byte{0x00, 0xff, 0xff, 0xff, 0xff}, "`00ffffffff`"},
	// Invalid (non-minimal) integers are encoded in hex.
	{[]byte{0x00, 0x00}, "`0000`"},
}

func TestIntegerToString(t *testing.T) {
	testConvertFunc(t, "integerToString", integerToString, integerToStringTests)
}

var objectIdentifierToStringTests = []convertFuncTest{
	// Prefer to encode OIDs as OIDs.
	{[]byte{42, 3, 4, 5}, "1.2.3.4.5"},
	// Invalid OIDs are encoded in hex.
	{[]byte{0x80, 0x00}, "`8000`"},
}

func TestObjectIdentifierToString(t *testing.T) {
	testConvertFunc(t, "objectIdentifierToString", objectIdentifierToString, objectIdentifierToStringTests)
}

var derToASCIITests = []convertFuncTest{
	// Test the X.509 BIT STRING heuristic.
	{
		[]byte{0x03, 0x03, 0x00, 0x30, 0x00},
		"BIT_STRING {\n  `00`\n  SEQUENCE {}\n}\n",
	},
	// BIT STRINGs are encoded normally if the contents are not an element.
	{
		[]byte{0x03, 0x03, 0x00, 0x00, 0x00},
		"BIT_STRING { `000000` }\n",
	},
	// BIT STRINGs are encoded normally if the leading byte is non-zero.
	{
		[]byte{0x03, 0x05, 0x01, 0x30, 0x80, 0x00, 0x00},
		"BIT_STRING { `0130800000` }\n",
	},
	// OBJECT IDENTIFIERs are pretty-printed if possible.
	{
		[]byte{0x06, 0x03, 0x2a, 0x03, 0x04},
		"OBJECT_IDENTIFIER { 1.2.3.4 }\n",
	},
	// OBJECT IDENTIFIERs have an identifying comment if known.
	{
		[]byte{0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01},
		"# sha256\nOBJECT_IDENTIFIER { 2.16.840.1.101.3.4.2.1 }\n",
	},
	// OBJECT IDENTIFIERs are hex-encoded if invalid.
	{
		[]byte{0x06, 0x02, 0x80, 0x00},
		"OBJECT_IDENTIFIER { `8000` }\n",
	},
	// TRUE and FALSE are detected in BOOLEANs.
	{
		[]byte{0x01, 0x01, 0x00},
		"BOOLEAN { FALSE }\n",
	},
	{
		[]byte{0x01, 0x01, 0xff},
		"BOOLEAN { TRUE }\n",
	},
	// Unrecognized BOOLEANs are hex-encoded.
	{
		[]byte{0x01, 0x02, 0x00, 0x00},
		"BOOLEAN { `0000` }\n",
	},
	{
		[]byte{0x01, 0x01, 0x42},
		"BOOLEAN { `42` }\n",
	},
	// By default, data is decoded as a string or hex literal depending on contents.
	{
		[]byte("\x04\x0bhello world"),
		"OCTET_STRING { \"hello world\" }\n",
	},
	{
		[]byte{0x04, 0x03, 0x01, 0x02, 0x03},
		"OCTET_STRING { `010203` }\n",
	},
	// Free-standing garbage is encoded directly.
	{
		[]byte("garbage"),
		"\"garbage\"\n",
	},
	{
		[]byte{0x01, 0x02, 0x03},
		"`010203`\n",
	},
	// Combined test of interesting cases around elements themselves.
	{
		[]byte{0x30, 0x07, 0x67, 0x61, 0x72, 0x62, 0x61, 0x67, 0x65, 0x04, 0x0a, 0xa0, 0x80, 0x02, 0x01, 0x01, 0x02, 0x01, 0xff, 0x00, 0x00, 0x04, 0x0b, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x30, 0x16, 0xa0, 0x80, 0x02, 0x01, 0x01, 0x02, 0x02, 0x00, 0x00, 0x30, 0x80, 0x05, 0x00, 0x06, 0x03, 0x2a, 0x03, 0x04, 0x06, 0x02, 0x80, 0x00, 0xff, 0xff, 0xff},
		`SEQUENCE {
  "garbage"
}
OCTET_STRING {
  [0] ` + "`80`" + `
    INTEGER { 1 }
    INTEGER { -1 }
  ` + "`0000`" + `
}
OCTET_STRING { "hello world" }
SEQUENCE {
  [0] ` + "`80`" + `
    INTEGER { 1 }
    INTEGER { ` + "`0000`" + ` }
    SEQUENCE ` + "`80`" + `
      NULL {}
      OBJECT_IDENTIFIER { 1.2.3.4 }
      OBJECT_IDENTIFIER { ` + "`8000`" + ` }
}
` + "`ffffff`\n",
	},
}

func TestDERToASCII(t *testing.T) {
	testConvertFunc(t, "derToASCII", derToASCII, derToASCIITests)
}
<|endoftext|>


<commit_before>package vendor

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
)

// RemoteRepo describes a remote dvcs repository.
type RemoteRepo interface {

	// Checkout checks out the specific branch and revision
	// If branch is empty, the default branch for the underlying
	// VCS will be used. If revision is empty, the latest available
	// revision, taking into account branch, will be fetched.
	Checkout(branch, revision string) (WorkingCopy, error)

	// URL returns the URL the clone was taken from. It should
	// only be called after Clone.
	URL() string
}

// WorkingCopy represents a local copy of a remote dvcs repository.
type WorkingCopy interface {

	// Dir is the root of this working copy.
	Dir() string

	// Revision returns the revision of this working copy.
	Revision() (string, error)

	// Branch returns the branch to which this working copy belongs.
	Branch() (string, error)

	// Destroy removes the working copy and cleans path to the working copy.
	Destroy() error
}

var (
	ghregex = regexp.MustCompile(`^github.com/([A-Za-z0-9-._]+)/([A-Za-z0-9-._]+)(/.+)?`)
	bbregex = regexp.MustCompile(`^bitbucket.org/([A-Za-z0-9-._]+)/([A-Za-z0-9-._]+)(/.+)?`)
	lpregex = regexp.MustCompile(`^launchpad.net/([A-Za-z0-9-._]+)(/[A-Za-z0-9-._]+)?(/.+)?`)
)

// DeduceRemoteRepo takes a potential import path and returns a RemoteRepo
// representing the remote location of the source of an import path.
func DeduceRemoteRepo(path string) (RemoteRepo, string, error) {
	validimport := regexp.MustCompile(`^([A-Za-z0-9-]+)(.[A-Za-z0-9-]+)+(/.[A-Za-z0-9-_.]+)+$`)
	if !validimport.MatchString(path) {
		return nil, "", fmt.Errorf("%q is not a valid import path", path)
	}

	switch {
	case ghregex.MatchString(path):
		v := ghregex.FindStringSubmatch(path)
		v = append(v, "")
		repo, err := Gitrepo(fmt.Sprintf("https://github.com/%s/%s", v[1], v[2]))
		return repo, v[3], err
	case bbregex.MatchString(path):
		v := bbregex.FindStringSubmatch(path)
		v = append(v, "")
		repo, err := Gitrepo(fmt.Sprintf("https://bitbucket.org/%s/%s", v[1], v[2]))
		if err == nil {
			return repo, v[3], nil
		}
		repo, err = Hgrepo(fmt.Sprintf("https://bitbucket.org/%s/%s", v[1], v[2]))
		if err == nil {
			return repo, v[3], nil
		}
		return nil, "", fmt.Errorf("unknown repository type")
	case lpregex.MatchString(path):
		v := lpregex.FindStringSubmatch(path)
		v = append(v, "", "")
		if v[2] == "" {
			// launchpad.net/project"
			repo, err := Bzrrepo(fmt.Sprintf("https://launchpad.net/%v", v[1]))
			return repo, "", err
		}
		// launchpad.net/project/series"
		repo, err := Bzrrepo(fmt.Sprintf("https://launchpad.net/%s/%s", v[1], v[2]))
		return repo, v[3], err
	default:
		// no idea, try to resolve as a vanity import
		importpath, vcs, reporoot, err := ParseMetadata(path)
		if err != nil {
			return nil, "", err
		}
		extra := path[len(importpath):]
		switch vcs {
		case "git":
			repo, err := Gitrepo(reporoot)
			return repo, extra, err
		case "hg":
			repo, err := Hgrepo(reporoot)
			return repo, extra, err
		case "bzr":
			repo, err := Bzrrepo(reporoot)
			return repo, extra, err
		default:
			return nil, "", fmt.Errorf("unknown repository type: %q", vcs)
		}
	}
}

// Gitrepo returns a RemoteRepo representing a remote git repository.
func Gitrepo(url string) (RemoteRepo, error) {
	if err := probeGitUrl(url); err != nil {
		return nil, err
	}
	return &gitrepo{
		url: url,
	}, nil
}

func probeGitUrl(url string) error {
	_, err := run("git", "ls-remote", "--exit-code", url, "HEAD")
	return err
}

// gitrepo is a git RemoteRepo.
type gitrepo struct {

	// remote repository url, see man 1 git-clone
	url string
}

func (g *gitrepo) URL() string {
	return g.url
}

func (g *gitrepo) Checkout(branch, revision string) (WorkingCopy, error) {
	dir, err := mktmp()
	if err != nil {
		return nil, err
	}

	args := []string{
		"clone",
		g.url,
		dir,
	}
	if branch != "" {
		args = append(args, "--branch", branch)
	}

	if err := runOut(os.Stderr, "git", args...); err != nil {
		os.RemoveAll(dir)
		return nil, err
	}

	return &GitClone{
		Path: dir,
	}, nil
}

// GitClone is a git WorkingCopy.
type GitClone struct {
	Path string
}

func (g *GitClone) Dir() string { return g.Path }

func (g *GitClone) Revision() (string, error) {
	rev, err := run("git", "-C", g.Path, "rev-parse", "HEAD")
	return strings.TrimSpace(string(rev)), err
}

func (g *GitClone) Branch() (string, error) {
	rev, err := run("git", "-C", g.Path, "rev-parse", "--abbrev-ref", "HEAD")
	return strings.TrimSpace(string(rev)), err
}

func (g *GitClone) Destroy() error {
	parent := filepath.Dir(g.Path)
	if err := os.RemoveAll(g.Path); err != nil {
		return err
	}
	return cleanPath(parent)
}

// Hgrepo returns a RemoteRepo representing a remote git repository.
func Hgrepo(url string) (RemoteRepo, error) {
	if err := probeHgUrl(url); err != nil {
		return nil, err
	}
	return &hgrepo{
		url: url,
	}, nil
}

func probeHgUrl(url string) error {
	_, err := run("hg", "identify", url)
	return err
}

// hgrepo is a Mercurial repo.
type hgrepo struct {

	// remote repository url, see man 1 hg
	url string
}

func (h *hgrepo) URL() string { return h.url }

func (h *hgrepo) Checkout(branch, revision string) (WorkingCopy, error) {
	dir, err := mktmp()
	if err != nil {
		return nil, err
	}
	args := []string{
		"clone",
		h.url,
		dir,
	}

	if branch != "" {
		args = append(args, "--branch", branch)
	}
	if err := runOut(os.Stderr, "hg", args...); err != nil {
		return nil, err
	}

	return &HgClone{
		Path: dir,
	}, nil
}

// HgClone is a mercurial WorkingCopy.
type HgClone struct {
	Path string
}

func (h *HgClone) Dir() string { return h.Path }

func (h *HgClone) Revision() (string, error) {
	rev, err := run("hg", "--cwd", h.Path, "id", "-i")
	return strings.TrimSpace(string(rev)), err
}

func (h *HgClone) Branch() (string, error) {
	rev, err := run("hg", "--cwd", h.Path, "branch")
	return strings.TrimSpace(string(rev)), err
}

func (h *HgClone) Destroy() error {
	parent := filepath.Dir(h.Path)
	if err := os.RemoveAll(h.Path); err != nil {
		return err
	}
	return cleanPath(parent)
}

// Bzrrepo returns a RemoteRepo representing a remote bzr repository.
func Bzrrepo(url string) (RemoteRepo, error) {
	if err := probeBzrUrl(url); err != nil {
		return nil, err
	}
	return &bzrrepo{
		url: url,
	}, nil
}

func probeBzrUrl(url string) error {
	_, err := run("bzr", "info", url)
	return err
}

// bzrrepo is a bzr RemoteRepo.
type bzrrepo struct {

	// remote repository url
	url string
}

func (b *bzrrepo) URL() string {
	return b.url
}

func (b *bzrrepo) Checkout(branch, revision string) (WorkingCopy, error) {
	dir, err := mktmp()
	if err != nil {
		return nil, err
	}
	dir = filepath.Join(dir, "wc")
	if err := runOut(os.Stderr, "bzr", "branch", b.url, dir); err != nil {
		os.RemoveAll(dir)
		return nil, err
	}

	return &BzrClone{
		Path: dir,
	}, nil
}

// BzrClone is a bazaar WorkingCopy.
type BzrClone struct {
	Path string
}

func (b *BzrClone) Dir() string { return b.Path }

func (b *BzrClone) Revision() (string, error) {
	return "1", nil
}

func (b *BzrClone) Branch() (string, error) {
	return "master", nil
}

func (b *BzrClone) Destroy() error {
	parent := filepath.Dir(b.Path)
	if err := os.RemoveAll(b.Path); err != nil {
		return err
	}
	return cleanPath(parent)
}

func cleanPath(path string) error {
	if files, _ := ioutil.ReadDir(path); len(files) > 0 || filepath.Base(path) == "src" {
		return nil
	}
	parent := filepath.Dir(path)
	if err := os.RemoveAll(path); err != nil {
		return err
	}
	return cleanPath(parent)
}

func mkdir(path string) error {
	return os.MkdirAll(path, 0755)
}

func mktmp() (string, error) {
	return ioutil.TempDir("", "gb-vendor-")
}

func run(c string, args ...string) ([]byte, error) {
	var buf bytes.Buffer
	err := runOut(&buf, c, args...)
	return buf.Bytes(), err
}

func runOut(w io.Writer, c string, args ...string) error {
	cmd := exec.Command(c, args...)
	cmd.Stdout = w
	cmd.Stderr = os.Stderr
	return cmd.Run()
}
<commit_msg>responding to review comments<commit_after>package vendor

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
)

// RemoteRepo describes a remote dvcs repository.
type RemoteRepo interface {

	// Checkout checks out the specific branch and revision
	// If branch is empty, the default branch for the underlying
	// VCS will be used. If revision is empty, the latest available
	// revision, taking into account branch, will be fetched.
	Checkout(branch, revision string) (WorkingCopy, error)

	// URL returns the URL the clone was taken from. It should
	// only be called after Clone.
	URL() string
}

// WorkingCopy represents a local copy of a remote dvcs repository.
type WorkingCopy interface {

	// Dir is the root of this working copy.
	Dir() string

	// Revision returns the revision of this working copy.
	Revision() (string, error)

	// Branch returns the branch to which this working copy belongs.
	Branch() (string, error)

	// Destroy removes the working copy and cleans path to the working copy.
	Destroy() error
}

var (
	ghregex = regexp.MustCompile(`^github.com/([A-Za-z0-9-._]+)/([A-Za-z0-9-._]+)(/.+)?`)
	bbregex = regexp.MustCompile(`^bitbucket.org/([A-Za-z0-9-._]+)/([A-Za-z0-9-._]+)(/.+)?`)
	lpregex = regexp.MustCompile(`^launchpad.net/([A-Za-z0-9-._]+)(/[A-Za-z0-9-._]+)?(/.+)?`)
)

// DeduceRemoteRepo takes a potential import path and returns a RemoteRepo
// representing the remote location of the source of an import path.
func DeduceRemoteRepo(path string) (RemoteRepo, string, error) {
	validimport := regexp.MustCompile(`^([A-Za-z0-9-]+)(.[A-Za-z0-9-]+)+(/.[A-Za-z0-9-_.]+)+$`)
	if !validimport.MatchString(path) {
		return nil, "", fmt.Errorf("%q is not a valid import path", path)
	}

	switch {
	case ghregex.MatchString(path):
		v := ghregex.FindStringSubmatch(path)
		v = append(v, "")
		repo, err := Gitrepo(fmt.Sprintf("https://github.com/%s/%s", v[1], v[2]))
		return repo, v[3], err
	case bbregex.MatchString(path):
		v := bbregex.FindStringSubmatch(path)
		v = append(v, "")
		repo, err := Gitrepo(fmt.Sprintf("https://bitbucket.org/%s/%s", v[1], v[2]))
		if err == nil {
			return repo, v[3], nil
		}
		repo, err = Hgrepo(fmt.Sprintf("https://bitbucket.org/%s/%s", v[1], v[2]))
		if err == nil {
			return repo, v[3], nil
		}
		return nil, "", fmt.Errorf("unknown repository type")
	case lpregex.MatchString(path):
		v := lpregex.FindStringSubmatch(path)
		v = append(v, "", "")
		if v[2] == "" {
			// launchpad.net/project"
			repo, err := Bzrrepo(fmt.Sprintf("https://launchpad.net/%v", v[1]))
			return repo, "", err
		}
		// launchpad.net/project/series"
		repo, err := Bzrrepo(fmt.Sprintf("https://launchpad.net/%s/%s", v[1], v[2]))
		return repo, v[3], err
	default:
		// no idea, try to resolve as a vanity import
		importpath, vcs, reporoot, err := ParseMetadata(path)
		if err != nil {
			return nil, "", err
		}
		extra := path[len(importpath):]
		switch vcs {
		case "git":
			repo, err := Gitrepo(reporoot)
			return repo, extra, err
		case "hg":
			repo, err := Hgrepo(reporoot)
			return repo, extra, err
		case "bzr":
			repo, err := Bzrrepo(reporoot)
			return repo, extra, err
		default:
			return nil, "", fmt.Errorf("unknown repository type: %q", vcs)
		}
	}
}

// Gitrepo returns a RemoteRepo representing a remote git repository.
func Gitrepo(url string) (RemoteRepo, error) {
	if err := probeGitUrl(url); err != nil {
		return nil, err
	}
	return &gitrepo{
		url: url,
	}, nil
}

func probeGitUrl(url string) error {
	_, err := run("git", "ls-remote", "--exit-code", url, "HEAD")
	return err
}

// gitrepo is a git RemoteRepo.
type gitrepo struct {

	// remote repository url, see man 1 git-clone
	url string
}

func (g *gitrepo) URL() string {
	return g.url
}

func (g *gitrepo) Checkout(branch, revision string) (WorkingCopy, error) {
	dir, err := mktmp()
	if err != nil {
		return nil, err
	}

	args := []string{
		"clone",
		g.url,
		dir,
		"--single-branch",
	}
	if branch != "" {
		args = append(args, "--branch", branch)
	}

	if err := runOut(os.Stderr, "git", args...); err != nil {
		os.RemoveAll(dir)
		return nil, err
	}

	if revision != "" {
		if err := runOut(os.Stderr, "git", "-C", dir, "checkout", revision); err != nil {
			os.RemoveAll(dir)
			return nil, err
		}
	}

	return &GitClone{
		Path: dir,
	}, nil
}

// GitClone is a git WorkingCopy.
type GitClone struct {
	Path string
}

func (g *GitClone) Dir() string { return g.Path }

func (g *GitClone) Revision() (string, error) {
	rev, err := run("git", "-C", g.Path, "rev-parse", "HEAD")
	return strings.TrimSpace(string(rev)), err
}

func (g *GitClone) Branch() (string, error) {
	rev, err := run("git", "-C", g.Path, "rev-parse", "--abbrev-ref", "HEAD")
	return strings.TrimSpace(string(rev)), err
}

func (g *GitClone) Destroy() error {
	parent := filepath.Dir(g.Path)
	if err := os.RemoveAll(g.Path); err != nil {
		return err
	}
	return cleanPath(parent)
}

// Hgrepo returns a RemoteRepo representing a remote git repository.
func Hgrepo(url string) (RemoteRepo, error) {
	if err := probeHgUrl(url); err != nil {
		return nil, err
	}
	return &hgrepo{
		url: url,
	}, nil
}

func probeHgUrl(url string) error {
	_, err := run("hg", "identify", url)
	return err
}

// hgrepo is a Mercurial repo.
type hgrepo struct {

	// remote repository url, see man 1 hg
	url string
}

func (h *hgrepo) URL() string { return h.url }

func (h *hgrepo) Checkout(branch, revision string) (WorkingCopy, error) {
	dir, err := mktmp()
	if err != nil {
		return nil, err
	}
	args := []string{
		"clone",
		h.url,
		dir,
	}

	if branch != "" {
		args = append(args, "--branch", branch)
	}
	if err := runOut(os.Stderr, "hg", args...); err != nil {
		os.RemoveAll(dir)
		return nil, err
	}
	if revision != "" {
		if err := runOut(os.Stderr, "hg", "--cwd", dir, "update", "-r", revision); err != nil {
			os.RemoveAll(dir)
			return nil, err
		}
	}

	return &HgClone{
		Path: dir,
	}, nil
}

// HgClone is a mercurial WorkingCopy.
type HgClone struct {
	Path string
}

func (h *HgClone) Dir() string { return h.Path }

func (h *HgClone) Revision() (string, error) {
	rev, err := run("hg", "--cwd", h.Path, "id", "-i")
	return strings.TrimSpace(string(rev)), err
}

func (h *HgClone) Branch() (string, error) {
	rev, err := run("hg", "--cwd", h.Path, "branch")
	return strings.TrimSpace(string(rev)), err
}

func (h *HgClone) Destroy() error {
	parent := filepath.Dir(h.Path)
	if err := os.RemoveAll(h.Path); err != nil {
		return err
	}
	return cleanPath(parent)
}

// Bzrrepo returns a RemoteRepo representing a remote bzr repository.
func Bzrrepo(url string) (RemoteRepo, error) {
	if err := probeBzrUrl(url); err != nil {
		return nil, err
	}
	return &bzrrepo{
		url: url,
	}, nil
}

func probeBzrUrl(url string) error {
	_, err := run("bzr", "info", url)
	return err
}

// bzrrepo is a bzr RemoteRepo.
type bzrrepo struct {

	// remote repository url
	url string
}

func (b *bzrrepo) URL() string {
	return b.url
}

func (b *bzrrepo) Checkout(branch, revision string) (WorkingCopy, error) {
	dir, err := mktmp()
	if err != nil {
		return nil, err
	}
	wc := filepath.Join(dir, "wc")
	if err := runOut(os.Stderr, "bzr", "branch", b.url, wc); err != nil {
		os.RemoveAll(dir)
		return nil, err
	}

	return &BzrClone{
		Path: wc,
	}, nil
}

// BzrClone is a bazaar WorkingCopy.
type BzrClone struct {
	Path string
}

func (b *BzrClone) Dir() string { return b.Path }

func (b *BzrClone) Revision() (string, error) {
	return "1", nil
}

func (b *BzrClone) Branch() (string, error) {
	return "master", nil
}

func (b *BzrClone) Destroy() error {
	parent := filepath.Dir(b.Path)
	if err := os.RemoveAll(b.Path); err != nil {
		return err
	}
	return cleanPath(parent)
}

func cleanPath(path string) error {
	if files, _ := ioutil.ReadDir(path); len(files) > 0 || filepath.Base(path) == "src" {
		return nil
	}
	parent := filepath.Dir(path)
	if err := os.RemoveAll(path); err != nil {
		return err
	}
	return cleanPath(parent)
}

func mkdir(path string) error {
	return os.MkdirAll(path, 0755)
}

func mktmp() (string, error) {
	return ioutil.TempDir("", "gb-vendor-")
}

func run(c string, args ...string) ([]byte, error) {
	var buf bytes.Buffer
	err := runOut(&buf, c, args...)
	return buf.Bytes(), err
}

func runOut(w io.Writer, c string, args ...string) error {
	cmd := exec.Command(c, args...)
	cmd.Stdout = w
	cmd.Stderr = os.Stderr
	return cmd.Run()
}
<|endoftext|>