<commit_before>package river

import (
	"flag"
	"fmt"
	"os"
	"testing"
	"time"

	"github.com/siddontang/go-mysql-elasticsearch/elastic"
	"github.com/siddontang/go-mysql/client"
	. "gopkg.in/check.v1"
)

var my_addr = flag.String("my_addr", "127.0.0.1:3306", "MySQL addr")
var es_addr = flag.String("es_addr", "127.0.0.1:9200", "Elasticsearch addr")

func Test(t *testing.T) {
	TestingT(t)
}

type riverTestSuite struct {
	c *client.Conn
	r *River
}

var _ = Suite(&riverTestSuite{})

func (s *riverTestSuite) SetUpSuite(c *C) {
	var err error
	s.c, err = client.Connect(*my_addr, "root", "", "test")
	c.Assert(err, IsNil)

	s.testExecute(c, "SET SESSION binlog_format = 'ROW'")

	schema := `
        CREATE TABLE IF NOT EXISTS %s (
            id INT,
            title VARCHAR(256),
            content VARCHAR(256),
            mylist VARCHAR(256),
            tenum ENUM("e1", "e2", "e3"),
            tset SET("a", "b", "c"),
            tbit BIT(1) default 1,
            PRIMARY KEY(id)) ENGINE=INNODB;
    `

	schema_json := `
	CREATE TABLE IF NOT EXISTS %s (
	    id INT,
	    info JSON,
	    PRIMARY KEY(id)) ENGINE=INNODB;
    `

	s.testExecute(c, "DROP TABLE IF EXISTS test_river")
	s.testExecute(c, "DROP TABLE IF EXISTS test_for_id")
	s.testExecute(c, "DROP TABLE IF EXISTS test_for_json")
	s.testExecute(c, fmt.Sprintf(schema, "test_river"))
	s.testExecute(c, fmt.Sprintf(schema, "test_for_id"))
	s.testExecute(c, fmt.Sprintf(schema_json, "test_for_json"))

	for i := 0; i < 10; i++ {
		table := fmt.Sprintf("test_river_%04d", i)
		s.testExecute(c, fmt.Sprintf("DROP TABLE IF EXISTS %s", table))
		s.testExecute(c, fmt.Sprintf(schema, table))
	}

	cfg := new(Config)
	cfg.MyAddr = *my_addr
	cfg.MyUser = "root"
	cfg.MyPassword = ""
	cfg.MyCharset = "utf8"
	cfg.ESAddr = *es_addr

	cfg.ServerID = 1001
	cfg.Flavor = "mysql"

	cfg.DataDir = "/tmp/test_river"
	cfg.DumpExec = "mysqldump"

	cfg.StatAddr = "127.0.0.1:12800"
	cfg.BulkSize = 1
	cfg.FlushBulkTime = TomlDuration{3 * time.Millisecond}

	os.RemoveAll(cfg.DataDir)

	cfg.Sources = []SourceConfig{SourceConfig{Schema: "test", Tables: []string{"test_river", "test_river_[0-9]{4}", "test_for_id", "test_for_json"}}}

	cfg.Rules = []*Rule{
		&Rule{Schema: "test",
			Table:        "test_river",
			Index:        "river",
			Type:         "river",
			FieldMapping: map[string]string{"title": "es_title", "mylist": "es_mylist,list"},
		},

		&Rule{Schema: "test",
			Table:        "test_for_id",
			Index:        "river",
			Type:         "river",
			ID:           []string{"id", "title"},
			FieldMapping: map[string]string{"title": "es_title", "mylist": "es_mylist,list"},
		},

		&Rule{Schema: "test",
			Table:        "test_river_[0-9]{4}",
			Index:        "river",
			Type:         "river",
			FieldMapping: map[string]string{"title": "es_title", "mylist": "es_mylist,list"},
		},

		&Rule{Schema: "test",
			Table:        "test_for_json",
			Index:        "river",
			Type:         "river",
		},
	}

	s.r, err = NewRiver(cfg)
	c.Assert(err, IsNil)

	err = s.r.es.DeleteIndex("river")
	c.Assert(err, IsNil)
}

func (s *riverTestSuite) TearDownSuite(c *C) {
	if s.c != nil {
		s.c.Close()
	}

	if s.r != nil {
		s.r.Close()
	}
}

func (s *riverTestSuite) TestConfig(c *C) {
	str := `
my_addr = "127.0.0.1:3306"
my_user = "root"
my_pass = ""
my_charset = "utf8"
es_addr = "127.0.0.1:9200"
es_user = ""
es_pass = ""
data_dir = "./var"

[[source]]
schema = "test"

tables = ["test_river", "test_river_[0-9]{4}", "test_for_id", "test_for_json"]

[[rule]]
schema = "test"
table = "test_river"
index = "river"
type = "river"
parent = "pid"

    [rule.field]
    title = "es_title"
    mylist = "es_mylist,list"

[[rule]]
schema = "test"
table = "test_for_id"
index = "river"
type = "river"
parent = "pid"
id = ["id", "title"]
    [rule.field]
    title = "es_title"
    mylist = "es_mylist,list"

[[rule]]
schema = "test"
table = "test_river_[0-9]{4}"
index = "river"
type = "river"

    [rule.field]
    title = "es_title"
    mylist = "es_mylist,list"

[[rule]]
schema = "test"
table = "test_for_json"
index = "river"
type = "river"
`

	cfg, err := NewConfig(str)
	c.Assert(err, IsNil)
	c.Assert(cfg.Sources, HasLen, 1)
	c.Assert(cfg.Sources[0].Tables, HasLen, 4)
	c.Assert(cfg.Rules, HasLen, 4)
}

func (s *riverTestSuite) testExecute(c *C, query string, args ...interface{}) {
	_, err := s.c.Execute(query, args...)
	c.Assert(err, IsNil)
}

func (s *riverTestSuite) testPrepareData(c *C) {
	s.testExecute(c, "INSERT INTO test_river (id, title, content, tenum, tset) VALUES (?, ?, ?, ?, ?)", 1, "first", "hello go 1", "e1", "a,b")
	s.testExecute(c, "INSERT INTO test_river (id, title, content, tenum, tset) VALUES (?, ?, ?, ?, ?)", 2, "second", "hello mysql 2", "e2", "b,c")
	s.testExecute(c, "INSERT INTO test_river (id, title, content, tenum, tset) VALUES (?, ?, ?, ?, ?)", 3, "third", "hello elaticsearch 3", "e3", "c")
	s.testExecute(c, "INSERT INTO test_river (id, title, content, tenum, tset, tbit) VALUES (?, ?, ?, ?, ?, ?)", 4, "fouth", "hello go-mysql-elasticserach 4", "e1", "a,b,c", 0)
	s.testExecute(c, "INSERT INTO test_for_id (id, title, content, tenum, tset) VALUES (?, ?, ?, ?, ?)", 1, "first", "hello go 1", "e1", "a,b")
	s.testExecute(c, "INSERT INTO test_for_json (id, info) VALUES (?, ?)", 9200, "{\"first\": \"a\", \"second\": \"b\"}")

	for i := 0; i < 10; i++ {
		table := fmt.Sprintf("test_river_%04d", i)
		s.testExecute(c, fmt.Sprintf("INSERT INTO %s (id, title, content, tenum, tset) VALUES (?, ?, ?, ?, ?)", table), 5+i, "abc", "hello", "e1", "a,b,c")
	}
}

func (s *riverTestSuite) testElasticGet(c *C, id string) *elastic.Response {
	index := "river"
	docType := "river"

	r, err := s.r.es.Get(index, docType, id)
	c.Assert(err, IsNil)

	return r
}

func testWaitSyncDone(c *C, r *River) {
	<-r.canal.WaitDumpDone()

	err := r.canal.CatchMasterPos(10 * time.Second)
	c.Assert(err, IsNil)

	for i := 0; i < 1000; i++ {
		if len(r.syncCh) == 0 {
			return
		}

		time.Sleep(10 * time.Millisecond)
	}

	c.Fatalf("wait 1s but still have %d items to be synced", len(r.syncCh))
}

func (s *riverTestSuite) TestRiver(c *C) {
	s.testPrepareData(c)

	s.r.Start()

	testWaitSyncDone(c, s.r)

	var r *elastic.Response
	r = s.testElasticGet(c, "1")
	c.Assert(r.Found, Equals, true)
	c.Assert(r.Source["tenum"], Equals, "e1")
	c.Assert(r.Source["tset"], Equals, "a,b")

	r = s.testElasticGet(c, "1:first")
	c.Assert(r.Found, Equals, true)

	r = s.testElasticGet(c, "9200")
	c.Assert(r.Found, Equals, true)
	switch v := r.Source["info"].(type) {
	case map[string]string:
	    	c.Assert(v["first"], Equals, "a")
	    	c.Assert(v["second"], Equals, "b")
	default:
		c.Assert(v, Equals, nil)
	    	c.Assert(true, Equals, false)
	}

	r = s.testElasticGet(c, "100")
	c.Assert(r.Found, Equals, false)

	for i := 0; i < 10; i++ {
		r = s.testElasticGet(c, fmt.Sprintf("%d", 5+i))
		c.Assert(r.Found, Equals, true)
		c.Assert(r.Source["es_title"], Equals, "abc")
	}

	s.testExecute(c, "UPDATE test_river SET title = ?, tenum = ?, tset = ?, mylist = ? WHERE id = ?", "second 2", "e3", "a,b,c", "a,b,c", 2)
	s.testExecute(c, "DELETE FROM test_river WHERE id = ?", 1)
	s.testExecute(c, "UPDATE test_river SET title = ?, id = ? WHERE id = ?", "second 30", 30, 3)

	// so we can insert invalid data
	s.testExecute(c, `SET SESSION sql_mode="NO_ENGINE_SUBSTITUTION";`)

	// bad insert
	s.testExecute(c, "UPDATE test_river SET title = ?, tenum = ?, tset = ? WHERE id = ?", "second 2", "e5", "a,b,c,d", 4)

	for i := 0; i < 10; i++ {
		table := fmt.Sprintf("test_river_%04d", i)
		s.testExecute(c, fmt.Sprintf("UPDATE %s SET title = ? WHERE id = ?", table), "hello", 5+i)
	}

	testWaitSyncDone(c, s.r)

	r = s.testElasticGet(c, "1")
	c.Assert(r.Found, Equals, false)

	r = s.testElasticGet(c, "2")
	c.Assert(r.Found, Equals, true)
	c.Assert(r.Source["es_title"], Equals, "second 2")
	c.Assert(r.Source["tenum"], Equals, "e3")
	c.Assert(r.Source["tset"], Equals, "a,b,c")
	c.Assert(r.Source["es_mylist"], DeepEquals, []interface{}{"a", "b", "c"})
	c.Assert(r.Source["tbit"], Equals, float64(1))

	r = s.testElasticGet(c, "4")
	c.Assert(r.Found, Equals, true)
	c.Assert(r.Source["tenum"], Equals, "")
	c.Assert(r.Source["tset"], Equals, "a,b,c")
	c.Assert(r.Source["tbit"], Equals, float64(0))

	r = s.testElasticGet(c, "3")
	c.Assert(r.Found, Equals, false)

	r = s.testElasticGet(c, "30")
	c.Assert(r.Found, Equals, true)
	c.Assert(r.Source["es_title"], Equals, "second 30")

	for i := 0; i < 10; i++ {
		r = s.testElasticGet(c, fmt.Sprintf("%d", 5+i))
		c.Assert(r.Found, Equals, true)
		c.Assert(r.Source["es_title"], Equals, "hello")
	}
}
<commit_msg>Update river_test.go<commit_after>package river

import (
	"flag"
	"fmt"
	"os"
	"testing"
	"time"

	"github.com/siddontang/go-mysql-elasticsearch/elastic"
	"github.com/siddontang/go-mysql/client"
	. "gopkg.in/check.v1"
)

var my_addr = flag.String("my_addr", "127.0.0.1:3306", "MySQL addr")
var es_addr = flag.String("es_addr", "127.0.0.1:9200", "Elasticsearch addr")

func Test(t *testing.T) {
	TestingT(t)
}

type riverTestSuite struct {
	c *client.Conn
	r *River
}

var _ = Suite(&riverTestSuite{})

func (s *riverTestSuite) SetUpSuite(c *C) {
	var err error
	s.c, err = client.Connect(*my_addr, "root", "", "test")
	c.Assert(err, IsNil)

	s.testExecute(c, "SET SESSION binlog_format = 'ROW'")

	schema := `
        CREATE TABLE IF NOT EXISTS %s (
            id INT,
            title VARCHAR(256),
            content VARCHAR(256),
            mylist VARCHAR(256),
            tenum ENUM("e1", "e2", "e3"),
            tset SET("a", "b", "c"),
            tbit BIT(1) default 1,
            PRIMARY KEY(id)) ENGINE=INNODB;
    `

	schema_json := `
	CREATE TABLE IF NOT EXISTS %s (
	    id INT,
	    info JSON,
	    PRIMARY KEY(id)) ENGINE=INNODB;
    `

	s.testExecute(c, "DROP TABLE IF EXISTS test_river")
	s.testExecute(c, "DROP TABLE IF EXISTS test_for_id")
	s.testExecute(c, "DROP TABLE IF EXISTS test_for_json")
	s.testExecute(c, fmt.Sprintf(schema, "test_river"))
	s.testExecute(c, fmt.Sprintf(schema, "test_for_id"))
	s.testExecute(c, fmt.Sprintf(schema_json, "test_for_json"))

	for i := 0; i < 10; i++ {
		table := fmt.Sprintf("test_river_%04d", i)
		s.testExecute(c, fmt.Sprintf("DROP TABLE IF EXISTS %s", table))
		s.testExecute(c, fmt.Sprintf(schema, table))
	}

	cfg := new(Config)
	cfg.MyAddr = *my_addr
	cfg.MyUser = "root"
	cfg.MyPassword = ""
	cfg.MyCharset = "utf8"
	cfg.ESAddr = *es_addr

	cfg.ServerID = 1001
	cfg.Flavor = "mysql"

	cfg.DataDir = "/tmp/test_river"
	cfg.DumpExec = "mysqldump"

	cfg.StatAddr = "127.0.0.1:12800"
	cfg.BulkSize = 1
	cfg.FlushBulkTime = TomlDuration{3 * time.Millisecond}

	os.RemoveAll(cfg.DataDir)

	cfg.Sources = []SourceConfig{SourceConfig{Schema: "test", Tables: []string{"test_river", "test_river_[0-9]{4}", "test_for_id", "test_for_json"}}}

	cfg.Rules = []*Rule{
		&Rule{Schema: "test",
			Table:        "test_river",
			Index:        "river",
			Type:         "river",
			FieldMapping: map[string]string{"title": "es_title", "mylist": "es_mylist,list"},
		},

		&Rule{Schema: "test",
			Table:        "test_for_id",
			Index:        "river",
			Type:         "river",
			ID:           []string{"id", "title"},
			FieldMapping: map[string]string{"title": "es_title", "mylist": "es_mylist,list"},
		},

		&Rule{Schema: "test",
			Table:        "test_river_[0-9]{4}",
			Index:        "river",
			Type:         "river",
			FieldMapping: map[string]string{"title": "es_title", "mylist": "es_mylist,list"},
		},

		&Rule{Schema: "test",
			Table:        "test_for_json",
			Index:        "river",
			Type:         "river",
		},
	}

	s.r, err = NewRiver(cfg)
	c.Assert(err, IsNil)

	err = s.r.es.DeleteIndex("river")
	c.Assert(err, IsNil)
}

func (s *riverTestSuite) TearDownSuite(c *C) {
	if s.c != nil {
		s.c.Close()
	}

	if s.r != nil {
		s.r.Close()
	}
}

func (s *riverTestSuite) TestConfig(c *C) {
	str := `
my_addr = "127.0.0.1:3306"
my_user = "root"
my_pass = ""
my_charset = "utf8"
es_addr = "127.0.0.1:9200"
es_user = ""
es_pass = ""
data_dir = "./var"

[[source]]
schema = "test"

tables = ["test_river", "test_river_[0-9]{4}", "test_for_id", "test_for_json"]

[[rule]]
schema = "test"
table = "test_river"
index = "river"
type = "river"
parent = "pid"

    [rule.field]
    title = "es_title"
    mylist = "es_mylist,list"

[[rule]]
schema = "test"
table = "test_for_id"
index = "river"
type = "river"
parent = "pid"
id = ["id", "title"]
    [rule.field]
    title = "es_title"
    mylist = "es_mylist,list"

[[rule]]
schema = "test"
table = "test_river_[0-9]{4}"
index = "river"
type = "river"

    [rule.field]
    title = "es_title"
    mylist = "es_mylist,list"

[[rule]]
schema = "test"
table = "test_for_json"
index = "river"
type = "river"
`

	cfg, err := NewConfig(str)
	c.Assert(err, IsNil)
	c.Assert(cfg.Sources, HasLen, 1)
	c.Assert(cfg.Sources[0].Tables, HasLen, 4)
	c.Assert(cfg.Rules, HasLen, 4)
}

func (s *riverTestSuite) testExecute(c *C, query string, args ...interface{}) {
	_, err := s.c.Execute(query, args...)
	c.Assert(err, IsNil)
}

func (s *riverTestSuite) testPrepareData(c *C) {
	s.testExecute(c, "INSERT INTO test_river (id, title, content, tenum, tset) VALUES (?, ?, ?, ?, ?)", 1, "first", "hello go 1", "e1", "a,b")
	s.testExecute(c, "INSERT INTO test_river (id, title, content, tenum, tset) VALUES (?, ?, ?, ?, ?)", 2, "second", "hello mysql 2", "e2", "b,c")
	s.testExecute(c, "INSERT INTO test_river (id, title, content, tenum, tset) VALUES (?, ?, ?, ?, ?)", 3, "third", "hello elaticsearch 3", "e3", "c")
	s.testExecute(c, "INSERT INTO test_river (id, title, content, tenum, tset, tbit) VALUES (?, ?, ?, ?, ?, ?)", 4, "fouth", "hello go-mysql-elasticserach 4", "e1", "a,b,c", 0)
	s.testExecute(c, "INSERT INTO test_for_id (id, title, content, tenum, tset) VALUES (?, ?, ?, ?, ?)", 1, "first", "hello go 1", "e1", "a,b")
	s.testExecute(c, "INSERT INTO test_for_json (id, info) VALUES (?, ?)", 9200, "{\"first\": \"a\", \"second\": \"b\"}")

	for i := 0; i < 10; i++ {
		table := fmt.Sprintf("test_river_%04d", i)
		s.testExecute(c, fmt.Sprintf("INSERT INTO %s (id, title, content, tenum, tset) VALUES (?, ?, ?, ?, ?)", table), 5+i, "abc", "hello", "e1", "a,b,c")
	}
}

func (s *riverTestSuite) testElasticGet(c *C, id string) *elastic.Response {
	index := "river"
	docType := "river"

	r, err := s.r.es.Get(index, docType, id)
	c.Assert(err, IsNil)

	return r
}

func testWaitSyncDone(c *C, r *River) {
	<-r.canal.WaitDumpDone()

	err := r.canal.CatchMasterPos(10 * time.Second)
	c.Assert(err, IsNil)

	for i := 0; i < 1000; i++ {
		if len(r.syncCh) == 0 {
			return
		}

		time.Sleep(10 * time.Millisecond)
	}

	c.Fatalf("wait 1s but still have %d items to be synced", len(r.syncCh))
}

func (s *riverTestSuite) TestRiver(c *C) {
	s.testPrepareData(c)

	s.r.Start()

	testWaitSyncDone(c, s.r)

	var r *elastic.Response
	r = s.testElasticGet(c, "1")
	c.Assert(r.Found, Equals, true)
	c.Assert(r.Source["tenum"], Equals, "e1")
	c.Assert(r.Source["tset"], Equals, "a,b")

	r = s.testElasticGet(c, "1:first")
	c.Assert(r.Found, Equals, true)

	r = s.testElasticGet(c, "9200")
	c.Assert(r.Found, Equals, true)
	switch v := r.Source["info"].(type) {
	case map[string]interface{}:
	    	c.Assert(v["first"], Equals, "a")
	    	c.Assert(v["second"], Equals, "b")
	default:
		c.Assert(v, Equals, nil)
	    	c.Assert(true, Equals, false)
	}

	r = s.testElasticGet(c, "100")
	c.Assert(r.Found, Equals, false)

	for i := 0; i < 10; i++ {
		r = s.testElasticGet(c, fmt.Sprintf("%d", 5+i))
		c.Assert(r.Found, Equals, true)
		c.Assert(r.Source["es_title"], Equals, "abc")
	}

	s.testExecute(c, "UPDATE test_river SET title = ?, tenum = ?, tset = ?, mylist = ? WHERE id = ?", "second 2", "e3", "a,b,c", "a,b,c", 2)
	s.testExecute(c, "DELETE FROM test_river WHERE id = ?", 1)
	s.testExecute(c, "UPDATE test_river SET title = ?, id = ? WHERE id = ?", "second 30", 30, 3)

	// so we can insert invalid data
	s.testExecute(c, `SET SESSION sql_mode="NO_ENGINE_SUBSTITUTION";`)

	// bad insert
	s.testExecute(c, "UPDATE test_river SET title = ?, tenum = ?, tset = ? WHERE id = ?", "second 2", "e5", "a,b,c,d", 4)

	for i := 0; i < 10; i++ {
		table := fmt.Sprintf("test_river_%04d", i)
		s.testExecute(c, fmt.Sprintf("UPDATE %s SET title = ? WHERE id = ?", table), "hello", 5+i)
	}

	testWaitSyncDone(c, s.r)

	r = s.testElasticGet(c, "1")
	c.Assert(r.Found, Equals, false)

	r = s.testElasticGet(c, "2")
	c.Assert(r.Found, Equals, true)
	c.Assert(r.Source["es_title"], Equals, "second 2")
	c.Assert(r.Source["tenum"], Equals, "e3")
	c.Assert(r.Source["tset"], Equals, "a,b,c")
	c.Assert(r.Source["es_mylist"], DeepEquals, []interface{}{"a", "b", "c"})
	c.Assert(r.Source["tbit"], Equals, float64(1))

	r = s.testElasticGet(c, "4")
	c.Assert(r.Found, Equals, true)
	c.Assert(r.Source["tenum"], Equals, "")
	c.Assert(r.Source["tset"], Equals, "a,b,c")
	c.Assert(r.Source["tbit"], Equals, float64(0))

	r = s.testElasticGet(c, "3")
	c.Assert(r.Found, Equals, false)

	r = s.testElasticGet(c, "30")
	c.Assert(r.Found, Equals, true)
	c.Assert(r.Source["es_title"], Equals, "second 30")

	for i := 0; i < 10; i++ {
		r = s.testElasticGet(c, fmt.Sprintf("%d", 5+i))
		c.Assert(r.Found, Equals, true)
		c.Assert(r.Source["es_title"], Equals, "hello")
	}
}
<|endoftext|>


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

package sym

// Attribute is a set of common symbol attributes.
type Attribute int32

const (
	// AttrDuplicateOK marks a symbol that can be present in multiple object
	// files.
	AttrDuplicateOK Attribute = 1 << iota
	// AttrExternal marks function symbols loaded from host object files.
	AttrExternal
	// AttrNoSplit marks functions that cannot split the stack; the linker
	// cares because it checks that there are no call chains of nosplit
	// functions that require more than StackLimit bytes (see
	// lib.go:dostkcheck)
	AttrNoSplit
	// AttrReachable marks symbols that are transitively referenced from the
	// entry points. Unreachable symbols are not written to the output.
	AttrReachable
	// AttrCgoExportDynamic and AttrCgoExportStatic mark symbols referenced
	// by directives written by cgo (in response to //export directives in
	// the source).
	AttrCgoExportDynamic
	AttrCgoExportStatic
	// AttrSpecial marks symbols that do not have their address (i.e. Value)
	// computed by the usual mechanism of data.go:dodata() &
	// data.go:address().
	AttrSpecial
	// AttrStackCheck is used by dostkcheck to only check each NoSplit
	// function's stack usage once.
	AttrStackCheck
	// AttrNotInSymbolTable marks symbols that are not written to the symbol table.
	AttrNotInSymbolTable
	// AttrOnList marks symbols that are on some list (such as the list of
	// all text symbols, or one of the lists of data symbols) and is
	// consulted to avoid bugs where a symbol is put on a list twice.
	AttrOnList
	// AttrLocal marks symbols that are only visible within the module
	// (executable or shared library) being linked. Only relevant when
	// dynamically linking Go code.
	AttrLocal
	// AttrReflectMethod marks certain methods from the reflect package that
	// can be used to call arbitrary methods. If no symbol with this bit set
	// is marked as reachable, more dead code elimination can be done.
	AttrReflectMethod
	// AttrMakeTypelink Amarks types that should be added to the typelink
	// table. See typelinks.go:typelinks().
	AttrMakeTypelink
	// AttrShared marks symbols compiled with the -shared option.
	AttrShared
	// AttrVisibilityHidden symbols are ELF symbols with
	// visibility set to STV_HIDDEN. They become local symbols in
	// the final executable. Only relevant when internally linking
	// on an ELF platform.
	AttrVisibilityHidden
	// AttrSubSymbol mostly means that the symbol appears on the Sub list of some
	// other symbol.  Unfortunately, it's not 100% reliable; at least, it's not set
	// correctly for the .TOC. symbol in Link.dodata.  Usually the Outer field of the
	// symbol points to the symbol whose list it is on, but that it is not set for the
	// symbols added to .windynamic in initdynimport in pe.go.
	//
	// TODO(mwhudson): fix the inconsistencies noticed above.
	//
	// Sub lists are used when loading host objects (sections from the host object
	// become regular linker symbols and symbols go on the Sub list of their section)
	// and for constructing the global offset table when internally linking a dynamic
	// executable.
	//
	// TODO(mwhudson): perhaps a better name for this is AttrNonGoSymbol.
	AttrSubSymbol
	// AttrContainer is set on text symbols that are present as the .Outer for some
	// other symbol.
	AttrContainer
	// AttrTopFrame means that the function is an entry point and unwinders
	// should stop when they hit this function.
	AttrTopFrame
	// AttrReadOnly indicates whether the symbol's content (Symbol.P) is backed by
	// read-only memory.
	AttrReadOnly
	// 19 attributes defined so far.
)

func (a Attribute) DuplicateOK() bool      { return a&AttrDuplicateOK != 0 }
func (a Attribute) External() bool         { return a&AttrExternal != 0 }
func (a Attribute) NoSplit() bool          { return a&AttrNoSplit != 0 }
func (a Attribute) Reachable() bool        { return a&AttrReachable != 0 }
func (a Attribute) CgoExportDynamic() bool { return a&AttrCgoExportDynamic != 0 }
func (a Attribute) CgoExportStatic() bool  { return a&AttrCgoExportStatic != 0 }
func (a Attribute) Special() bool          { return a&AttrSpecial != 0 }
func (a Attribute) StackCheck() bool       { return a&AttrStackCheck != 0 }
func (a Attribute) NotInSymbolTable() bool { return a&AttrNotInSymbolTable != 0 }
func (a Attribute) OnList() bool           { return a&AttrOnList != 0 }
func (a Attribute) Local() bool            { return a&AttrLocal != 0 }
func (a Attribute) ReflectMethod() bool    { return a&AttrReflectMethod != 0 }
func (a Attribute) MakeTypelink() bool     { return a&AttrMakeTypelink != 0 }
func (a Attribute) Shared() bool           { return a&AttrShared != 0 }
func (a Attribute) VisibilityHidden() bool { return a&AttrVisibilityHidden != 0 }
func (a Attribute) SubSymbol() bool        { return a&AttrSubSymbol != 0 }
func (a Attribute) Container() bool        { return a&AttrContainer != 0 }
func (a Attribute) TopFrame() bool         { return a&AttrTopFrame != 0 }
func (a Attribute) ReadOnly() bool         { return a&AttrReadOnly != 0 }

func (a Attribute) CgoExport() bool {
	return a.CgoExportDynamic() || a.CgoExportStatic()
}

func (a *Attribute) Set(flag Attribute, value bool) {
	if value {
		*a |= flag
	} else {
		*a &^= flag
	}
}
<commit_msg>[dev.link] cmd/link: set attributes atomically<commit_after>// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package sym

import "sync/atomic"

// Attribute is a set of common symbol attributes.
type Attribute int32

const (
	// AttrDuplicateOK marks a symbol that can be present in multiple object
	// files.
	AttrDuplicateOK Attribute = 1 << iota
	// AttrExternal marks function symbols loaded from host object files.
	AttrExternal
	// AttrNoSplit marks functions that cannot split the stack; the linker
	// cares because it checks that there are no call chains of nosplit
	// functions that require more than StackLimit bytes (see
	// lib.go:dostkcheck)
	AttrNoSplit
	// AttrReachable marks symbols that are transitively referenced from the
	// entry points. Unreachable symbols are not written to the output.
	AttrReachable
	// AttrCgoExportDynamic and AttrCgoExportStatic mark symbols referenced
	// by directives written by cgo (in response to //export directives in
	// the source).
	AttrCgoExportDynamic
	AttrCgoExportStatic
	// AttrSpecial marks symbols that do not have their address (i.e. Value)
	// computed by the usual mechanism of data.go:dodata() &
	// data.go:address().
	AttrSpecial
	// AttrStackCheck is used by dostkcheck to only check each NoSplit
	// function's stack usage once.
	AttrStackCheck
	// AttrNotInSymbolTable marks symbols that are not written to the symbol table.
	AttrNotInSymbolTable
	// AttrOnList marks symbols that are on some list (such as the list of
	// all text symbols, or one of the lists of data symbols) and is
	// consulted to avoid bugs where a symbol is put on a list twice.
	AttrOnList
	// AttrLocal marks symbols that are only visible within the module
	// (executable or shared library) being linked. Only relevant when
	// dynamically linking Go code.
	AttrLocal
	// AttrReflectMethod marks certain methods from the reflect package that
	// can be used to call arbitrary methods. If no symbol with this bit set
	// is marked as reachable, more dead code elimination can be done.
	AttrReflectMethod
	// AttrMakeTypelink Amarks types that should be added to the typelink
	// table. See typelinks.go:typelinks().
	AttrMakeTypelink
	// AttrShared marks symbols compiled with the -shared option.
	AttrShared
	// AttrVisibilityHidden symbols are ELF symbols with
	// visibility set to STV_HIDDEN. They become local symbols in
	// the final executable. Only relevant when internally linking
	// on an ELF platform.
	AttrVisibilityHidden
	// AttrSubSymbol mostly means that the symbol appears on the Sub list of some
	// other symbol.  Unfortunately, it's not 100% reliable; at least, it's not set
	// correctly for the .TOC. symbol in Link.dodata.  Usually the Outer field of the
	// symbol points to the symbol whose list it is on, but that it is not set for the
	// symbols added to .windynamic in initdynimport in pe.go.
	//
	// TODO(mwhudson): fix the inconsistencies noticed above.
	//
	// Sub lists are used when loading host objects (sections from the host object
	// become regular linker symbols and symbols go on the Sub list of their section)
	// and for constructing the global offset table when internally linking a dynamic
	// executable.
	//
	// TODO(mwhudson): perhaps a better name for this is AttrNonGoSymbol.
	AttrSubSymbol
	// AttrContainer is set on text symbols that are present as the .Outer for some
	// other symbol.
	AttrContainer
	// AttrTopFrame means that the function is an entry point and unwinders
	// should stop when they hit this function.
	AttrTopFrame
	// AttrReadOnly indicates whether the symbol's content (Symbol.P) is backed by
	// read-only memory.
	AttrReadOnly
	// 19 attributes defined so far.
)

func (a *Attribute) load() Attribute { return Attribute(atomic.LoadInt32((*int32)(a))) }

func (a *Attribute) DuplicateOK() bool      { return a.load()&AttrDuplicateOK != 0 }
func (a *Attribute) External() bool         { return a.load()&AttrExternal != 0 }
func (a *Attribute) NoSplit() bool          { return a.load()&AttrNoSplit != 0 }
func (a *Attribute) Reachable() bool        { return a.load()&AttrReachable != 0 }
func (a *Attribute) CgoExportDynamic() bool { return a.load()&AttrCgoExportDynamic != 0 }
func (a *Attribute) CgoExportStatic() bool  { return a.load()&AttrCgoExportStatic != 0 }
func (a *Attribute) Special() bool          { return a.load()&AttrSpecial != 0 }
func (a *Attribute) StackCheck() bool       { return a.load()&AttrStackCheck != 0 }
func (a *Attribute) NotInSymbolTable() bool { return a.load()&AttrNotInSymbolTable != 0 }
func (a *Attribute) OnList() bool           { return a.load()&AttrOnList != 0 }
func (a *Attribute) Local() bool            { return a.load()&AttrLocal != 0 }
func (a *Attribute) ReflectMethod() bool    { return a.load()&AttrReflectMethod != 0 }
func (a *Attribute) MakeTypelink() bool     { return a.load()&AttrMakeTypelink != 0 }
func (a *Attribute) Shared() bool           { return a.load()&AttrShared != 0 }
func (a *Attribute) VisibilityHidden() bool { return a.load()&AttrVisibilityHidden != 0 }
func (a *Attribute) SubSymbol() bool        { return a.load()&AttrSubSymbol != 0 }
func (a *Attribute) Container() bool        { return a.load()&AttrContainer != 0 }
func (a *Attribute) TopFrame() bool         { return a.load()&AttrTopFrame != 0 }
func (a *Attribute) ReadOnly() bool         { return a.load()&AttrReadOnly != 0 }

func (a *Attribute) CgoExport() bool {
	return a.CgoExportDynamic() || a.CgoExportStatic()
}

func (a *Attribute) Set(flag Attribute, value bool) {
	// XXX it would be nice if we have atomic And, Or.
	for {
		a0 := a.load()
		var anew Attribute
		if value {
			anew = a0 | flag
		} else {
			anew = a0 &^ flag
		}
		if atomic.CompareAndSwapInt32((*int32)(a), int32(a0), int32(anew)) {
			return
		}
	}
}
<|endoftext|>


<commit_before>package executors

import (
	"bufio"
	"fmt"
	"os"
	"regexp"
	"strings"

	"github.com/akerl/speculate/creds"

	"github.com/akerl/timber/log"
	"github.com/aws/aws-sdk-go/service/sts"
)

var logger = log.NewLogger("mypackage")

const (
	mfaCodeRegexString   = `^\d{6}$`
	mfaArnRegexString    = `^arn:aws(?:-gov)?:iam::\d+:mfa/[\w+=,.@-]+$`
	iamEntityRegexString = `^[\w+=,.@-]+$`
	accountIDRegexString = `^\d{12}$`
)

var mfaCodeRegex = regexp.MustCompile(mfaCodeRegexString)
var mfaArnRegex = regexp.MustCompile(mfaArnRegexString)
var iamEntityRegex = regexp.MustCompile(iamEntityRegexString)
var accountIDRegex = regexp.MustCompile(accountIDRegexString)

// Executor defines the interface for requesting a new set of AWS creds
type Executor interface {
	Execute() (creds.Creds, error)
	ExecuteWithCreds(creds.Creds) (creds.Creds, error)
	SetAccountID(string) error
	SetRoleName(string) error
	SetSessionName(string) error
	SetPolicy(string) error
	SetLifetime(int64) error
	SetMfa(bool) error
	SetMfaSerial(string) error
	SetMfaCode(string) error
	SetMfaPrompt(MfaPrompt) error
	GetAccountID() (string, error)
	GetRoleName() (string, error)
	GetSessionName() (string, error)
	GetPolicy() (string, error)
	GetLifetime() (int64, error)
	GetMfa() (bool, error)
	GetMfaSerial() (string, error)
	GetMfaCode() (string, error)
	GetMfaPrompt() (MfaPrompt, error)
}

// Lifetime object encapsulates the setup of session duration
type Lifetime struct {
	lifetimeInt int64
}

// SetLifetime allows setting the credential lifespan
func (l *Lifetime) SetLifetime(val int64) error {
	if val != 0 && (val < 900 || val > 3600) {
		return fmt.Errorf("Lifetime must be between 900 and 3600: %d", val)
	}
	logger.InfoMsg(fmt.Sprintf("Setting lifetime to %d", val))
	l.lifetimeInt = val
	return nil
}

// GetLifetime returns the lifetime of the executor
func (l *Lifetime) GetLifetime() (int64, error) {
	if l.lifetimeInt == 0 {
		l.lifetimeInt = 3600
	}
	return l.lifetimeInt, nil
}

// Mfa object encapsulates the setup of MFA for API calls
type Mfa struct {
	useMfa    bool
	mfaSerial string
	mfaCode   string
	mfaPrompt MfaPrompt
}

// MfaPrompt interface describes an object which can prompt the user for their MFA
type MfaPrompt interface {
	Prompt() (string, error)
}

// SetMfa sets whether MFA is used
func (m *Mfa) SetMfa(val bool) error {
	logger.InfoMsg(fmt.Sprintf("Setting MFA: %t", val))
	m.useMfa = val
	return nil
}

// SetMfaSerial sets the ARN of the MFA device
func (m *Mfa) SetMfaSerial(val string) error {
	if val == "" || mfaArnRegex.MatchString(val) {
		logger.InfoMsg(fmt.Sprintf("Setting MFA serial: %s", val))
		m.mfaSerial = val
		return nil
	}
	return fmt.Errorf("MFA Serial is malformed: %s", val)
}

// SetMfaCode sets the OTP for MFA
func (m *Mfa) SetMfaCode(val string) error {
	if val == "" || mfaCodeRegex.MatchString(val) {
		logger.InfoMsg(fmt.Sprintf("Setting MFA code: %s", val))
		m.mfaCode = val
		return nil
	}
	return fmt.Errorf("MFA Code is malformed: %s", val)
}

// SetMfaPrompt provides a custom method for loading the MFA code
func (m *Mfa) SetMfaPrompt(val MfaPrompt) error {
	logger.InfoMsg("Setting MFA prompt function")
	m.mfaPrompt = val
	return nil
}

// GetMfa returns if MFA will be used
func (m *Mfa) GetMfa() (bool, error) {
	if !m.useMfa && m.mfaCode != "" {
		m.useMfa = true
	}
	return m.useMfa, nil
}

// GetMfaSerial returns the ARN of the MFA device
func (m *Mfa) GetMfaSerial() (string, error) {
	if m.mfaSerial == "" {
		c := creds.Creds{}
		var err error
		m.mfaSerial, err = c.MfaArn()
		if err != nil {
			return "", err
		}
		logger.InfoMsg(fmt.Sprintf("Using default value for MFA serial: %s", m.mfaSerial))
	}
	return m.mfaSerial, nil
}

// GetMfaCode returns the OTP to use
func (m *Mfa) GetMfaCode() (string, error) {
	if m.mfaCode == "" {
		mfaPrompt, err := m.GetMfaPrompt()
		if err != nil {
			return "", err
		}
		logger.InfoMsg("Calling MFA Prompt function")
		mfa, err := mfaPrompt.Prompt()
		if err != nil {
			return "", err
		}
		m.mfaCode = mfa
	}
	return m.mfaCode, nil
}

// GetMfaPrompt returns the function to use for asking the user for an MFA code
func (m *Mfa) GetMfaPrompt() (MfaPrompt, error) {
	if m.mfaPrompt == nil {
		logger.InfoMsg("Using default value for MFA prompt function")
		m.mfaPrompt = &DefaultMfaPrompt{}
	}
	return m.mfaPrompt, nil
}

// DefaultMfaPrompt defines the standard CLI-based MFA prompt
type DefaultMfaPrompt struct{}

// Prompt asks the user for their MFA token
func (p *DefaultMfaPrompt) Prompt() (string, error) {
	mfaReader := bufio.NewReader(os.Stdin)
	fmt.Fprint(os.Stderr, "MFA Code: ")
	mfa, err := mfaReader.ReadString('\n')
	if err != nil {
		return "", err
	}
	return strings.TrimSpace(mfa), nil
}

func (m *Mfa) configureMfa(paramsIface interface{}) error {
	useMfa, err := m.GetMfa()
	if err != nil {
		return err
	}
	if !useMfa {
		return nil
	}

	mfaCode, err := m.GetMfaCode()
	if err != nil {
		return err
	}
	mfaSerial, err := m.GetMfaSerial()
	if err != nil {
		return err
	}

	switch params := paramsIface.(type) {
	case *sts.AssumeRoleInput:
		params.TokenCode = &mfaCode
		params.SerialNumber = &mfaSerial
	case *sts.GetSessionTokenInput:
		params.TokenCode = &mfaCode
		params.SerialNumber = &mfaSerial
	default:
		return fmt.Errorf("Expected AssumeRoleInput or GetSessionTokenInput, received %T", params)
	}
	return nil
}
<commit_msg>fix logger name<commit_after>package executors

import (
	"bufio"
	"fmt"
	"os"
	"regexp"
	"strings"

	"github.com/akerl/speculate/creds"

	"github.com/akerl/timber/log"
	"github.com/aws/aws-sdk-go/service/sts"
)

var logger = log.NewLogger("speculate")

const (
	mfaCodeRegexString   = `^\d{6}$`
	mfaArnRegexString    = `^arn:aws(?:-gov)?:iam::\d+:mfa/[\w+=,.@-]+$`
	iamEntityRegexString = `^[\w+=,.@-]+$`
	accountIDRegexString = `^\d{12}$`
)

var mfaCodeRegex = regexp.MustCompile(mfaCodeRegexString)
var mfaArnRegex = regexp.MustCompile(mfaArnRegexString)
var iamEntityRegex = regexp.MustCompile(iamEntityRegexString)
var accountIDRegex = regexp.MustCompile(accountIDRegexString)

// Executor defines the interface for requesting a new set of AWS creds
type Executor interface {
	Execute() (creds.Creds, error)
	ExecuteWithCreds(creds.Creds) (creds.Creds, error)
	SetAccountID(string) error
	SetRoleName(string) error
	SetSessionName(string) error
	SetPolicy(string) error
	SetLifetime(int64) error
	SetMfa(bool) error
	SetMfaSerial(string) error
	SetMfaCode(string) error
	SetMfaPrompt(MfaPrompt) error
	GetAccountID() (string, error)
	GetRoleName() (string, error)
	GetSessionName() (string, error)
	GetPolicy() (string, error)
	GetLifetime() (int64, error)
	GetMfa() (bool, error)
	GetMfaSerial() (string, error)
	GetMfaCode() (string, error)
	GetMfaPrompt() (MfaPrompt, error)
}

// Lifetime object encapsulates the setup of session duration
type Lifetime struct {
	lifetimeInt int64
}

// SetLifetime allows setting the credential lifespan
func (l *Lifetime) SetLifetime(val int64) error {
	if val != 0 && (val < 900 || val > 3600) {
		return fmt.Errorf("Lifetime must be between 900 and 3600: %d", val)
	}
	logger.InfoMsg(fmt.Sprintf("Setting lifetime to %d", val))
	l.lifetimeInt = val
	return nil
}

// GetLifetime returns the lifetime of the executor
func (l *Lifetime) GetLifetime() (int64, error) {
	if l.lifetimeInt == 0 {
		l.lifetimeInt = 3600
	}
	return l.lifetimeInt, nil
}

// Mfa object encapsulates the setup of MFA for API calls
type Mfa struct {
	useMfa    bool
	mfaSerial string
	mfaCode   string
	mfaPrompt MfaPrompt
}

// MfaPrompt interface describes an object which can prompt the user for their MFA
type MfaPrompt interface {
	Prompt() (string, error)
}

// SetMfa sets whether MFA is used
func (m *Mfa) SetMfa(val bool) error {
	logger.InfoMsg(fmt.Sprintf("Setting MFA: %t", val))
	m.useMfa = val
	return nil
}

// SetMfaSerial sets the ARN of the MFA device
func (m *Mfa) SetMfaSerial(val string) error {
	if val == "" || mfaArnRegex.MatchString(val) {
		logger.InfoMsg(fmt.Sprintf("Setting MFA serial: %s", val))
		m.mfaSerial = val
		return nil
	}
	return fmt.Errorf("MFA Serial is malformed: %s", val)
}

// SetMfaCode sets the OTP for MFA
func (m *Mfa) SetMfaCode(val string) error {
	if val == "" || mfaCodeRegex.MatchString(val) {
		logger.InfoMsg(fmt.Sprintf("Setting MFA code: %s", val))
		m.mfaCode = val
		return nil
	}
	return fmt.Errorf("MFA Code is malformed: %s", val)
}

// SetMfaPrompt provides a custom method for loading the MFA code
func (m *Mfa) SetMfaPrompt(val MfaPrompt) error {
	logger.InfoMsg("Setting MFA prompt function")
	m.mfaPrompt = val
	return nil
}

// GetMfa returns if MFA will be used
func (m *Mfa) GetMfa() (bool, error) {
	if !m.useMfa && m.mfaCode != "" {
		m.useMfa = true
	}
	return m.useMfa, nil
}

// GetMfaSerial returns the ARN of the MFA device
func (m *Mfa) GetMfaSerial() (string, error) {
	if m.mfaSerial == "" {
		c := creds.Creds{}
		var err error
		m.mfaSerial, err = c.MfaArn()
		if err != nil {
			return "", err
		}
		logger.InfoMsg(fmt.Sprintf("Using default value for MFA serial: %s", m.mfaSerial))
	}
	return m.mfaSerial, nil
}

// GetMfaCode returns the OTP to use
func (m *Mfa) GetMfaCode() (string, error) {
	if m.mfaCode == "" {
		mfaPrompt, err := m.GetMfaPrompt()
		if err != nil {
			return "", err
		}
		logger.InfoMsg("Calling MFA Prompt function")
		mfa, err := mfaPrompt.Prompt()
		if err != nil {
			return "", err
		}
		m.mfaCode = mfa
	}
	return m.mfaCode, nil
}

// GetMfaPrompt returns the function to use for asking the user for an MFA code
func (m *Mfa) GetMfaPrompt() (MfaPrompt, error) {
	if m.mfaPrompt == nil {
		logger.InfoMsg("Using default value for MFA prompt function")
		m.mfaPrompt = &DefaultMfaPrompt{}
	}
	return m.mfaPrompt, nil
}

// DefaultMfaPrompt defines the standard CLI-based MFA prompt
type DefaultMfaPrompt struct{}

// Prompt asks the user for their MFA token
func (p *DefaultMfaPrompt) Prompt() (string, error) {
	mfaReader := bufio.NewReader(os.Stdin)
	fmt.Fprint(os.Stderr, "MFA Code: ")
	mfa, err := mfaReader.ReadString('\n')
	if err != nil {
		return "", err
	}
	return strings.TrimSpace(mfa), nil
}

func (m *Mfa) configureMfa(paramsIface interface{}) error {
	useMfa, err := m.GetMfa()
	if err != nil {
		return err
	}
	if !useMfa {
		return nil
	}

	mfaCode, err := m.GetMfaCode()
	if err != nil {
		return err
	}
	mfaSerial, err := m.GetMfaSerial()
	if err != nil {
		return err
	}

	switch params := paramsIface.(type) {
	case *sts.AssumeRoleInput:
		params.TokenCode = &mfaCode
		params.SerialNumber = &mfaSerial
	case *sts.GetSessionTokenInput:
		params.TokenCode = &mfaCode
		params.SerialNumber = &mfaSerial
	default:
		return fmt.Errorf("Expected AssumeRoleInput or GetSessionTokenInput, received %T", params)
	}
	return nil
}
<|endoftext|>


<commit_before>package fstab

import (
	"fmt"
	"reflect"
	"strconv"
	"strings"
)

// Mount represetnts the filesystem info
type Mount struct {
	// The block special device or remote filesystem to be mounted
	Spec string

	// The mount point for the filesystem
	File string

	// The type of the filesystem
	VfsType string

	// Mount options associated with the filesystem
	MntOps map[string]string

	// Used by dump to determine which filesystems need to be dumped.
	Freq int

	// Used by the fsck(8) program to determine the order in which filesystem checks are done at reboot time
	PassNo int
}

const (
	Path = 0
	Label
	UUID
	PartUUID
	PartLabel
)

type DeviceIdentifierType int

// parseOptions parses the options field into an array of strings
func parseOptions(optionsString string) (options map[string]string) {
	options = make(map[string]string)
	for _, option := range strings.Split(optionsString, ",") {
		bits := strings.Split(strings.TrimSpace(option), "=")
		if len(bits) > 1 {
			options[bits[0]] = bits[1]
		} else {
			options[bits[0]] = ""
		}
	}
	return
}

// MntOpsString returns the serialized MntOps value
func (mount *Mount) MntOpsString() (opsstring string) {
	first := true
	for key, value := range mount.MntOps {
		if first {
			first = false
		} else {
			opsstring += ","
		}

		opsstring += key

		if "" != value {
			opsstring += "=" + value
		}
	}
	return
}

// String serializes the object into fstab format
func (mount *Mount) String() string {
	return mount.Sprintf("%s %s %s %s %d %d")
}

// Sprintf serializes the object according to the given format
func (mount *Mount) Sprintf(format string) string {
	return fmt.Sprintf(format, mount.Spec, mount.File, mount.VfsType, mount.MntOpsString(), mount.Freq, mount.PassNo)
}

// PaddedString serializes the objet into fstab format with configurable column width.
// Each positional argument specifies the width for the column in order. Up to 6 arguments
// are supported, outstanding arguments will be ignored.
func (mount *Mount) PaddedString(paddings ...int) string {
	stringPaddings := 4
	intPaddings := 2
	if len(paddings) < stringPaddings {
		stringPaddings = len(paddings)
		intPaddings = 0
	} else {
		intPaddings = len(paddings) - stringPaddings
		if intPaddings > 2 {
			intPaddings = 2
		}
	}

	var fields []string = make([]string, 0, 6)
	{
		for _, padding := range paddings[:stringPaddings] {
			fields = append(fields, "%-"+strconv.Itoa(padding)+"s")
		}

		for i := len(fields); i < 4; i++ {
			fields = append(fields, "%s")
		}
	}

	if intPaddings > 0 {
		for _, padding := range paddings[4:(4 + intPaddings)] {
			fields = append(fields, "%"+strconv.Itoa(padding)+"d")
		}
	}

	for i := len(fields); i < 6; i++ {
		fields = append(fields, "%d")
	}

	fmt.Printf("%d %d\n%v\n%v\n", stringPaddings, intPaddings, paddings, fields)
	return mount.Sprintf(strings.Join(fields, " "))
}

func (mount *Mount) IsSwap() bool {
	return "swap" == mount.VfsType
}

func (mount *Mount) IsNFS() bool {
	return "nfs" == mount.VfsType
}

// Equals compares 2 Mount objects
func (mount *Mount) Equals(other *Mount) bool {
	return reflect.DeepEqual(*mount, *other)
}

// SpecType returns the device identifier type
func (mount *Mount) SpecType() (spectype DeviceIdentifierType) {
	bits := strings.Split(mount.Spec, "=")
	switch strings.ToUpper(bits[0]) {
	case "UUID":
		spectype = UUID

	case "LABEL":
		spectype = Label

	case "PARTUUID":
		spectype = PartUUID

	case "PARTLABEL":
		spectype = PartLabel

	default:
		spectype = Path
	}
	return
}

// SpecType returns the device identifier value; that is if Spec is
// "UUID=vogons-ate-my-sandwich", it will return "vogons-ate-my-sandwich"
func (mount *Mount) SpecValue() string {
	bits := strings.Split(mount.Spec, "=")
	if 1 == len(bits) {
		return mount.Spec
	} else {
		return bits[1]
	}
}

// ParseLine parses a single line (of an fstab).
// It will most frequently return a Mount; however,
// If a parsing error occurs, `err` will be non-nil and provide an error message.
// If the line is either empy or a comment line, `mount` will also be nil.
func ParseLine(line string) (mount *Mount, err error) {
	line = strings.TrimSpace(line)

	// Lines starting with a pound sign (#) are comments, and are ignored. So are empty lines.
	if ("" == line) || (line[0] == '#') {
		return nil, nil
	}

	fields := strings.Fields(line)
	if len(fields) < 4 {
		return nil, fmt.Errorf("too few fields (%i), at least 4 are expected", len(fields))
	} else {
		mount = new(Mount)
		mount.Spec = fields[0]
		mount.File = fields[1]
		mount.VfsType = fields[2]
		mount.MntOps = parseOptions(fields[3])

		var convErr error

		if len(fields) > 4 {
			mount.Freq, convErr = strconv.Atoi(fields[4])
			if nil != convErr {
				return nil, fmt.Errorf("%s is not a number", fields[4])
			}
		}

		if len(fields) > 5 {
			mount.PassNo, convErr = strconv.Atoi(fields[5])
			if nil != convErr {
				return nil, fmt.Errorf("%s it not a number", fields[5])
			}
		}
	}

	return
}
<commit_msg>Uses typed constants for the DeviceIdentifierType enum (fixes #1)<commit_after>package fstab

import (
	"fmt"
	"reflect"
	"strconv"
	"strings"
)

// Mount represetnts the filesystem info
type Mount struct {
	// The block special device or remote filesystem to be mounted
	Spec string

	// The mount point for the filesystem
	File string

	// The type of the filesystem
	VfsType string

	// Mount options associated with the filesystem
	MntOps map[string]string

	// Used by dump to determine which filesystems need to be dumped.
	Freq int

	// Used by the fsck(8) program to determine the order in which filesystem checks are done at reboot time
	PassNo int
}

type DeviceIdentifierType int

const (
	Path      DeviceIdentifierType = iota
	Label     DeviceIdentifierType = iota
	UUID      DeviceIdentifierType = iota
	PartUUID  DeviceIdentifierType = iota
	PartLabel DeviceIdentifierType = iota
)

// parseOptions parses the options field into an array of strings
func parseOptions(optionsString string) (options map[string]string) {
	options = make(map[string]string)
	for _, option := range strings.Split(optionsString, ",") {
		bits := strings.Split(strings.TrimSpace(option), "=")
		if len(bits) > 1 {
			options[bits[0]] = bits[1]
		} else {
			options[bits[0]] = ""
		}
	}
	return
}

// MntOpsString returns the serialized MntOps value
func (mount *Mount) MntOpsString() (opsstring string) {
	first := true
	for key, value := range mount.MntOps {
		if first {
			first = false
		} else {
			opsstring += ","
		}

		opsstring += key

		if "" != value {
			opsstring += "=" + value
		}
	}
	return
}

// String serializes the object into fstab format
func (mount *Mount) String() string {
	return mount.Sprintf("%s %s %s %s %d %d")
}

// Sprintf serializes the object according to the given format
func (mount *Mount) Sprintf(format string) string {
	return fmt.Sprintf(format, mount.Spec, mount.File, mount.VfsType, mount.MntOpsString(), mount.Freq, mount.PassNo)
}

// PaddedString serializes the objet into fstab format with configurable column width.
// Each positional argument specifies the width for the column in order. Up to 6 arguments
// are supported, outstanding arguments will be ignored.
func (mount *Mount) PaddedString(paddings ...int) string {
	stringPaddings := 4
	intPaddings := 2
	if len(paddings) < stringPaddings {
		stringPaddings = len(paddings)
		intPaddings = 0
	} else {
		intPaddings = len(paddings) - stringPaddings
		if intPaddings > 2 {
			intPaddings = 2
		}
	}

	var fields []string = make([]string, 0, 6)
	{
		for _, padding := range paddings[:stringPaddings] {
			fields = append(fields, "%-"+strconv.Itoa(padding)+"s")
		}

		for i := len(fields); i < 4; i++ {
			fields = append(fields, "%s")
		}
	}

	if intPaddings > 0 {
		for _, padding := range paddings[4:(4 + intPaddings)] {
			fields = append(fields, "%"+strconv.Itoa(padding)+"d")
		}
	}

	for i := len(fields); i < 6; i++ {
		fields = append(fields, "%d")
	}

	fmt.Printf("%d %d\n%v\n%v\n", stringPaddings, intPaddings, paddings, fields)
	return mount.Sprintf(strings.Join(fields, " "))
}

func (mount *Mount) IsSwap() bool {
	return "swap" == mount.VfsType
}

func (mount *Mount) IsNFS() bool {
	return "nfs" == mount.VfsType
}

// Equals compares 2 Mount objects
func (mount *Mount) Equals(other *Mount) bool {
	return reflect.DeepEqual(*mount, *other)
}

// SpecType returns the device identifier type
func (mount *Mount) SpecType() (spectype DeviceIdentifierType) {
	bits := strings.Split(mount.Spec, "=")
	switch strings.ToUpper(bits[0]) {
	case "UUID":
		spectype = UUID

	case "LABEL":
		spectype = Label

	case "PARTUUID":
		spectype = PartUUID

	case "PARTLABEL":
		spectype = PartLabel

	default:
		spectype = Path
	}
	return
}

// SpecType returns the device identifier value; that is if Spec is
// "UUID=vogons-ate-my-sandwich", it will return "vogons-ate-my-sandwich"
func (mount *Mount) SpecValue() string {
	bits := strings.Split(mount.Spec, "=")
	if 1 == len(bits) {
		return mount.Spec
	} else {
		return bits[1]
	}
}

// ParseLine parses a single line (of an fstab).
// It will most frequently return a Mount; however,
// If a parsing error occurs, `err` will be non-nil and provide an error message.
// If the line is either empy or a comment line, `mount` will also be nil.
func ParseLine(line string) (mount *Mount, err error) {
	line = strings.TrimSpace(line)

	// Lines starting with a pound sign (#) are comments, and are ignored. So are empty lines.
	if ("" == line) || (line[0] == '#') {
		return nil, nil
	}

	fields := strings.Fields(line)
	if len(fields) < 4 {
		return nil, fmt.Errorf("too few fields (%i), at least 4 are expected", len(fields))
	} else {
		mount = new(Mount)
		mount.Spec = fields[0]
		mount.File = fields[1]
		mount.VfsType = fields[2]
		mount.MntOps = parseOptions(fields[3])

		var convErr error

		if len(fields) > 4 {
			mount.Freq, convErr = strconv.Atoi(fields[4])
			if nil != convErr {
				return nil, fmt.Errorf("%s is not a number", fields[4])
			}
		}

		if len(fields) > 5 {
			mount.PassNo, convErr = strconv.Atoi(fields[5])
			if nil != convErr {
				return nil, fmt.Errorf("%s it not a number", fields[5])
			}
		}
	}

	return
}
<|endoftext|>


<commit_before>package common

import (
	"fmt"
	"runtime"
)

const VerBinary = "0.0.4"

func VerString(app string) string {
	return fmt.Sprintf("%s v%s (built w/%s)", app, VerBinary, runtime.Version())
}
<commit_msg>bump version<commit_after>package common

import (
	"fmt"
	"runtime"
)

const VerBinary = "0.0.5"

func VerString(app string) string {
	return fmt.Sprintf("%s v%s (built w/%s)", app, VerBinary, runtime.Version())
}
<|endoftext|>


<commit_before>package common

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"strings"
	"time"

	"github.com/denverdino/aliyungo/util"
)

// RemovalPolicy.N add index to array item
// RemovalPolicy=["a", "b"] => RemovalPolicy.1="a" RemovalPolicy.2="b"
type FlattenArray []string

// string contains underline which will be replaced with dot
// SystemDisk_Category => SystemDisk.Category
type UnderlineString string

// A Client represents a client of ECS services
type Client struct {
	AccessKeyId     string //Access Key Id
	AccessKeySecret string //Access Key Secret
	securityToken   string
	debug           bool
	httpClient      *http.Client
	endpoint        string
	version         string
	serviceCode     string
	regionID        Region
	businessInfo    string
	userAgent       string
}

// Initialize properties of a client instance
func (client *Client) Init(endpoint, version, accessKeyId, accessKeySecret string) {
	client.AccessKeyId = accessKeyId
	client.AccessKeySecret = accessKeySecret + "&"
	client.debug = false
	client.httpClient = &http.Client{}
	client.endpoint = endpoint
	client.version = version
}

// Initialize properties of a client instance including regionID
func (client *Client) NewInit(endpoint, version, accessKeyId, accessKeySecret, serviceCode string, regionID Region) {
	client.Init(endpoint, version, accessKeyId, accessKeySecret)
	client.serviceCode = serviceCode
	client.regionID = regionID
	client.setEndpointByLocation(regionID, serviceCode, accessKeyId, accessKeySecret)
}

// Intialize client object when all properties are ready
func (client *Client) InitClient() *Client {
	client.debug = false
	client.httpClient = &http.Client{}
	client.setEndpointByLocation(client.regionID, client.serviceCode, client.AccessKeyId, client.AccessKeySecret)
	return client
}

//NewClient using location service
func (client *Client) setEndpointByLocation(region Region, serviceCode, accessKeyId, accessKeySecret string) {
	locationClient := NewLocationClient(accessKeyId, accessKeySecret)
	ep := locationClient.DescribeOpenAPIEndpoint(region, serviceCode)
	if ep == "" {
		ep = loadEndpointFromFile(region, serviceCode)
	}

	if ep != "" {
		client.endpoint = ep
	}
}

// Ensure all necessary properties are valid
func (client *Client) ensureProperties() error {
	var msg string

	if client.endpoint == "" {
		msg = fmt.Sprintf("endpoint cannot be empty!")
	} else if client.version == "" {
		msg = fmt.Sprintf("version cannot be empty!")
	} else if client.AccessKeyId == "" {
		msg = fmt.Sprintf("AccessKeyId cannot be empty!")
	} else if client.AccessKeySecret == "" {
		msg = fmt.Sprintf("AccessKeySecret cannot be empty!")
	}

	if msg != "" {
		return errors.New(msg)
	}

	return nil
}

// ----------------------------------------------------
// WithXXX methods
// ----------------------------------------------------

// WithEndpoint sets custom endpoint
func (client *Client) WithEndpoint(endpoint string) *Client {
	client.SetEndpoint(endpoint)
	return client
}

// WithVersion sets custom version
func (client *Client) WithVersion(version string) *Client {
	client.SetVersion(version)
	return client
}

// WithRegionID sets Region ID
func (client *Client) WithRegionID(regionID Region) *Client {
	client.SetRegionID(regionID)
	return client
}

//WithServiceCode sets serviceCode
func (client *Client) WithServiceCode(serviceCode string) *Client {
	client.SetServiceCode(serviceCode)
	return client
}

// WithAccessKeyId sets new AccessKeyId
func (client *Client) WithAccessKeyId(id string) *Client {
	client.SetAccessKeyId(id)
	return client
}

// WithAccessKeySecret sets new AccessKeySecret
func (client *Client) WithAccessKeySecret(secret string) *Client {
	client.SetAccessKeySecret(secret)
	return client
}

// WithSecurityToken sets securityToken
func (client *Client) WithSecurityToken(securityToken string) *Client {
	client.SetSecurityToken(securityToken)
	return client
}

// WithDebug sets debug mode to log the request/response message
func (client *Client) WithDebug(debug bool) *Client {
	client.SetDebug(debug)
	return client
}

// WithBusinessInfo sets business info to log the request/response message
func (client *Client) WithBusinessInfo(businessInfo string) *Client {
	client.SetBusinessInfo(businessInfo)
	return client
}

// WithUserAgent sets user agent to the request/response message
func (client *Client) WithUserAgent(userAgent string) *Client {
	client.SetUserAgent(userAgent)
	return client
}

// ----------------------------------------------------
// SetXXX methods
// ----------------------------------------------------

// SetEndpoint sets custom endpoint
func (client *Client) SetEndpoint(endpoint string) {
	client.endpoint = endpoint
}

// SetEndpoint sets custom version
func (client *Client) SetVersion(version string) {
	client.version = version
}

// SetEndpoint sets Region ID
func (client *Client) SetRegionID(regionID Region) {
	client.regionID = regionID
}

//SetServiceCode sets serviceCode
func (client *Client) SetServiceCode(serviceCode string) {
	client.serviceCode = serviceCode
}

// SetAccessKeyId sets new AccessKeyId
func (client *Client) SetAccessKeyId(id string) {
	client.AccessKeyId = id
}

// SetAccessKeySecret sets new AccessKeySecret
func (client *Client) SetAccessKeySecret(secret string) {
	client.AccessKeySecret = secret + "&"
}

// SetAccessKeySecret sets securityToken
func (client *Client) SetSecurityToken(securityToken string) {
	client.securityToken = securityToken
}

// SetDebug sets debug mode to log the request/response message
func (client *Client) SetDebug(debug bool) {
	client.debug = debug
}

// SetBusinessInfo sets business info to log the request/response message
func (client *Client) SetBusinessInfo(businessInfo string) {
	if strings.HasPrefix(businessInfo, "/") {
		client.businessInfo = businessInfo
	} else if businessInfo != "" {
		client.businessInfo = "/" + businessInfo
	}
}

// SetUserAgent sets user agent to the request/response message
func (client *Client) SetUserAgent(userAgent string) {
	client.userAgent = userAgent
}

// Invoke sends the raw HTTP request for ECS services
func (client *Client) Invoke(action string, args interface{}, response interface{}) error {
	if err := client.ensureProperties(); err != nil {
		return err
	}

	request := Request{}
	request.init(client.version, action, client.AccessKeyId, client.securityToken, client.regionID)

	query := util.ConvertToQueryValues(request)
	util.SetQueryValues(args, &query)

	// Sign request
	signature := util.CreateSignatureForRequest(ECSRequestMethod, &query, client.AccessKeySecret)

	// Generate the request URL
	requestURL := client.endpoint + "?" + query.Encode() + "&Signature=" + url.QueryEscape(signature)

	httpReq, err := http.NewRequest(ECSRequestMethod, requestURL, nil)

	if err != nil {
		return GetClientError(err)
	}

	// TODO move to util and add build val flag
	httpReq.Header.Set("X-SDK-Client", `AliyunGO/`+Version+client.businessInfo)
	httpReq.Header.Set("User-Agent", httpReq.UserAgent()+" "+client.userAgent)

	t0 := time.Now()
	httpResp, err := client.httpClient.Do(httpReq)
	t1 := time.Now()
	if err != nil {
		return GetClientError(err)
	}
	statusCode := httpResp.StatusCode

	if client.debug {
		log.Printf("Invoke %s %s %d (%v)", ECSRequestMethod, requestURL, statusCode, t1.Sub(t0))
	}

	defer httpResp.Body.Close()
	body, err := ioutil.ReadAll(httpResp.Body)

	if err != nil {
		return GetClientError(err)
	}

	if client.debug {
		var prettyJSON bytes.Buffer
		err = json.Indent(&prettyJSON, body, "", "    ")
		log.Println(string(prettyJSON.Bytes()))
	}

	if statusCode >= 400 && statusCode <= 599 {
		errorResponse := ErrorResponse{}
		err = json.Unmarshal(body, &errorResponse)
		ecsError := &Error{
			ErrorResponse: errorResponse,
			StatusCode:    statusCode,
		}
		return ecsError
	}

	err = json.Unmarshal(body, response)
	//log.Printf("%++v", response)
	if err != nil {
		return GetClientError(err)
	}

	return nil
}

// Invoke sends the raw HTTP request for ECS services
func (client *Client) InvokeByFlattenMethod(action string, args interface{}, response interface{}) error {
	if err := client.ensureProperties(); err != nil {
		return err
	}

	request := Request{}
	request.init(client.version, action, client.AccessKeyId, client.securityToken, client.regionID)

	query := util.ConvertToQueryValues(request)

	util.SetQueryValueByFlattenMethod(args, &query)

	// Sign request
	signature := util.CreateSignatureForRequest(ECSRequestMethod, &query, client.AccessKeySecret)

	// Generate the request URL
	requestURL := client.endpoint + "?" + query.Encode() + "&Signature=" + url.QueryEscape(signature)

	httpReq, err := http.NewRequest(ECSRequestMethod, requestURL, nil)

	if err != nil {
		return GetClientError(err)
	}

	// TODO move to util and add build val flag
	httpReq.Header.Set("X-SDK-Client", `AliyunGO/`+Version+client.businessInfo)
	httpReq.Header.Set("User-Agent", httpReq.UserAgent()+" "+client.userAgent)

	t0 := time.Now()
	httpResp, err := client.httpClient.Do(httpReq)
	t1 := time.Now()
	if err != nil {
		return GetClientError(err)
	}
	statusCode := httpResp.StatusCode

	if client.debug {
		log.Printf("Invoke %s %s %d (%v)", ECSRequestMethod, requestURL, statusCode, t1.Sub(t0))
	}

	defer httpResp.Body.Close()
	body, err := ioutil.ReadAll(httpResp.Body)

	if err != nil {
		return GetClientError(err)
	}

	if client.debug {
		var prettyJSON bytes.Buffer
		err = json.Indent(&prettyJSON, body, "", "    ")
		log.Println(string(prettyJSON.Bytes()))
	}

	if statusCode >= 400 && statusCode <= 599 {
		errorResponse := ErrorResponse{}
		err = json.Unmarshal(body, &errorResponse)
		ecsError := &Error{
			ErrorResponse: errorResponse,
			StatusCode:    statusCode,
		}
		return ecsError
	}

	err = json.Unmarshal(body, response)
	//log.Printf("%++v", response)
	if err != nil {
		return GetClientError(err)
	}

	return nil
}

// Invoke sends the raw HTTP request for ECS services
//改进了一下上面那个方法，可以使用各种Http方法
//2017.1.30 增加了一个path参数，用来拓展访问的地址
func (client *Client) InvokeByAnyMethod(method, action, path string, args interface{}, response interface{}) error {
	if err := client.ensureProperties(); err != nil {
		return err
	}

	request := Request{}
	request.init(client.version, action, client.AccessKeyId, client.securityToken, client.regionID)

	data := util.ConvertToQueryValues(request)
	util.SetQueryValues(args, &data)

	// Sign request
	signature := util.CreateSignatureForRequest(method, &data, client.AccessKeySecret)

	data.Add("Signature", signature)
	// Generate the request URL
	var (
		httpReq *http.Request
		err     error
	)
	if method == http.MethodGet {
		requestURL := client.endpoint + path + "?" + data.Encode()
		//fmt.Println(requestURL)
		httpReq, err = http.NewRequest(method, requestURL, nil)
	} else {
		//fmt.Println(client.endpoint + path)
		httpReq, err = http.NewRequest(method, client.endpoint+path, strings.NewReader(data.Encode()))
		httpReq.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	}

	if err != nil {
		return GetClientError(err)
	}

	// TODO move to util and add build val flag
	httpReq.Header.Set("X-SDK-Client", `AliyunGO/`+Version+client.businessInfo)
	httpReq.Header.Set("User-Agent", httpReq.Header.Get("User-Agent")+" "+client.userAgent)

	t0 := time.Now()
	httpResp, err := client.httpClient.Do(httpReq)
	t1 := time.Now()
	if err != nil {
		return GetClientError(err)
	}
	statusCode := httpResp.StatusCode

	if client.debug {
		log.Printf("Invoke %s %s %d (%v) %v", ECSRequestMethod, client.endpoint, statusCode, t1.Sub(t0), data.Encode())
	}

	defer httpResp.Body.Close()
	body, err := ioutil.ReadAll(httpResp.Body)

	if err != nil {
		return GetClientError(err)
	}

	if client.debug {
		var prettyJSON bytes.Buffer
		err = json.Indent(&prettyJSON, body, "", "    ")
		log.Println(string(prettyJSON.Bytes()))
	}

	if statusCode >= 400 && statusCode <= 599 {
		errorResponse := ErrorResponse{}
		err = json.Unmarshal(body, &errorResponse)
		ecsError := &Error{
			ErrorResponse: errorResponse,
			StatusCode:    statusCode,
		}
		return ecsError
	}

	err = json.Unmarshal(body, response)
	//log.Printf("%++v", response)
	if err != nil {
		return GetClientError(err)
	}

	return nil
}

// GenerateClientToken generates the Client Token with random string
func (client *Client) GenerateClientToken() string {
	return util.CreateRandomString()
}

func GetClientErrorFromString(str string) error {
	return &Error{
		ErrorResponse: ErrorResponse{
			Code:    "AliyunGoClientFailure",
			Message: str,
		},
		StatusCode: -1,
	}
}

func GetClientError(err error) error {
	return GetClientErrorFromString(err.Error())
}
<commit_msg>Add environment TLSHandshakeTimeout to override the default TLSHandshakeTimeout when the network is bad (#207)<commit_after>package common

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

	"github.com/denverdino/aliyungo/util"
)

// RemovalPolicy.N add index to array item
// RemovalPolicy=["a", "b"] => RemovalPolicy.1="a" RemovalPolicy.2="b"
type FlattenArray []string

// string contains underline which will be replaced with dot
// SystemDisk_Category => SystemDisk.Category
type UnderlineString string

// A Client represents a client of ECS services
type Client struct {
	AccessKeyId     string //Access Key Id
	AccessKeySecret string //Access Key Secret
	securityToken   string
	debug           bool
	httpClient      *http.Client
	endpoint        string
	version         string
	serviceCode     string
	regionID        Region
	businessInfo    string
	userAgent       string
}

// Initialize properties of a client instance
func (client *Client) Init(endpoint, version, accessKeyId, accessKeySecret string) {
	client.AccessKeyId = accessKeyId
	client.AccessKeySecret = accessKeySecret + "&"
	client.debug = false
	handshakeTimeout, err := strconv.Atoi(os.Getenv("TLSHandshakeTimeout"))
	if err != nil {
		handshakeTimeout = 0
	}
	if handshakeTimeout == 0 {
		client.httpClient = &http.Client{}
	} else {
		t := &http.Transport{
			TLSHandshakeTimeout: time.Duration(handshakeTimeout) * time.Second,}
		client.httpClient = &http.Client{Transport: t,}
	}
	client.endpoint = endpoint
	client.version = version
}

// Initialize properties of a client instance including regionID
func (client *Client) NewInit(endpoint, version, accessKeyId, accessKeySecret, serviceCode string, regionID Region) {
	client.Init(endpoint, version, accessKeyId, accessKeySecret)
	client.serviceCode = serviceCode
	client.regionID = regionID
	client.setEndpointByLocation(regionID, serviceCode, accessKeyId, accessKeySecret)
}

// Intialize client object when all properties are ready
func (client *Client) InitClient() *Client {
	client.debug = false
	handshakeTimeout, err := strconv.Atoi(os.Getenv("TLSHandshakeTimeout"))
	if err != nil {
		handshakeTimeout = 0
	}
	if handshakeTimeout == 0 {
		client.httpClient = &http.Client{}
	} else {
		t := &http.Transport{
			TLSHandshakeTimeout: time.Duration(handshakeTimeout) * time.Second,}
		client.httpClient = &http.Client{Transport: t,}
	}
	client.setEndpointByLocation(client.regionID, client.serviceCode, client.AccessKeyId, client.AccessKeySecret)
	return client
}

//NewClient using location service
func (client *Client) setEndpointByLocation(region Region, serviceCode, accessKeyId, accessKeySecret string) {
	locationClient := NewLocationClient(accessKeyId, accessKeySecret)
	ep := locationClient.DescribeOpenAPIEndpoint(region, serviceCode)
	if ep == "" {
		ep = loadEndpointFromFile(region, serviceCode)
	}

	if ep != "" {
		client.endpoint = ep
	}
}

// Ensure all necessary properties are valid
func (client *Client) ensureProperties() error {
	var msg string

	if client.endpoint == "" {
		msg = fmt.Sprintf("endpoint cannot be empty!")
	} else if client.version == "" {
		msg = fmt.Sprintf("version cannot be empty!")
	} else if client.AccessKeyId == "" {
		msg = fmt.Sprintf("AccessKeyId cannot be empty!")
	} else if client.AccessKeySecret == "" {
		msg = fmt.Sprintf("AccessKeySecret cannot be empty!")
	}

	if msg != "" {
		return errors.New(msg)
	}

	return nil
}

// ----------------------------------------------------
// WithXXX methods
// ----------------------------------------------------

// WithEndpoint sets custom endpoint
func (client *Client) WithEndpoint(endpoint string) *Client {
	client.SetEndpoint(endpoint)
	return client
}

// WithVersion sets custom version
func (client *Client) WithVersion(version string) *Client {
	client.SetVersion(version)
	return client
}

// WithRegionID sets Region ID
func (client *Client) WithRegionID(regionID Region) *Client {
	client.SetRegionID(regionID)
	return client
}

//WithServiceCode sets serviceCode
func (client *Client) WithServiceCode(serviceCode string) *Client {
	client.SetServiceCode(serviceCode)
	return client
}

// WithAccessKeyId sets new AccessKeyId
func (client *Client) WithAccessKeyId(id string) *Client {
	client.SetAccessKeyId(id)
	return client
}

// WithAccessKeySecret sets new AccessKeySecret
func (client *Client) WithAccessKeySecret(secret string) *Client {
	client.SetAccessKeySecret(secret)
	return client
}

// WithSecurityToken sets securityToken
func (client *Client) WithSecurityToken(securityToken string) *Client {
	client.SetSecurityToken(securityToken)
	return client
}

// WithDebug sets debug mode to log the request/response message
func (client *Client) WithDebug(debug bool) *Client {
	client.SetDebug(debug)
	return client
}

// WithBusinessInfo sets business info to log the request/response message
func (client *Client) WithBusinessInfo(businessInfo string) *Client {
	client.SetBusinessInfo(businessInfo)
	return client
}

// WithUserAgent sets user agent to the request/response message
func (client *Client) WithUserAgent(userAgent string) *Client {
	client.SetUserAgent(userAgent)
	return client
}

// ----------------------------------------------------
// SetXXX methods
// ----------------------------------------------------

// SetEndpoint sets custom endpoint
func (client *Client) SetEndpoint(endpoint string) {
	client.endpoint = endpoint
}

// SetEndpoint sets custom version
func (client *Client) SetVersion(version string) {
	client.version = version
}

// SetEndpoint sets Region ID
func (client *Client) SetRegionID(regionID Region) {
	client.regionID = regionID
}

//SetServiceCode sets serviceCode
func (client *Client) SetServiceCode(serviceCode string) {
	client.serviceCode = serviceCode
}

// SetAccessKeyId sets new AccessKeyId
func (client *Client) SetAccessKeyId(id string) {
	client.AccessKeyId = id
}

// SetAccessKeySecret sets new AccessKeySecret
func (client *Client) SetAccessKeySecret(secret string) {
	client.AccessKeySecret = secret + "&"
}

// SetAccessKeySecret sets securityToken
func (client *Client) SetSecurityToken(securityToken string) {
	client.securityToken = securityToken
}

// SetDebug sets debug mode to log the request/response message
func (client *Client) SetDebug(debug bool) {
	client.debug = debug
}

// SetBusinessInfo sets business info to log the request/response message
func (client *Client) SetBusinessInfo(businessInfo string) {
	if strings.HasPrefix(businessInfo, "/") {
		client.businessInfo = businessInfo
	} else if businessInfo != "" {
		client.businessInfo = "/" + businessInfo
	}
}

// SetUserAgent sets user agent to the request/response message
func (client *Client) SetUserAgent(userAgent string) {
	client.userAgent = userAgent
}

// Invoke sends the raw HTTP request for ECS services
func (client *Client) Invoke(action string, args interface{}, response interface{}) error {
	if err := client.ensureProperties(); err != nil {
		return err
	}

	request := Request{}
	request.init(client.version, action, client.AccessKeyId, client.securityToken, client.regionID)

	query := util.ConvertToQueryValues(request)
	util.SetQueryValues(args, &query)

	// Sign request
	signature := util.CreateSignatureForRequest(ECSRequestMethod, &query, client.AccessKeySecret)

	// Generate the request URL
	requestURL := client.endpoint + "?" + query.Encode() + "&Signature=" + url.QueryEscape(signature)

	httpReq, err := http.NewRequest(ECSRequestMethod, requestURL, nil)

	if err != nil {
		return GetClientError(err)
	}

	// TODO move to util and add build val flag
	httpReq.Header.Set("X-SDK-Client", `AliyunGO/`+Version+client.businessInfo)
	httpReq.Header.Set("User-Agent", httpReq.UserAgent()+" "+client.userAgent)

	t0 := time.Now()
	httpResp, err := client.httpClient.Do(httpReq)
	t1 := time.Now()
	if err != nil {
		return GetClientError(err)
	}
	statusCode := httpResp.StatusCode

	if client.debug {
		log.Printf("Invoke %s %s %d (%v)", ECSRequestMethod, requestURL, statusCode, t1.Sub(t0))
	}

	defer httpResp.Body.Close()
	body, err := ioutil.ReadAll(httpResp.Body)

	if err != nil {
		return GetClientError(err)
	}

	if client.debug {
		var prettyJSON bytes.Buffer
		err = json.Indent(&prettyJSON, body, "", "    ")
		log.Println(string(prettyJSON.Bytes()))
	}

	if statusCode >= 400 && statusCode <= 599 {
		errorResponse := ErrorResponse{}
		err = json.Unmarshal(body, &errorResponse)
		ecsError := &Error{
			ErrorResponse: errorResponse,
			StatusCode:    statusCode,
		}
		return ecsError
	}

	err = json.Unmarshal(body, response)
	//log.Printf("%++v", response)
	if err != nil {
		return GetClientError(err)
	}

	return nil
}

// Invoke sends the raw HTTP request for ECS services
func (client *Client) InvokeByFlattenMethod(action string, args interface{}, response interface{}) error {
	if err := client.ensureProperties(); err != nil {
		return err
	}

	request := Request{}
	request.init(client.version, action, client.AccessKeyId, client.securityToken, client.regionID)

	query := util.ConvertToQueryValues(request)

	util.SetQueryValueByFlattenMethod(args, &query)

	// Sign request
	signature := util.CreateSignatureForRequest(ECSRequestMethod, &query, client.AccessKeySecret)

	// Generate the request URL
	requestURL := client.endpoint + "?" + query.Encode() + "&Signature=" + url.QueryEscape(signature)

	httpReq, err := http.NewRequest(ECSRequestMethod, requestURL, nil)

	if err != nil {
		return GetClientError(err)
	}

	// TODO move to util and add build val flag
	httpReq.Header.Set("X-SDK-Client", `AliyunGO/`+Version+client.businessInfo)
	httpReq.Header.Set("User-Agent", httpReq.UserAgent()+" "+client.userAgent)

	t0 := time.Now()
	httpResp, err := client.httpClient.Do(httpReq)
	t1 := time.Now()
	if err != nil {
		return GetClientError(err)
	}
	statusCode := httpResp.StatusCode

	if client.debug {
		log.Printf("Invoke %s %s %d (%v)", ECSRequestMethod, requestURL, statusCode, t1.Sub(t0))
	}

	defer httpResp.Body.Close()
	body, err := ioutil.ReadAll(httpResp.Body)

	if err != nil {
		return GetClientError(err)
	}

	if client.debug {
		var prettyJSON bytes.Buffer
		err = json.Indent(&prettyJSON, body, "", "    ")
		log.Println(string(prettyJSON.Bytes()))
	}

	if statusCode >= 400 && statusCode <= 599 {
		errorResponse := ErrorResponse{}
		err = json.Unmarshal(body, &errorResponse)
		ecsError := &Error{
			ErrorResponse: errorResponse,
			StatusCode:    statusCode,
		}
		return ecsError
	}

	err = json.Unmarshal(body, response)
	//log.Printf("%++v", response)
	if err != nil {
		return GetClientError(err)
	}

	return nil
}

// Invoke sends the raw HTTP request for ECS services
//改进了一下上面那个方法，可以使用各种Http方法
//2017.1.30 增加了一个path参数，用来拓展访问的地址
func (client *Client) InvokeByAnyMethod(method, action, path string, args interface{}, response interface{}) error {
	if err := client.ensureProperties(); err != nil {
		return err
	}

	request := Request{}
	request.init(client.version, action, client.AccessKeyId, client.securityToken, client.regionID)

	data := util.ConvertToQueryValues(request)
	util.SetQueryValues(args, &data)

	// Sign request
	signature := util.CreateSignatureForRequest(method, &data, client.AccessKeySecret)

	data.Add("Signature", signature)
	// Generate the request URL
	var (
		httpReq *http.Request
		err     error
	)
	if method == http.MethodGet {
		requestURL := client.endpoint + path + "?" + data.Encode()
		//fmt.Println(requestURL)
		httpReq, err = http.NewRequest(method, requestURL, nil)
	} else {
		//fmt.Println(client.endpoint + path)
		httpReq, err = http.NewRequest(method, client.endpoint+path, strings.NewReader(data.Encode()))
		httpReq.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	}

	if err != nil {
		return GetClientError(err)
	}

	// TODO move to util and add build val flag
	httpReq.Header.Set("X-SDK-Client", `AliyunGO/`+Version+client.businessInfo)
	httpReq.Header.Set("User-Agent", httpReq.Header.Get("User-Agent")+" "+client.userAgent)

	t0 := time.Now()
	httpResp, err := client.httpClient.Do(httpReq)
	t1 := time.Now()
	if err != nil {
		return GetClientError(err)
	}
	statusCode := httpResp.StatusCode

	if client.debug {
		log.Printf("Invoke %s %s %d (%v) %v", ECSRequestMethod, client.endpoint, statusCode, t1.Sub(t0), data.Encode())
	}

	defer httpResp.Body.Close()
	body, err := ioutil.ReadAll(httpResp.Body)

	if err != nil {
		return GetClientError(err)
	}

	if client.debug {
		var prettyJSON bytes.Buffer
		err = json.Indent(&prettyJSON, body, "", "    ")
		log.Println(string(prettyJSON.Bytes()))
	}

	if statusCode >= 400 && statusCode <= 599 {
		errorResponse := ErrorResponse{}
		err = json.Unmarshal(body, &errorResponse)
		ecsError := &Error{
			ErrorResponse: errorResponse,
			StatusCode:    statusCode,
		}
		return ecsError
	}

	err = json.Unmarshal(body, response)
	//log.Printf("%++v", response)
	if err != nil {
		return GetClientError(err)
	}

	return nil
}

// GenerateClientToken generates the Client Token with random string
func (client *Client) GenerateClientToken() string {
	return util.CreateRandomString()
}

func GetClientErrorFromString(str string) error {
	return &Error{
		ErrorResponse: ErrorResponse{
			Code:    "AliyunGoClientFailure",
			Message: str,
		},
		StatusCode: -1,
	}
}

func GetClientError(err error) error {
	return GetClientErrorFromString(err.Error())
}
<|endoftext|>


<commit_before>package common

import (
	"fmt"
	"net/url"
	"os"
	"path/filepath"
	"runtime"
	"strings"
)

// ScrubConfig is a helper that returns a string representation of
// any struct with the given values stripped out.
func ScrubConfig(target interface{}, values ...string) string {
	conf := fmt.Sprintf("Config: %+v", target)
	for _, value := range values {
		if value == "" {
			continue
		}
		conf = strings.Replace(conf, value, "<Filtered>", -1)
	}
	return conf
}

// ChooseString returns the first non-empty value.
func ChooseString(vals ...string) string {
	for _, el := range vals {
		if el != "" {
			return el
		}
	}

	return ""
}

// DownloadableURL processes a URL that may also be a file path and returns
// a completely valid URL. For example, the original URL might be "local/file.iso"
// which isn't a valid URL. DownloadableURL will return "file:///local/file.iso"
func DownloadableURL(original string) (string, error) {
	if runtime.GOOS == "windows" {
		// If the distance to the first ":" is just one character, assume
		// we're dealing with a drive letter and thus a file path.
		idx := strings.Index(original, ":")
		if idx == 1 {
			original = "file:///" + original
		}
	}

	url, err := url.Parse(original)
	if err != nil {
		return "", err
	}

	if url.Scheme == "" {
		url.Scheme = "file"
	}

	if url.Scheme == "file" {
		// Windows file handling is all sorts of tricky...
		if runtime.GOOS == "windows" {
			// If the path is using Windows-style slashes, URL parses
			// it into the host field.
			if url.Path == "" && strings.Contains(url.Host, `\`) {
				url.Path = url.Host
				url.Host = ""
			}

			// For Windows absolute file paths, remove leading / prior to processing
			// since net/url turns "C:/" into "/C:/"
			if len(url.Path) > 0 && url.Path[0] == '/' {
				url.Path = url.Path[1:len(url.Path)]
			}
		}

		// Only do the filepath transformations if the file appears
		// to actually exist.
		if _, err := os.Stat(url.Path); err == nil {
			url.Path, err = filepath.Abs(url.Path)
			if err != nil {
				return "", err
			}

			url.Path, err = filepath.EvalSymlinks(url.Path)
			if err != nil {
				return "", err
			}

			url.Path = filepath.Clean(url.Path)
		}

		if runtime.GOOS == "windows" {
			// Also replace all backslashes with forwardslashes since Windows
			// users are likely to do this but the URL should actually only
			// contain forward slashes.
			url.Path = strings.Replace(url.Path, `\`, `/`, -1)
		}
	}

	// Make sure it is lowercased
	url.Scheme = strings.ToLower(url.Scheme)

	// Verify that the scheme is something we support in our common downloader.
	supported := []string{"file", "http", "https"}
	found := false
	for _, s := range supported {
		if url.Scheme == s {
			found = true
			break
		}
	}

	if !found {
		return "", fmt.Errorf("Unsupported URL scheme: %s", url.Scheme)
	}

	return url.String(), nil
}
<commit_msg>common: revert some changes from #2121 for Windows<commit_after>package common

import (
	"fmt"
	"net/url"
	"os"
	"path/filepath"
	"runtime"
	"strings"
)

// ScrubConfig is a helper that returns a string representation of
// any struct with the given values stripped out.
func ScrubConfig(target interface{}, values ...string) string {
	conf := fmt.Sprintf("Config: %+v", target)
	for _, value := range values {
		if value == "" {
			continue
		}
		conf = strings.Replace(conf, value, "<Filtered>", -1)
	}
	return conf
}

// ChooseString returns the first non-empty value.
func ChooseString(vals ...string) string {
	for _, el := range vals {
		if el != "" {
			return el
		}
	}

	return ""
}

// DownloadableURL processes a URL that may also be a file path and returns
// a completely valid URL. For example, the original URL might be "local/file.iso"
// which isn't a valid URL. DownloadableURL will return "file:///local/file.iso"
func DownloadableURL(original string) (string, error) {
	if runtime.GOOS == "windows" {
		// If the distance to the first ":" is just one character, assume
		// we're dealing with a drive letter and thus a file path.
		idx := strings.Index(original, ":")
		if idx == 1 {
			original = "file:///" + original
		}
	}

	url, err := url.Parse(original)
	if err != nil {
		return "", err
	}

	if url.Scheme == "" {
		url.Scheme = "file"
	}

	if url.Scheme == "file" {
		// Windows file handling is all sorts of tricky...
		if runtime.GOOS == "windows" {
			// If the path is using Windows-style slashes, URL parses
			// it into the host field.
			if url.Path == "" && strings.Contains(url.Host, `\`) {
				url.Path = url.Host
				url.Host = ""
			}

			// For Windows absolute file paths, remove leading / prior to processing
			// since net/url turns "C:/" into "/C:/"
			if len(url.Path) > 0 && url.Path[0] == '/' {
				url.Path = url.Path[1:len(url.Path)]
			}
		}

		// Only do the filepath transformations if the file appears
		// to actually exist.
		if _, err := os.Stat(url.Path); err == nil {
			url.Path, err = filepath.Abs(url.Path)
			if err != nil {
				return "", err
			}

			url.Path, err = filepath.EvalSymlinks(url.Path)
			if err != nil {
				return "", err
			}

			url.Path = filepath.Clean(url.Path)
		}

		if runtime.GOOS == "windows" {
			// Also replace all backslashes with forwardslashes since Windows
			// users are likely to do this but the URL should actually only
			// contain forward slashes.
			url.Path = strings.Replace(url.Path, `\`, `/`, -1)
		}
	}

	// Make sure it is lowercased
	url.Scheme = strings.ToLower(url.Scheme)

	// This is to work around issue #5927. This can safely be removed once
	// we distribute with a version of Go that fixes that bug.
	//
	// See: https://code.google.com/p/go/issues/detail?id=5927
	if url.Path != "" && url.Path[0] != '/' {
		url.Path = "/" + url.Path
	}

	// Verify that the scheme is something we support in our common downloader.
	supported := []string{"file", "http", "https"}
	found := false
	for _, s := range supported {
		if url.Scheme == s {
			found = true
			break
		}
	}

	if !found {
		return "", fmt.Errorf("Unsupported URL scheme: %s", url.Scheme)
	}

	return url.String(), nil
}
<|endoftext|>


<commit_before>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package factory_test

import (
	"runtime"
	"strings"

	jc "github.com/juju/testing/checkers"
	gc "gopkg.in/check.v1"

	"github.com/juju/juju/container"
	"github.com/juju/juju/container/factory"
	"github.com/juju/juju/container/lxd"
	"github.com/juju/juju/instance"
	"github.com/juju/juju/testing"
)

type factorySuite struct {
	testing.BaseSuite
}

var _ = gc.Suite(&factorySuite{})

func (*factorySuite) TestNewContainerManager(c *gc.C) {
	for _, test := range []struct {
		containerType instance.ContainerType
		valid         bool
	}{{
		containerType: instance.LXC,
		valid:         true,
	}, {
		containerType: instance.LXD,
		valid:         true,
	}, {
		containerType: instance.KVM,
		valid:         true,
	}, {
		containerType: instance.NONE,
		valid:         false,
	}, {
		containerType: instance.ContainerType("other"),
		valid:         false,
	}} {
		/* LXD isn't available in go 1.2 */
		if !lxd.HasLXDSupport() {
			continue
		}

		conf := container.ManagerConfig{container.ConfigName: "test"}
		manager, err := factory.NewContainerManager(test.containerType, conf, nil)
		if test.valid {
			c.Assert(err, jc.ErrorIsNil)
			c.Assert(manager, gc.NotNil)
		} else {
			c.Assert(err, gc.ErrorMatches, `unknown container type: ".*"`)
			c.Assert(manager, gc.IsNil)
		}
	}
}
<commit_msg>lxd: fix another typo in tests<commit_after>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package factory_test

import (
	"runtime"
	"strings"

	jc "github.com/juju/testing/checkers"
	gc "gopkg.in/check.v1"

	"github.com/juju/juju/container"
	"github.com/juju/juju/container/factory"
	"github.com/juju/juju/container/lxd"
	"github.com/juju/juju/instance"
	"github.com/juju/juju/testing"
)

type factorySuite struct {
	testing.BaseSuite
}

var _ = gc.Suite(&factorySuite{})

func (*factorySuite) TestNewContainerManager(c *gc.C) {
	for _, test := range []struct {
		containerType instance.ContainerType
		valid         bool
	}{{
		containerType: instance.LXC,
		valid:         true,
	}, {
		containerType: instance.LXD,
		valid:         true,
	}, {
		containerType: instance.KVM,
		valid:         true,
	}, {
		containerType: instance.NONE,
		valid:         false,
	}, {
		containerType: instance.ContainerType("other"),
		valid:         false,
	}} {
		/* LXD isn't available in go 1.2 */
		if test.ContainerType == instance.LXD && !lxd.HasLXDSupport() {
			continue
		}

		conf := container.ManagerConfig{container.ConfigName: "test"}
		manager, err := factory.NewContainerManager(test.containerType, conf, nil)
		if test.valid {
			c.Assert(err, jc.ErrorIsNil)
			c.Assert(manager, gc.NotNil)
		} else {
			c.Assert(err, gc.ErrorMatches, `unknown container type: ".*"`)
			c.Assert(manager, gc.IsNil)
		}
	}
}
<|endoftext|>


<commit_before>// Copyright (C) 2017 Damon Revoe. All rights reserved.
// Use of this source code is governed by the MIT
// license, which can be found in the LICENSE file.

package main

var libTemplate = []embeddedTemplateFile{
	embeddedTemplateFile{"include/{name}/Makefile.am", 0644,
		[]byte(`{{template "FileHeader" . -}}
pkgincludedir = $(includedir)/{{.name}}

{{$headerExt := StringList "*?.H" "*?.h" "*?.hh" "*?.hxx" "*?.hpp" -}}
{{$allFiles := Dir .dirname -}}
pkginclude_HEADERS ={{template "Multiline" Select $allFiles $headerExt}}
{{$extraFiles := Exclude $allFiles $headerExt}}{{if $extraFiles}}
EXTRA_DIST ={{template "Multiline" $extraFiles}}
{{end}}
all: config.h

check: all

config.h: $(CONFIG_HEADER)
	sed -e 's/#\([^ ][^ ]*\) \([^ ][^ ]*\)/#\1 {{VarNameUC .name}}_\2/g' < \
		$(CONFIG_HEADER) > $@

install-data-hook: config.h
	$(INSTALL_DATA) config.h $(DESTDIR)$(pkgincludedir)/config.h

uninstall-hook:
	rm -f $(DESTDIR)$(pkgincludedir)/config.h
	rmdir $(DESTDIR)$(pkgincludedir) || true

# For older versions of Automake.
uninstall-local:
	rm -f $(DESTDIR)$(pkgincludedir)/config.h
	rmdir $(DESTDIR)$(pkgincludedir) || true

CLEANFILES = config.h
{{template "Snippet" .}}`)},
	embeddedTemplateFile{"include/Makefile.am", 0644,
		[]byte(`{{template "FileHeader" . -}}
SUBDIRS = {{.name}}
{{template "Snippet" .}}`)},
	embeddedTemplateFile{"src/Makefile.am", 0644,
		[]byte(`{{template "FileHeader" . -}}
lib_LTLIBRARIES = lib{{.name}}.la

{{if index . "version-info" -}}
lib{{VarName .name}}_la_LDFLAGS = -version-info @library_version_info@

{{end -}}
{{$sourceExt := StringList "*?.C" "*?.c" "*?.cc" "*?.cxx" "*?.cpp" -}}
{{$allFiles := Dir .dirname -}}
lib{{VarName .name -}}
_la_SOURCES ={{template "Multiline" Select $allFiles $sourceExt}}
{{$extraFiles := Exclude $allFiles $sourceExt -}}
{{if $extraFiles}}
EXTRA_DIST ={{template "Multiline" $extraFiles}}
{{end -}}
{{template "Snippet" .}}`)},
	embeddedTemplateFile{"tests/Makefile.am", 0644,
		[]byte(`{{template "FileHeader" . -}}
LDADD = ../src/lib$(PACKAGE).la

{{$sourceExt := StringList "*?.C" "*?.c" "*?.cc" "*?.cxx" "*?.cpp" -}}
{{$allFiles := Dir .dirname -}}
{{$testSources := Select $allFiles $sourceExt -}}
{{if eq (len $testSources) 0}}
{{Error "'lib' template requires at least one test_*.{cc,c} file under tests/"}}
{{end -}}
check_PROGRAMS ={{range $testSources}} \
	{{TrimExt .}}{{end}}

{{range $testSources -}}
{{VarName (TrimExt .)}}_SOURCES = {{.}}

{{end -}}
TESTS = $(check_PROGRAMS)
{{$extraFiles := Exclude $allFiles $sourceExt -}}
{{if $extraFiles}}
EXTRA_DIST ={{template "Multiline" $extraFiles}}
{{end -}}
{{template "Snippet" .}}`)},
	embeddedTemplateFile{"configure.ac", 0644,
		[]byte(`{{template "FileHeader" . -}}
AC_INIT([{{.name}}], [{{.version}}])
AC_CONFIG_AUX_DIR([config])
AC_CONFIG_MACRO_DIRS([m4])
{{$sources := Dir "src" -}}
{{if eq (len $sources) 0}}
{{Error "'lib' template requires at least one source file in src/"}}
{{end -}}
AC_CONFIG_SRCDIR([src/{{index $sources 0}}])
AC_CONFIG_HEADERS([config.h])
AM_INIT_AUTOMAKE([foreign])

{{if index . "version-info" -}}
library_version_info={{index . "version-info"}}
AC_SUBST(library_version_info)

{{end -}}
test -z "$CXXFLAGS" && CXXFLAGS=""

AC_PROG_CXX
LT_INIT([disable-shared])
PKG_PROG_PKG_CONFIG
PKG_INSTALLDIR

CPPFLAGS="$CPPFLAGS -I\$(top_srcdir)/include -I\$(top_builddir)/include"

dnl When compiling with GNU C++, display more warnings.
AS_IF([test "$GXX" = yes],
	[CXXFLAGS="$CXXFLAGS -ansi -pedantic -Wall \
-Woverloaded-virtual -Wsign-promo -W -Wshadow -Wpointer-arith -Wcast-qual \
-Wwrite-strings -Wconversion -Wsign-compare -Wredundant-decls -Winline"],
dnl Display all levels of the Digital (Compaq) C++ warnings.
[test "$CXX" = cxx &&
	cxx -V < /dev/null 2>&1 | grep -Eiq 'digital|compaq'],
	[DIGITALCXX="yes"
	CXXFLAGS="$CXXFLAGS -w0 -msg_display_tag -std strict_ansi"],
dnl Enable all warnings and remarks of the Intel C++ compiler.
[test "$CXX" = icpc && icpc -V < /dev/null 2>&1 | grep -iq intel],
	[CXXFLAGS="$CXXFLAGS -w2"])

AC_ARG_ENABLE(debug, AS_HELP_STRING([--enable-debug],
	[enable debug info and runtime checks (default=no)]))

AM_CONDITIONAL(DEBUG, [test "$enable_debug" = yes])

AS_IF([test "$enable_debug" != yes],
	[CXXFLAGS="$CXXFLAGS -O3"],
[AC_DEFINE([DEBUG], 1, [Define to 1 to enable various runtime checks.])
AS_IF([test "$GXX" = yes],
	[CXXFLAGS="$CXXFLAGS -ggdb"],
[test "$DIGITALCXX" = yes],
	[CXXFLAGS="$CXXFLAGS -gall"],
[test "$ac_cv_prog_cxx_g" = yes],
	[CXXFLAGS="$CXXFLAGS -g"])])
{{if or .external_libs .requires}}
dnl Checks for libraries.{{end}}{{if .external_libs}}{{range .external_libs}}
AC_CHECK_LIB([{{.name}}], [{{.function}}],,
	AC_MSG_ERROR([unable to link with {{.name}}]){{if .other_libs}},
	[{{.other_libs}}]{{end}}){{end}}
{{end}}{{if .requires}}
PKG_PROG_PKG_CONFIG()
{{range .requires}}
PKG_CHECK_MODULES([{{VarNameUC .}}], [{{VarName .}}])
CXXFLAGS="$CXXFLAGS ${{VarNameUC .}}_CFLAGS"
LIBS="$LIBS ${{VarNameUC .}}_LIBS"
{{end}}{{end -}}
{{template "Snippet" .}}
AC_SUBST(CONFIG_FLAGS)
AC_SUBST(CONFIG_LIBS)
AC_SUBST(PRIVATE_CONFIG_LIBS)
AC_SUBST(UNINST_PREFIX)
AC_SUBST(UNINST_FLAGS)
AC_SUBST(UNINST_LIBS)

AC_CONFIG_FILES([Makefile
include/Makefile
include/{{.name}}/Makefile
src/Makefile
tests/Makefile
{{.name}}.pc
{{.name}}-uninstalled.pc])
AC_OUTPUT
`)},
}
<commit_msg>Add .pc.in files to libtmpl<commit_after>// Copyright (C) 2017 Damon Revoe. All rights reserved.
// Use of this source code is governed by the MIT
// license, which can be found in the LICENSE file.

package main

var libTemplate = []embeddedTemplateFile{
	embeddedTemplateFile{"include/{name}/Makefile.am", 0644,
		[]byte(`{{template "FileHeader" . -}}
pkgincludedir = $(includedir)/{{.name}}

{{$headerExt := StringList "*?.H" "*?.h" "*?.hh" "*?.hxx" "*?.hpp" -}}
{{$allFiles := Dir .dirname -}}
pkginclude_HEADERS ={{template "Multiline" Select $allFiles $headerExt}}
{{$extraFiles := Exclude $allFiles $headerExt}}{{if $extraFiles}}
EXTRA_DIST ={{template "Multiline" $extraFiles}}
{{end}}
all: config.h

check: all

config.h: $(CONFIG_HEADER)
	sed -e 's/#\([^ ][^ ]*\) \([^ ][^ ]*\)/#\1 {{VarNameUC .name}}_\2/g' < \
		$(CONFIG_HEADER) > $@

install-data-hook: config.h
	$(INSTALL_DATA) config.h $(DESTDIR)$(pkgincludedir)/config.h

uninstall-hook:
	rm -f $(DESTDIR)$(pkgincludedir)/config.h
	rmdir $(DESTDIR)$(pkgincludedir) || true

# For older versions of Automake.
uninstall-local:
	rm -f $(DESTDIR)$(pkgincludedir)/config.h
	rmdir $(DESTDIR)$(pkgincludedir) || true

CLEANFILES = config.h
{{template "Snippet" .}}`)},
	embeddedTemplateFile{"include/Makefile.am", 0644,
		[]byte(`{{template "FileHeader" . -}}
SUBDIRS = {{.name}}
{{template "Snippet" .}}`)},
	embeddedTemplateFile{"src/Makefile.am", 0644,
		[]byte(`{{template "FileHeader" . -}}
lib_LTLIBRARIES = lib{{.name}}.la

{{if index . "version-info" -}}
lib{{VarName .name}}_la_LDFLAGS = -version-info @library_version_info@

{{end -}}
{{$sourceExt := StringList "*?.C" "*?.c" "*?.cc" "*?.cxx" "*?.cpp" -}}
{{$allFiles := Dir .dirname -}}
lib{{VarName .name -}}
_la_SOURCES ={{template "Multiline" Select $allFiles $sourceExt}}
{{$extraFiles := Exclude $allFiles $sourceExt -}}
{{if $extraFiles}}
EXTRA_DIST ={{template "Multiline" $extraFiles}}
{{end -}}
{{template "Snippet" .}}`)},
	embeddedTemplateFile{"tests/Makefile.am", 0644,
		[]byte(`{{template "FileHeader" . -}}
LDADD = ../src/lib$(PACKAGE).la

{{$sourceExt := StringList "*?.C" "*?.c" "*?.cc" "*?.cxx" "*?.cpp" -}}
{{$allFiles := Dir .dirname -}}
{{$testSources := Select $allFiles $sourceExt -}}
{{if eq (len $testSources) 0}}
{{Error "'lib' template requires at least one test_*.{cc,c} file under tests/"}}
{{end -}}
check_PROGRAMS ={{range $testSources}} \
	{{TrimExt .}}{{end}}

{{range $testSources -}}
{{VarName (TrimExt .)}}_SOURCES = {{.}}

{{end -}}
TESTS = $(check_PROGRAMS)
{{$extraFiles := Exclude $allFiles $sourceExt -}}
{{if $extraFiles}}
EXTRA_DIST ={{template "Multiline" $extraFiles}}
{{end -}}
{{template "Snippet" .}}`)},
	embeddedTemplateFile{"configure.ac", 0644,
		[]byte(`{{template "FileHeader" . -}}
AC_INIT([{{.name}}], [{{.version}}])
AC_CONFIG_AUX_DIR([config])
AC_CONFIG_MACRO_DIRS([m4])
{{$sources := Dir "src" -}}
{{if eq (len $sources) 0}}
{{Error "'lib' template requires at least one source file in src/"}}
{{end -}}
AC_CONFIG_SRCDIR([src/{{index $sources 0}}])
AC_CONFIG_HEADERS([config.h])
AM_INIT_AUTOMAKE([foreign])

{{if index . "version-info" -}}
library_version_info={{index . "version-info"}}
AC_SUBST(library_version_info)

{{end -}}
test -z "$CXXFLAGS" && CXXFLAGS=""

AC_PROG_CXX
LT_INIT([disable-shared])
PKG_PROG_PKG_CONFIG
PKG_INSTALLDIR

CPPFLAGS="$CPPFLAGS -I\$(top_srcdir)/include -I\$(top_builddir)/include"

dnl When compiling with GNU C++, display more warnings.
AS_IF([test "$GXX" = yes],
	[CXXFLAGS="$CXXFLAGS -ansi -pedantic -Wall \
-Woverloaded-virtual -Wsign-promo -W -Wshadow -Wpointer-arith -Wcast-qual \
-Wwrite-strings -Wconversion -Wsign-compare -Wredundant-decls -Winline"],
dnl Display all levels of the Digital (Compaq) C++ warnings.
[test "$CXX" = cxx &&
	cxx -V < /dev/null 2>&1 | grep -Eiq 'digital|compaq'],
	[DIGITALCXX="yes"
	CXXFLAGS="$CXXFLAGS -w0 -msg_display_tag -std strict_ansi"],
dnl Enable all warnings and remarks of the Intel C++ compiler.
[test "$CXX" = icpc && icpc -V < /dev/null 2>&1 | grep -iq intel],
	[CXXFLAGS="$CXXFLAGS -w2"])

AC_ARG_ENABLE(debug, AS_HELP_STRING([--enable-debug],
	[enable debug info and runtime checks (default=no)]))

AM_CONDITIONAL(DEBUG, [test "$enable_debug" = yes])

AS_IF([test "$enable_debug" != yes],
	[CXXFLAGS="$CXXFLAGS -O3"],
[AC_DEFINE([DEBUG], 1, [Define to 1 to enable various runtime checks.])
AS_IF([test "$GXX" = yes],
	[CXXFLAGS="$CXXFLAGS -ggdb"],
[test "$DIGITALCXX" = yes],
	[CXXFLAGS="$CXXFLAGS -gall"],
[test "$ac_cv_prog_cxx_g" = yes],
	[CXXFLAGS="$CXXFLAGS -g"])])
{{if or .external_libs .requires}}
dnl Checks for libraries.{{end}}{{if .external_libs}}{{range .external_libs}}
AC_CHECK_LIB([{{.name}}], [{{.function}}],,
	AC_MSG_ERROR([unable to link with {{.name}}]){{if .other_libs}},
	[{{.other_libs}}]{{end}}){{end}}
{{end}}{{if .requires}}
PKG_PROG_PKG_CONFIG()
{{range .requires}}
PKG_CHECK_MODULES([{{VarNameUC .}}], [{{VarName .}}])
CXXFLAGS="$CXXFLAGS ${{VarNameUC .}}_CFLAGS"
LIBS="$LIBS ${{VarNameUC .}}_LIBS"
{{end}}{{end -}}
{{template "Snippet" .}}
AC_SUBST(CONFIG_FLAGS)
AC_SUBST(CONFIG_LIBS)
AC_SUBST(PRIVATE_CONFIG_LIBS)
AC_SUBST(UNINST_PREFIX)
AC_SUBST(UNINST_FLAGS)
AC_SUBST(UNINST_LIBS)

AC_CONFIG_FILES([Makefile
include/Makefile
include/{{.name}}/Makefile
src/Makefile
tests/Makefile
{{.name}}.pc
{{.name}}-uninstalled.pc])
AC_OUTPUT
`)},
	embeddedTemplateFile{"{name}-uninstalled.pc.in", 0644,
		[]byte(`prefix=@UNINST_PREFIX@
exec_prefix=@UNINST_PREFIX@
libdir=@UNINST_PREFIX@/src
includedir=@UNINST_PREFIX@/include

Name: @PACKAGE_NAME@
Version: @PACKAGE_VERSION@
Libs: @UNINST_LIBS@
Libs.private: @PRIVATE_CONFIG_LIBS@
Cflags: @UNINST_FLAGS@
`)},
	embeddedTemplateFile{"{name}.pc.in", 0644,
		[]byte(`prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@

Name: @PACKAGE_NAME@
Version: @PACKAGE_VERSION@
Libs: @CONFIG_LIBS@
Libs.private: @PRIVATE_CONFIG_LIBS@
Cflags: @CONFIG_FLAGS@
`)},
}
<|endoftext|>


<commit_before>package main

type LicenseInfo struct {
	Author string
}
<commit_msg>Delete unnessary file<commit_after><|endoftext|>