<commit_before>package lib

import (
	"fmt"
	"os"
	"time"

	oss "github.com/aliyun/aliyun-oss-go-sdk/oss"
	. "gopkg.in/check.v1"
)

func (s *OssutilCommandSuite) TestRemoveObject(c *C) {
	bucket := bucketNameMB

	// put object
	object := "TestRemoveObject"
	s.putObject(bucket, object, uploadFileName, c)
	time.Sleep(2 * sleepTime)

	// list object
	objects := s.listObjects(bucket, object, "ls - ", c)
	c.Assert(len(objects), Equals, 1)
	c.Assert(objects[0], Equals, object)

	// remove object
	s.removeObjects(bucket, object, false, true, c)

	// list object
	objects = s.listObjects(bucket, object, "ls - ", c)
	c.Assert(len(objects), Equals, 0)
}

func (s *OssutilCommandSuite) TestRemoveObjects(c *C) {
	bucket := bucketNamePrefix + "rmb1"
	s.putBucket(bucket, c)
	time.Sleep(14 * time.Second)

	// put object
	num := 2
	objectNames := []string{}
	for i := 0; i < num; i++ {
		object := fmt.Sprintf("remove%d", i)
		s.putObject(bucket, object, uploadFileName, c)
		objectNames = append(objectNames, object)
	}
	time.Sleep(2 * sleepTime)

	command := "rm"
	args := []string{CloudURLToString(bucket, "")}
	str := ""
	ok := true
	options := OptionMapType{
		"endpoint":        &str,
		"accessKeyID":     &str,
		"accessKeySecret": &str,
		"stsToken":        &str,
		"configFile":      &configFile,
		"bucket":          &ok,
		"force":           &ok,
	}
	_, err := cm.RunCommand(command, args, options)
	c.Assert(err, NotNil)

	// list object
	objects := s.listObjects(bucket, "", "ls - ", c)
	c.Assert(len(objects), Equals, num)

	// "rm oss://bucket/ -r"
	// remove object
	s.removeObjects(bucket, "", true, false, c)

	objects = s.listObjects(bucket, "", "ls - ", c)
	c.Assert(len(objects), Equals, num)

	// "rm oss://bucket/prefix -r -f"
	// remove object
	s.removeObjects(bucket, "re", true, true, c)
	time.Sleep(3 * sleepTime)

	// list object
	objects = s.listObjects(bucket, "", "ls - ", c)
	c.Assert(len(objects), Equals, 0)

	//reput objects and delete bucket
	for i := 0; i < num; i++ {
		object := fmt.Sprintf("remove%d", i)
		s.putObject(bucket, object, uploadFileName, c)
	}

	// list buckets
	buckets := s.listBuckets(false, c)
	c.Assert(FindPos(bucket, buckets) != -1, Equals, true)

	// error remove bucket with config
	cfile := "ossutil_test.config_boto"
	data := fmt.Sprintf("[Credentials]\nendpoint=%s\naccessKeyID=%s\naccessKeySecret=%s\n[Bucket-Endpoint]\n%s=%s[Bucket-Cname]\n%s=%s", "abc", "def", "ghi", bucket, "abc", bucket, "abc")
	s.createFile(cfile, data, c)

	options = OptionMapType{
		"endpoint":        &str,
		"accessKeyID":     &str,
		"accessKeySecret": &str,
		"stsToken":        &str,
		"configFile":      &cfile,
		"recursive":       &ok,
		"bucket":          &ok,
		"force":           &ok,
	}
	showElapse, err := cm.RunCommand(command, args, options)
	c.Assert(err, NotNil)

	options = OptionMapType{
		"endpoint":        &endpoint,
		"accessKeyID":     &accessKeyID,
		"accessKeySecret": &accessKeySecret,
		"stsToken":        &str,
		"configFile":      &cfile,
		"recursive":       &ok,
		"bucket":          &ok,
		"force":           &ok,
	}
	showElapse, err = cm.RunCommand(command, args, options)
	c.Assert(err, IsNil)
	c.Assert(showElapse, Equals, true)

	_ = os.Remove(cfile)
	time.Sleep(2 * 7 * time.Second)

	// list buckets
	buckets = s.listBuckets(false, c)
	c.Assert(FindPos(bucket, buckets) == -1, Equals, true)
}

func (s *OssutilCommandSuite) TestRemoveObjectBucketOption(c *C) {
	bucket := bucketNameExist

	object := "test_object"
	command := "rm"
	args := []string{CloudURLToString(bucket, object)}
	str := ""
	ok := true
	options := OptionMapType{
		"endpoint":        &str,
		"accessKeyID":     &str,
		"accessKeySecret": &str,
		"stsToken":        &str,
		"configFile":      &configFile,
		"bucket":          &ok,
		"force":           &ok,
	}
	_, err := cm.RunCommand(command, args, options)
	c.Assert(err, NotNil)

	// list buckets
	buckets := s.listBuckets(false, c)
	c.Assert(FindPos(bucket, buckets) != -1, Equals, true)
}

func (s *OssutilCommandSuite) TestErrRemove(c *C) {
	bucket := bucketNameExist

	showElapse, err := s.rawRemove([]string{"oss://"}, false, true, true)
	c.Assert(err, NotNil)
	c.Assert(showElapse, Equals, false)

	showElapse, err = s.rawRemove([]string{"./"}, false, true, true)
	c.Assert(err, NotNil)
	c.Assert(showElapse, Equals, false)

	showElapse, err = s.rawRemove([]string{CloudURLToString(bucket, "")}, false, true, false)
	c.Assert(err, NotNil)
	c.Assert(showElapse, Equals, false)

    showElapse, err = s.rawRemove([]string{"oss:///object"}, false, true, false)
    c.Assert(err, NotNil)
    c.Assert(showElapse, Equals, false)

    // remove bucket without force
	showElapse, err = s.rawRemove([]string{CloudURLToString(bucket, "")}, false, false, true)
	c.Assert(err, IsNil)
	c.Assert(showElapse, Equals, true)

	bucketStat := s.getStat(bucket, "", c)
	c.Assert(bucketStat[StatName], Equals, bucket)

	// batch delete not exist objects
    object := "batch_delete_notexst_object"
    showElapse, err = s.rawRemove([]string{CloudURLToString(bucket, object)}, true, true, false)
    c.Assert(err, IsNil)
    c.Assert(showElapse, Equals, true)

    // clear not exist bucket
    bucketName := bucketNamePrefix + "rmnotexist"
    showElapse, err = s.rawRemove([]string{CloudURLToString(bucketName, "")}, true, true, false)
    c.Assert(err, NotNil)
    c.Assert(showElapse, Equals, false)

    // test oss batch delete not exist objects
    objects := []string{}
    ossBucket, err := removeCommand.command.ossBucket(bucket)
    c.Assert(err, IsNil)
    num, err := removeCommand.ossBatchDeleteObjectsRetry(ossBucket, objects)
    c.Assert(err, IsNil)
    c.Assert(num, Equals, 0)
}

func (s *OssutilCommandSuite) TestErrDeleteObject(c *C) {
	bucketName := bucketNameNotExist

	bucket, err := removeCommand.command.ossBucket(bucketName)
	c.Assert(err, IsNil)

	object := "object"
	err = removeCommand.ossDeleteObjectRetry(bucket, object)
	c.Assert(err, NotNil)

	_, err = removeCommand.ossBatchDeleteObjectsRetry(bucket, []string{object})
	c.Assert(err, NotNil)
}

func (s *OssutilCommandSuite) TestAllTypeObject(c *C) {
    bucketName := bucketNamePrefix + "alltype"
    s.putBucket(bucketName, c)

	//s.clearAllMultipartInBucket(bucketName, c)
    err = s.initRemove(bucketName, "", "rm -marf")
    c.Assert(err, IsNil)
    removeCommand.RunCommand()

	normal_object := "TestAllTypeObject"
	s.putObject(bucketName, normal_object, uploadFileName, c)
	time.Sleep(2 * sleepTime)

	object := "TestMultipartObjectRm"
	s.putObject(bucketName, object, uploadFileName, c)
	time.Sleep(2 * sleepTime)

	objects := s.listObjects(bucketName, object, "ls - ", c)
	c.Assert(len(objects), Equals, 1)
	c.Assert(objects[0], Equals, object)

	bucket, err := copyCommand.command.ossBucket(bucketName)
	for i := 0; i < 20; i++ {
		_, err = bucket.InitiateMultipartUpload(object)
		c.Assert(err, IsNil)
	}

	lmr, e := bucket.ListMultipartUploads(oss.Prefix(object))
	c.Assert(e, IsNil)
	c.Assert(len(lmr.Uploads), Equals, 20)

	_, e = s.removeWrapper("rm -arf", bucketName, object, c)
	c.Assert(e, IsNil)

	lmr, e = bucket.ListMultipartUploads(oss.Prefix(object))
	c.Assert(e, IsNil)
	c.Assert(len(lmr.Uploads), Equals, 0)

	// list normal_object
	objects = s.listObjects(bucketName, normal_object, "ls - ", c)
	c.Assert(len(objects), Equals, 1)
	c.Assert(objects[0], Equals, normal_object)

    err = s.initRemove(bucketName, "", "rm -marf")
    c.Assert(err, IsNil)
    removeCommand.RunCommand()
}

func (s *OssutilCommandSuite) TestMultipartUpload(c *C) {
	bucketName := bucketNameMB

	s.clearAllMultipartInBucket(bucketName, c)

	// put object
	object := "TestMultipartObject"
	s.putObject(bucketName, object, uploadFileName, c)
	time.Sleep(2 * sleepTime)

	// list object
	objects := s.listObjects(bucketName, object, "ls - ", c)
	c.Assert(len(objects), Equals, 1)
	c.Assert(objects[0], Equals, object)

	bucket, err := copyCommand.command.ossBucket(bucketName)
	for i := 0; i < 20; i++ {
		_, err = bucket.InitiateMultipartUpload(object)
		c.Assert(err, IsNil)
	}

	lmr, e := bucket.ListMultipartUploads(oss.Prefix(object))
	c.Assert(e, IsNil)
	c.Assert(len(lmr.Uploads), Equals, 20)

	_, e = s.removeWrapper("rm -mrf", bucketName, object, c)
	c.Assert(e, IsNil)

	lmr, e = bucket.ListMultipartUploads(oss.Prefix(object))
	c.Assert(e, IsNil)
	c.Assert(len(lmr.Uploads), Equals, 0)

	obj := "TestMultipartObjectUploads"
	s.putObject(bucketName, obj, uploadFileName, c)
	time.Sleep(4 * sleepTime)

	for i := 0; i < 20; i++ {
		_, err = bucket.InitiateMultipartUpload(obj)
		c.Assert(err, IsNil)
	}
	_, e = s.removeWrapper("rm -mrf", bucketName, "", c)
	c.Assert(e, IsNil)
	c.Assert(len(lmr.Uploads), Equals, 0)
}

func (s *OssutilCommandSuite) TestMultipartUpload_Prefix(c *C) {
	bucketName := bucketNameMB
	bucket, err := copyCommand.command.ossBucket(bucketName)
	c.Assert(err, IsNil)

	s.clearAllMultipartInBucket(bucketName, c)

	object := "TestMultipartObject"
	s.putObject(bucketName, object, uploadFileName, c)
	time.Sleep(2 * sleepTime)

	object1 := "TestMultipartObject" + "prefix"
	s.putObject(bucketName, object1, uploadFileName, c)
	time.Sleep(2 * sleepTime)

	object2 := "TestMultipartObject" + "/dir/test"
	s.putObject(bucketName, object2, uploadFileName, c)
	time.Sleep(2 * sleepTime)

	// list object
	objects := s.listObjects(bucketName, object, "ls - ", c)
	c.Assert(len(objects), Equals, 3)

	for i := 0; i < 20; i++ {
		_, err = bucket.InitiateMultipartUpload(object)
		c.Assert(err, IsNil)
	}

	for i := 0; i < 20; i++ {
		_, err = bucket.InitiateMultipartUpload(object1)
		c.Assert(err, IsNil)
	}

	for i := 0; i < 20; i++ {
		_, err = bucket.InitiateMultipartUpload(object2)
		c.Assert(err, IsNil)
	}

	lmr, e := bucket.ListMultipartUploads(oss.Prefix(object))
	c.Assert(e, IsNil)
	c.Assert(len(lmr.Uploads), Equals, 20*3)

	_, e = s.removeWrapper("rm -mrf", bucketName, "", c)
	c.Assert(e, IsNil)

	lmr, e = bucket.ListMultipartUploads(oss.Prefix(object))
	c.Assert(e, IsNil)
	c.Assert(len(lmr.Uploads), Equals, 0)
}

func (s *OssutilCommandSuite) TestMultipartError(c *C) {
	bucketName := bucketNameMB
	object := "TestMultipartError"

	_, e := s.removeWrapper("rm -mb", bucketName, object, c)
	c.Assert(e, NotNil)

	_, e = s.removeWrapper("rm -mf", bucketName, "", c)
	c.Assert(e, NotNil)
}

func (s *OssutilCommandSuite) TestAllTypeError(c *C) {
	bucketName := bucketNameMB
	object := "random"

	_, e := s.removeWrapper("rm -ab", bucketName, object, c)
	c.Assert(e, NotNil)
}
<commit_msg>modify case<commit_after>package lib

import (
	"fmt"
	"os"
	"time"

	oss "github.com/aliyun/aliyun-oss-go-sdk/oss"
	. "gopkg.in/check.v1"
)

func (s *OssutilCommandSuite) TestRemoveObject(c *C) {
	bucket := bucketNameMB

	// put object
	object := "TestRemoveObject"
	s.putObject(bucket, object, uploadFileName, c)
	time.Sleep(2 * sleepTime)

	// list object
	objects := s.listObjects(bucket, object, "ls - ", c)
	c.Assert(len(objects), Equals, 1)
	c.Assert(objects[0], Equals, object)

	// remove object
	s.removeObjects(bucket, object, false, true, c)

	// list object
	objects = s.listObjects(bucket, object, "ls - ", c)
	c.Assert(len(objects), Equals, 0)
}

func (s *OssutilCommandSuite) TestRemoveObjects(c *C) {
	bucket := bucketNamePrefix + "rmb1"
	s.putBucket(bucket, c)
	time.Sleep(14 * time.Second)

	// put object
	num := 2
	objectNames := []string{}
	for i := 0; i < num; i++ {
		object := fmt.Sprintf("remove%d", i)
		s.putObject(bucket, object, uploadFileName, c)
		objectNames = append(objectNames, object)
	}
	time.Sleep(2 * sleepTime)

	command := "rm"
	args := []string{CloudURLToString(bucket, "")}
	str := ""
	ok := true
	options := OptionMapType{
		"endpoint":        &str,
		"accessKeyID":     &str,
		"accessKeySecret": &str,
		"stsToken":        &str,
		"configFile":      &configFile,
		"bucket":          &ok,
		"force":           &ok,
	}
	_, err := cm.RunCommand(command, args, options)
	c.Assert(err, NotNil)

	// list object
	objects := s.listObjects(bucket, "", "ls - ", c)
	c.Assert(len(objects), Equals, num)

	// "rm oss://bucket/ -r"
	// remove object
	s.removeObjects(bucket, "", true, false, c)

	objects = s.listObjects(bucket, "", "ls - ", c)
	c.Assert(len(objects), Equals, num)

	// "rm oss://bucket/prefix -r -f"
	// remove object
	s.removeObjects(bucket, "re", true, true, c)
	time.Sleep(3 * sleepTime)

	// list object
	objects = s.listObjects(bucket, "", "ls - ", c)
	c.Assert(len(objects), Equals, 0)

	//reput objects and delete bucket
	for i := 0; i < num; i++ {
		object := fmt.Sprintf("remove%d", i)
		s.putObject(bucket, object, uploadFileName, c)
	}

	// list buckets
	buckets := s.listBuckets(false, c)
	c.Assert(FindPos(bucket, buckets) != -1, Equals, true)

	// error remove bucket with config
	cfile := "ossutil_test.config_boto"
	data := fmt.Sprintf("[Credentials]\nendpoint=%s\naccessKeyID=%s\naccessKeySecret=%s\n[Bucket-Endpoint]\n%s=%s[Bucket-Cname]\n%s=%s", "abc", "def", "ghi", bucket, "abc", bucket, "abc")
	s.createFile(cfile, data, c)

	options = OptionMapType{
		"endpoint":        &str,
		"accessKeyID":     &str,
		"accessKeySecret": &str,
		"stsToken":        &str,
		"configFile":      &cfile,
		"recursive":       &ok,
		"bucket":          &ok,
		"force":           &ok,
	}
	showElapse, err := cm.RunCommand(command, args, options)
	c.Assert(err, NotNil)

	options = OptionMapType{
		"endpoint":        &endpoint,
		"accessKeyID":     &accessKeyID,
		"accessKeySecret": &accessKeySecret,
		"stsToken":        &str,
		"configFile":      &cfile,
		"recursive":       &ok,
		"bucket":          &ok,
		"force":           &ok,
	}
	showElapse, err = cm.RunCommand(command, args, options)
	c.Assert(err, IsNil)
	c.Assert(showElapse, Equals, true)

	_ = os.Remove(cfile)
	time.Sleep(2 * 7 * time.Second)

	// list buckets
	buckets = s.listBuckets(false, c)
	c.Assert(FindPos(bucket, buckets) == -1, Equals, true)
}

func (s *OssutilCommandSuite) TestRemoveObjectBucketOption(c *C) {
	bucket := bucketNameExist

	object := "test_object"
	command := "rm"
	args := []string{CloudURLToString(bucket, object)}
	str := ""
	ok := true
	options := OptionMapType{
		"endpoint":        &str,
		"accessKeyID":     &str,
		"accessKeySecret": &str,
		"stsToken":        &str,
		"configFile":      &configFile,
		"bucket":          &ok,
		"force":           &ok,
	}
	_, err := cm.RunCommand(command, args, options)
	c.Assert(err, NotNil)

	// list buckets
	buckets := s.listBuckets(false, c)
	c.Assert(FindPos(bucket, buckets) != -1, Equals, true)
}

func (s *OssutilCommandSuite) TestErrRemove(c *C) {
	bucket := bucketNameExist

	showElapse, err := s.rawRemove([]string{"oss://"}, false, true, true)
	c.Assert(err, NotNil)
	c.Assert(showElapse, Equals, false)

	showElapse, err = s.rawRemove([]string{"./"}, false, true, true)
	c.Assert(err, NotNil)
	c.Assert(showElapse, Equals, false)

	showElapse, err = s.rawRemove([]string{CloudURLToString(bucket, "")}, false, true, false)
	c.Assert(err, NotNil)
	c.Assert(showElapse, Equals, false)

    showElapse, err = s.rawRemove([]string{"oss:///object"}, false, true, false)
    c.Assert(err, NotNil)
    c.Assert(showElapse, Equals, false)

    // remove bucket without force
	showElapse, err = s.rawRemove([]string{CloudURLToString(bucket, "")}, false, false, true)
	c.Assert(err, IsNil)
	c.Assert(showElapse, Equals, true)

	bucketStat := s.getStat(bucket, "", c)
	c.Assert(bucketStat[StatName], Equals, bucket)

	// batch delete not exist objects
    object := "batch_delete_notexst_object"
    showElapse, err = s.rawRemove([]string{CloudURLToString(bucket, object)}, true, true, false)
    c.Assert(err, IsNil)
    c.Assert(showElapse, Equals, true)

    // clear not exist bucket
    bucketName := bucketNamePrefix + "rmnotexist"
    showElapse, err = s.rawRemove([]string{CloudURLToString(bucketName, "")}, true, true, false)
    c.Assert(err, NotNil)
    c.Assert(showElapse, Equals, false)

    // test oss batch delete not exist objects
    objects := []string{}
    ossBucket, err := removeCommand.command.ossBucket(bucket)
    c.Assert(err, IsNil)
    num, err := removeCommand.ossBatchDeleteObjectsRetry(ossBucket, objects)
    c.Assert(err, IsNil)
    c.Assert(num, Equals, 0)
}

func (s *OssutilCommandSuite) TestErrDeleteObject(c *C) {
	bucketName := bucketNameNotExist

	bucket, err := removeCommand.command.ossBucket(bucketName)
	c.Assert(err, IsNil)

	object := "object"
	err = removeCommand.ossDeleteObjectRetry(bucket, object)
	c.Assert(err, NotNil)

	_, err = removeCommand.ossBatchDeleteObjectsRetry(bucket, []string{object})
	c.Assert(err, NotNil)
}

func (s *OssutilCommandSuite) TestAllTypeObject(c *C) {
    bucketName := bucketNamePrefix + "alltype"
    s.putBucket(bucketName, c)

	//s.clearAllMultipartInBucket(bucketName, c)
    err := s.initRemove(bucketName, "", "rm -marf")
    c.Assert(err, IsNil)
    removeCommand.RunCommand()

	normal_object := "TestAllTypeObject"
	s.putObject(bucketName, normal_object, uploadFileName, c)
	time.Sleep(2 * sleepTime)

	object := "TestMultipartObjectRm"
	s.putObject(bucketName, object, uploadFileName, c)
	time.Sleep(2 * sleepTime)

	objects := s.listObjects(bucketName, object, "ls - ", c)
	c.Assert(len(objects), Equals, 1)
	c.Assert(objects[0], Equals, object)

	bucket, err := copyCommand.command.ossBucket(bucketName)
	for i := 0; i < 20; i++ {
		_, err = bucket.InitiateMultipartUpload(object)
		c.Assert(err, IsNil)
	}

	lmr, e := bucket.ListMultipartUploads(oss.Prefix(object))
	c.Assert(e, IsNil)
	c.Assert(len(lmr.Uploads), Equals, 20)

	_, e = s.removeWrapper("rm -arf", bucketName, object, c)
	c.Assert(e, IsNil)

	lmr, e = bucket.ListMultipartUploads(oss.Prefix(object))
	c.Assert(e, IsNil)
	c.Assert(len(lmr.Uploads), Equals, 0)

	// list normal_object
	objects = s.listObjects(bucketName, normal_object, "ls - ", c)
	c.Assert(len(objects), Equals, 1)
	c.Assert(objects[0], Equals, normal_object)

    err = s.initRemove(bucketName, "", "rm -marf")
    c.Assert(err, IsNil)
    removeCommand.RunCommand()
}

func (s *OssutilCommandSuite) TestMultipartUpload(c *C) {
	bucketName := bucketNameMB

	s.clearAllMultipartInBucket(bucketName, c)

	// put object
	object := "TestMultipartObject"
	s.putObject(bucketName, object, uploadFileName, c)
	time.Sleep(2 * sleepTime)

	// list object
	objects := s.listObjects(bucketName, object, "ls - ", c)
	c.Assert(len(objects), Equals, 1)
	c.Assert(objects[0], Equals, object)

	bucket, err := copyCommand.command.ossBucket(bucketName)
	for i := 0; i < 20; i++ {
		_, err = bucket.InitiateMultipartUpload(object)
		c.Assert(err, IsNil)
	}

	lmr, e := bucket.ListMultipartUploads(oss.Prefix(object))
	c.Assert(e, IsNil)
	c.Assert(len(lmr.Uploads), Equals, 20)

	_, e = s.removeWrapper("rm -mrf", bucketName, object, c)
	c.Assert(e, IsNil)

	lmr, e = bucket.ListMultipartUploads(oss.Prefix(object))
	c.Assert(e, IsNil)
	c.Assert(len(lmr.Uploads), Equals, 0)

	obj := "TestMultipartObjectUploads"
	s.putObject(bucketName, obj, uploadFileName, c)
	time.Sleep(4 * sleepTime)

	for i := 0; i < 20; i++ {
		_, err = bucket.InitiateMultipartUpload(obj)
		c.Assert(err, IsNil)
	}
	_, e = s.removeWrapper("rm -mrf", bucketName, "", c)
	c.Assert(e, IsNil)
	c.Assert(len(lmr.Uploads), Equals, 0)
}

func (s *OssutilCommandSuite) TestMultipartUpload_Prefix(c *C) {
	bucketName := bucketNameMB
	bucket, err := copyCommand.command.ossBucket(bucketName)
	c.Assert(err, IsNil)

	s.clearAllMultipartInBucket(bucketName, c)

	object := "TestMultipartObject"
	s.putObject(bucketName, object, uploadFileName, c)
	time.Sleep(2 * sleepTime)

	object1 := "TestMultipartObject" + "prefix"
	s.putObject(bucketName, object1, uploadFileName, c)
	time.Sleep(2 * sleepTime)

	object2 := "TestMultipartObject" + "/dir/test"
	s.putObject(bucketName, object2, uploadFileName, c)
	time.Sleep(2 * sleepTime)

	// list object
	objects := s.listObjects(bucketName, object, "ls - ", c)
	c.Assert(len(objects), Equals, 3)

	for i := 0; i < 20; i++ {
		_, err = bucket.InitiateMultipartUpload(object)
		c.Assert(err, IsNil)
	}

	for i := 0; i < 20; i++ {
		_, err = bucket.InitiateMultipartUpload(object1)
		c.Assert(err, IsNil)
	}

	for i := 0; i < 20; i++ {
		_, err = bucket.InitiateMultipartUpload(object2)
		c.Assert(err, IsNil)
	}

	lmr, e := bucket.ListMultipartUploads(oss.Prefix(object))
	c.Assert(e, IsNil)
	c.Assert(len(lmr.Uploads), Equals, 20*3)

	_, e = s.removeWrapper("rm -mrf", bucketName, "", c)
	c.Assert(e, IsNil)

	lmr, e = bucket.ListMultipartUploads(oss.Prefix(object))
	c.Assert(e, IsNil)
	c.Assert(len(lmr.Uploads), Equals, 0)
}

func (s *OssutilCommandSuite) TestMultipartError(c *C) {
	bucketName := bucketNameMB
	object := "TestMultipartError"

	_, e := s.removeWrapper("rm -mb", bucketName, object, c)
	c.Assert(e, NotNil)

	_, e = s.removeWrapper("rm -mf", bucketName, "", c)
	c.Assert(e, NotNil)
}

func (s *OssutilCommandSuite) TestAllTypeError(c *C) {
	bucketName := bucketNameMB
	object := "random"

	_, e := s.removeWrapper("rm -ab", bucketName, object, c)
	c.Assert(e, NotNil)
}
<|endoftext|>


<commit_before>package hdf5

// #include <stdlib.h>
// #include <string.h>
// #include <hdf5.h>
import "C"

import (
	"errors"
	"reflect"
	"unsafe"
)

// Get reads data from the file.
func (f *File) Get(name string, something interface{}) error {
	value := reflect.ValueOf(something)
	if value.Kind() != reflect.Ptr {
		return errors.New("expected a pointer")
	}

	value = reflect.Indirect(value)

	cname := C.CString(name)
	defer C.free(unsafe.Pointer(cname))

	did := C.H5Dopen2(f.fid, cname, C.H5P_DEFAULT)
	if did < 0 {
		return errors.New("cannot find the dataset")
	}
	defer C.H5Dclose(did)

	object := newObject()
	defer object.free()

	object.tid = C.H5Dget_type(did)
	if object.tid < 0 {
		return errors.New("cannot get the datatype of the dataset")
	}

	if err := initializeToGet(object, value); err != nil {
		return err
	}

	if C.H5Dread(did, object.tid, C.H5S_ALL, C.H5S_ALL, C.H5P_DEFAULT, object.data) != 0 {
		return errors.New("cannot read the dataset from the file")
	}

	if err := finalizeObjectToGet(object, value); err != nil {
		return err
	}

	return nil
}

func initializeToGet(object *object, value reflect.Value) error {
	switch value.Kind() {
	case reflect.Slice:
		return initializeSliceToGet(object, value)
	case reflect.Struct:
		return initializeStructToGet(object, value)
	default:
		return initializeScalarToGet(object, value)
	}
}

func finalizeObjectToGet(object *object, value reflect.Value) error {
	switch value.Kind() {
	case reflect.Struct:
		return finalizeStructToGet(object, value)
	default:
		return nil
	}
}

func initializeScalarToGet(object *object, value reflect.Value) error {
	bid, ok := kindTypeMapping[value.Kind()]
	if !ok {
		return errors.New("encountered an unsupported datatype")
	}

	if err := checkArrayType(object.tid, bid); err != nil {
		return err
	}

	if length, err := computeArrayLength(object.tid); err != nil {
		return err
	} else if length != 1 {
		return errors.New("expected an array with a single element")
	}

	object.data = unsafe.Pointer(value.Addr().Pointer())

	return nil
}

func initializeSliceToGet(object *object, value reflect.Value) error {
	typo := value.Type()

	bid, ok := kindTypeMapping[typo.Elem().Kind()]
	if !ok {
		return errors.New("encountered an unsupported datatype")
	}

	if err := checkArrayType(object.tid, bid); err != nil {
		return err
	}

	length, err := computeArrayLength(object.tid)
	if err != nil {
		return err
	}

	buffer := reflect.MakeSlice(typo, int(length), int(length))
	shadow := reflect.Indirect(reflect.New(typo))
	shadow.Set(buffer)

	src := (*reflect.SliceHeader)(unsafe.Pointer(shadow.UnsafeAddr()))
	dst := (*reflect.SliceHeader)(unsafe.Pointer(value.UnsafeAddr()))

	dst.Data, src.Data = src.Data, dst.Data
	dst.Cap, src.Cap = src.Cap, dst.Cap
	dst.Len, src.Len = src.Len, dst.Len

	object.data = unsafe.Pointer(dst.Data)
	object.flag |= flagVariableLength

	return nil
}

func initializeStructToGet(object *object, value reflect.Value) error {
	if tid := C.H5Tget_class(object.tid); tid < 0 {
		return errors.New("cannot get a data class")
	} else if tid != C.H5T_COMPOUND {
		return errors.New("expected a compound datatype")
	}

	size := C.H5Tget_size(object.tid)
	if size < 0 {
		return errors.New("cannot get the size of a compound datatype")
	}

	object.data = C.malloc(size)
	if object.data == nil {
		return errors.New("cannot allocate memory")
	}
	object.flag |= flagOwnedMemory

	return nil
}

func finalizeStructToGet(object *object, value reflect.Value) error {
	typo := value.Type()
	count := typo.NumField()

	for i := 0; i < count; i++ {
		field := typo.Field(i)

		cname := C.CString(field.Name)
		defer C.free(unsafe.Pointer(cname))

		j := C.H5Tget_member_index(object.tid, cname)
		if j < 0 {
			continue
		}

		o := object.new()

		o.tid = C.H5Tget_member_type(object.tid, C.uint(j))
		if o.tid < 0 {
			return errors.New("cannot get the datatype of a field")
		}

		if cid := C.H5Tget_class(o.tid); cid < 0 {
			return errors.New("cannot get the data class of a field")
		} else if cid == C.H5T_VLEN {
			if tid := C.H5Tget_super(o.tid); tid < 0 { // Close?
				return errors.New("cannot get the base type of a field")
			} else {
				o = object.new()
				o.tid = tid
			}
		}

		if err := initializeToGet(o, value.Field(i)); err != nil {
			return err
		}

		size := C.H5Tget_size(o.tid)
		if size < 0 {
			return errors.New("cannot get a size")
		}

		offset := C.H5Tget_member_offset(object.tid, C.uint(j))
		address := unsafe.Pointer(uintptr(object.data) + uintptr(offset))

		if o.flag&flagVariableLength != 0 {
			h := (*C.hvl_t)(address)
			if h.len != 1 {
				return errors.New("expected a variable-length datatype with a single element")
			}
			address = h.p
		}

		C.memcpy(o.data, address, size)
	}

	return nil
}

func checkArrayType(tid C.hid_t, bid C.hid_t) error {
	if cid := C.H5Tget_class(tid); cid < 0 {
		return errors.New("cannot get a data class")
	} else if cid != C.H5T_ARRAY {
		return errors.New("expected an array datatype")
	}

	if tid := C.H5Tget_super(tid); tid < 0 { // Close?
		return errors.New("cannot get the base type of a datatype")
	} else if C.H5Tequal(bid, tid) == 0 {
		return errors.New("the types do not match")
	}

	return nil
}

func computeArrayLength(tid C.hid_t) (C.hsize_t, error) {
	nd := C.H5Tget_array_ndims(tid)
	if nd < 0 {
		return 0, errors.New("cannot get the dimensionality of an array")
	}

	dimensions := make([]C.hsize_t, nd)
	if C.H5Tget_array_dims2(tid, (*C.hsize_t)(unsafe.Pointer(&dimensions[0]))) != nd {
		return 0, errors.New("cannot get the dimensions of an array")
	}

	length := C.hsize_t(1)
	for i := range dimensions {
		length *= dimensions[i]
	}

	return length, nil
}
<commit_msg>Rename a function<commit_after>package hdf5

// #include <stdlib.h>
// #include <string.h>
// #include <hdf5.h>
import "C"

import (
	"errors"
	"reflect"
	"unsafe"
)

// Get reads data from the file.
func (f *File) Get(name string, something interface{}) error {
	value := reflect.ValueOf(something)
	if value.Kind() != reflect.Ptr {
		return errors.New("expected a pointer")
	}

	value = reflect.Indirect(value)

	cname := C.CString(name)
	defer C.free(unsafe.Pointer(cname))

	did := C.H5Dopen2(f.fid, cname, C.H5P_DEFAULT)
	if did < 0 {
		return errors.New("cannot find the dataset")
	}
	defer C.H5Dclose(did)

	object := newObject()
	defer object.free()

	object.tid = C.H5Dget_type(did)
	if object.tid < 0 {
		return errors.New("cannot get the datatype of the dataset")
	}

	if err := initializeToGet(object, value); err != nil {
		return err
	}

	if C.H5Dread(did, object.tid, C.H5S_ALL, C.H5S_ALL, C.H5P_DEFAULT, object.data) != 0 {
		return errors.New("cannot read the dataset from the file")
	}

	if err := finalizeToGet(object, value); err != nil {
		return err
	}

	return nil
}

func initializeToGet(object *object, value reflect.Value) error {
	switch value.Kind() {
	case reflect.Slice:
		return initializeSliceToGet(object, value)
	case reflect.Struct:
		return initializeStructToGet(object, value)
	default:
		return initializeScalarToGet(object, value)
	}
}

func finalizeToGet(object *object, value reflect.Value) error {
	switch value.Kind() {
	case reflect.Struct:
		return finalizeStructToGet(object, value)
	default:
		return nil
	}
}

func initializeScalarToGet(object *object, value reflect.Value) error {
	bid, ok := kindTypeMapping[value.Kind()]
	if !ok {
		return errors.New("encountered an unsupported datatype")
	}

	if err := checkArrayType(object.tid, bid); err != nil {
		return err
	}

	if length, err := computeArrayLength(object.tid); err != nil {
		return err
	} else if length != 1 {
		return errors.New("expected an array with a single element")
	}

	object.data = unsafe.Pointer(value.Addr().Pointer())

	return nil
}

func initializeSliceToGet(object *object, value reflect.Value) error {
	typo := value.Type()

	bid, ok := kindTypeMapping[typo.Elem().Kind()]
	if !ok {
		return errors.New("encountered an unsupported datatype")
	}

	if err := checkArrayType(object.tid, bid); err != nil {
		return err
	}

	length, err := computeArrayLength(object.tid)
	if err != nil {
		return err
	}

	buffer := reflect.MakeSlice(typo, int(length), int(length))
	shadow := reflect.Indirect(reflect.New(typo))
	shadow.Set(buffer)

	src := (*reflect.SliceHeader)(unsafe.Pointer(shadow.UnsafeAddr()))
	dst := (*reflect.SliceHeader)(unsafe.Pointer(value.UnsafeAddr()))

	dst.Data, src.Data = src.Data, dst.Data
	dst.Cap, src.Cap = src.Cap, dst.Cap
	dst.Len, src.Len = src.Len, dst.Len

	object.data = unsafe.Pointer(dst.Data)
	object.flag |= flagVariableLength

	return nil
}

func initializeStructToGet(object *object, value reflect.Value) error {
	if tid := C.H5Tget_class(object.tid); tid < 0 {
		return errors.New("cannot get a data class")
	} else if tid != C.H5T_COMPOUND {
		return errors.New("expected a compound datatype")
	}

	size := C.H5Tget_size(object.tid)
	if size < 0 {
		return errors.New("cannot get the size of a compound datatype")
	}

	object.data = C.malloc(size)
	if object.data == nil {
		return errors.New("cannot allocate memory")
	}
	object.flag |= flagOwnedMemory

	return nil
}

func finalizeStructToGet(object *object, value reflect.Value) error {
	typo := value.Type()
	count := typo.NumField()

	for i := 0; i < count; i++ {
		field := typo.Field(i)

		cname := C.CString(field.Name)
		defer C.free(unsafe.Pointer(cname))

		j := C.H5Tget_member_index(object.tid, cname)
		if j < 0 {
			continue
		}

		o := object.new()

		o.tid = C.H5Tget_member_type(object.tid, C.uint(j))
		if o.tid < 0 {
			return errors.New("cannot get the datatype of a field")
		}

		if cid := C.H5Tget_class(o.tid); cid < 0 {
			return errors.New("cannot get the data class of a field")
		} else if cid == C.H5T_VLEN {
			if tid := C.H5Tget_super(o.tid); tid < 0 { // Close?
				return errors.New("cannot get the base type of a field")
			} else {
				o = object.new()
				o.tid = tid
			}
		}

		if err := initializeToGet(o, value.Field(i)); err != nil {
			return err
		}

		size := C.H5Tget_size(o.tid)
		if size < 0 {
			return errors.New("cannot get a size")
		}

		offset := C.H5Tget_member_offset(object.tid, C.uint(j))
		address := unsafe.Pointer(uintptr(object.data) + uintptr(offset))

		if o.flag&flagVariableLength != 0 {
			h := (*C.hvl_t)(address)
			if h.len != 1 {
				return errors.New("expected a variable-length datatype with a single element")
			}
			address = h.p
		}

		C.memcpy(o.data, address, size)
	}

	return nil
}

func checkArrayType(tid C.hid_t, bid C.hid_t) error {
	if cid := C.H5Tget_class(tid); cid < 0 {
		return errors.New("cannot get a data class")
	} else if cid != C.H5T_ARRAY {
		return errors.New("expected an array datatype")
	}

	if tid := C.H5Tget_super(tid); tid < 0 { // Close?
		return errors.New("cannot get the base type of a datatype")
	} else if C.H5Tequal(bid, tid) == 0 {
		return errors.New("the types do not match")
	}

	return nil
}

func computeArrayLength(tid C.hid_t) (C.hsize_t, error) {
	nd := C.H5Tget_array_ndims(tid)
	if nd < 0 {
		return 0, errors.New("cannot get the dimensionality of an array")
	}

	dimensions := make([]C.hsize_t, nd)
	if C.H5Tget_array_dims2(tid, (*C.hsize_t)(unsafe.Pointer(&dimensions[0]))) != nd {
		return 0, errors.New("cannot get the dimensions of an array")
	}

	length := C.hsize_t(1)
	for i := range dimensions {
		length *= dimensions[i]
	}

	return length, nil
}
<|endoftext|>


<commit_before>package contour

import "reflect"

// Get functions and methods.
//
// E versions return an error if one occurs. Non-E versions return the zero
// value if an error occurs.

// GetE returns the key's Value as an interface{}. An SettingNotFoundErr is
// returned if the key doesn't exist.
func GetE(k string) (interface{}, error) { return settings.GetE(k) }

// GetE returns the key's Value as an interface{}. An SettingNotFoundErr is
// returned if the key doesn't exist.
func (s *Settings) GetE(k string) (interface{}, error) {
	s.mu.RLock()
	defer s.mu.RUnlock()
	return s.get(k)
}

// This assumes the lock has already been obtained. Since this is not exported,
// it does not need to end with E to signify it returns an error as it can be
// assumed it does.
func (s *Settings) get(k string) (interface{}, error) {
	_, ok := s.settings[k]
	if !ok {
		return nil, SettingNotFoundErr{name: k}
	}
	return s.settings[k].Value, nil
}

// Get returns the key's value as an interface{}. A nil is returned if the key
// doesn't exist.
func Get(k string) interface{} { return settings.Get(k) }

// Get returns the key's value as an interface{}. A nil is returned if the key
// doesn't exist.
func (s *Settings) Get(k string) interface{} {
	v, _ := s.GetE(k)
	return v
}

// BoolE returns the key's value as a bool. A SettingNotFoundErr is returned
// if the key doesn't exist. A DataTypeErr will be returned if the setting's
// type is not bool.
func BoolE(k string) (bool, error) { return settings.BoolE(k) }

// BoolE returns the key's value as a bool. A SettingNotFoundErr is returned
// if the key doesn't exist. A DataTypeErr will be returned if the setting's
// type is not bool.
func (s *Settings) BoolE(k string) (bool, error) {
	v, err := s.GetE(k)
	if err != nil {
		return false, err
	}
	switch v.(type) {
	case bool:
		return v.(bool), nil
	case *bool:
		return *v.(*bool), nil
	}
	// Isn't a bool.
	return false, DataTypeErr{name: k, is: reflect.TypeOf(v).String(), not: _bool}
}

// Bool returns the key's value as a bool. A false will be returned if the key
// either doesn't exist or the setting's type is not bool.
func Bool(k string) bool { return settings.Bool(k) }

// Bool returns the key's value as a bool. A false will be returned if the key
// either doesn't exist or the setting's type is not bool.
func (s *Settings) Bool(k string) bool {
	v, _ := s.BoolE(k)
	return v
}

// IntE returns the key's value as an int. A SettingNotFoundErr is returned if
// the key doesn't exist. A DataTypeErr will be returned if the setting's type
// is not int.
func IntE(k string) (int, error) { return settings.IntE(k) }

// IntE returns the key's value as an int. A SettingNotFoundErr is returned if
// the key doesn't exist. A DataTypeErr will be returned if the setting's type
// is not int.
func (s *Settings) IntE(k string) (int, error) {
	s.mu.Lock()
	defer s.mu.Unlock()
	return s.int(k)
}

// This assumes the lock has already been obtained. Unexported methods don't
// need to be suffixed with E to show they return an error.
func (s *Settings) int(k string) (int, error) {
	v, err := s.get(k)
	if err != nil {
		return 0, err
	}
	switch v.(type) {
	case int:
		return v.(int), nil
	case *int:
		return *v.(*int), nil
	}

	// Isn't an int.
	return 0, DataTypeErr{name: k, is: reflect.TypeOf(v).String(), not: _int}
}

// Int returns the key's value as an int. A 0 will be returned if the key
// either doesn't exist or is not an int setting.
func Int(k string) int { return settings.Int(k) }

// Int returns the key's value as an int. A 0 will be returned if the key
// either doesn't exist or is not an int setting.
func (s *Settings) Int(k string) int {
	v, _ := s.IntE(k)
	return v
}

// Int64E returns the key's value as an int64. A SettingNotFoundErr is returned
// if the key doesn't exist. A DataTypeErr will be returned if the setting's
// type is neither an int64 not an int.
func Int64E(k string) (int64, error) { return settings.Int64E(k) }

// Int64E returns the key's value as an int64. A SettingNotFoundErr is returned
// if the key doesn't exist. A DataTypeErr will be returned if the setting's
// type is neither an int64 not an int.
func (s *Settings) Int64E(k string) (int64, error) {
	s.mu.Lock()
	defer s.mu.Unlock()
	return s.int64(k)
}

// It is assumed that the caller has the lock. Unexported methods don't need
// to be suffixed with an E to signify they return an error.
func (s *Settings) int64(k string) (int64, error) {
	v, err := s.get(k)
	if err != nil {
		return 0, err
	}
	switch v.(type) {
	case int64:
		return v.(int64), nil
	case *int64:
		return *v.(*int64), nil
	case int:
		return int64(v.(int)), nil
	case *int:
		return int64(*v.(*int)), nil
	}

	// Is neither an int64 nor an int.
	return 0, DataTypeErr{name: k, is: reflect.TypeOf(v).String(), not: _int64}
}

// Int64 returns the key's value as an int64. A 0 will be returned if the key
// either doesn't exist or is neither an int64 nor an int setting.
func Int64(k string) int64 { return settings.Int64(k) }

// Int64 returns the key's value as an int64. A 0 will be returned if the key
// either doesn't exist or is neither an int64 nor an int setting.
func (s *Settings) Int64(k string) int64 {
	v, _ := s.Int64E(k)
	return v
}

// StringE returns the key's value as a string. A SettingNotFoundErr is
// returned if the key doesn't exist. A DataTypeErr will be returned if the
// setting's type is not a string.
func StringE(k string) (string, error) { return settings.StringE(k) }

// StringE returns the key's value as a string. A SettingNotFoundErr is
// returned if the key doesn't exist. A DataTypeErr will be returned if the
// setting's type is not a string.
func (s *Settings) StringE(k string) (string, error) {
	s.mu.Lock()
	defer s.mu.Unlock()
	return s.string(k)
}

// It is assumed that the caller holds the lock. Unexported methods don't need
// to be suffixed with E to signify they return an error.
func (s *Settings) string(k string) (string, error) {
	v, err := s.get(k)
	if err != nil {
		return "", err
	}
	switch v.(type) {
	case string:
		return v.(string), nil
	case *string:
		return *v.(*string), nil
	}

	// Isn't a string.
	return "", DataTypeErr{name: k, is: reflect.TypeOf(v).String(), not: _string}
}

// String returns the key's value as a string. An empty string, "", will be
// returned if the key either doesn't exist or is not a string setting.
func String(k string) string { return settings.String(k) }

// String returns the key's value as a string. An empty string, "", will be
// returned if the key either doesn't exist or is not a string setting.
func (s *Settings) String(k string) string {
	v, _ := s.StringE(k)
	return v
}

// ConfFilename returns the configuration filename. and its format. If the key
// is not registered, or if the format isn't a supported format, an error is
// returned and the format will be Unsupported.
func ConfFilename() (name string, format Format, err error) { return settings.ConfFilename() }
func (s *Settings) ConfFilename() (name string, format Format, err error) {
	s.mu.Lock()
	defer s.mu.Unlock()
	v, ok := s.settings[s.confFilenameVarName]
	if !ok {
		return "", Unsupported, SettingNotFoundErr{Core, s.confFilenameVarName}
	}
	format, _ = ParseFilenameFormat(v.Name)
	return v.Name, format, nil
}
<commit_msg>update ConfFileName to use Settings.ConfFileName instead of trying to find it in the settings map; only return the value, don't return format or error<commit_after>package contour

import "reflect"

// Get functions and methods.
//
// E versions return an error if one occurs. Non-E versions return the zero
// value if an error occurs.

// GetE returns the key's Value as an interface{}. An SettingNotFoundErr is
// returned if the key doesn't exist.
func GetE(k string) (interface{}, error) { return settings.GetE(k) }

// GetE returns the key's Value as an interface{}. An SettingNotFoundErr is
// returned if the key doesn't exist.
func (s *Settings) GetE(k string) (interface{}, error) {
	s.mu.RLock()
	defer s.mu.RUnlock()
	return s.get(k)
}

// This assumes the lock has already been obtained. Since this is not exported,
// it does not need to end with E to signify it returns an error as it can be
// assumed it does.
func (s *Settings) get(k string) (interface{}, error) {
	_, ok := s.settings[k]
	if !ok {
		return nil, SettingNotFoundErr{name: k}
	}
	return s.settings[k].Value, nil
}

// Get returns the key's value as an interface{}. A nil is returned if the key
// doesn't exist.
func Get(k string) interface{} { return settings.Get(k) }

// Get returns the key's value as an interface{}. A nil is returned if the key
// doesn't exist.
func (s *Settings) Get(k string) interface{} {
	v, _ := s.GetE(k)
	return v
}

// BoolE returns the key's value as a bool. A SettingNotFoundErr is returned
// if the key doesn't exist. A DataTypeErr will be returned if the setting's
// type is not bool.
func BoolE(k string) (bool, error) { return settings.BoolE(k) }

// BoolE returns the key's value as a bool. A SettingNotFoundErr is returned
// if the key doesn't exist. A DataTypeErr will be returned if the setting's
// type is not bool.
func (s *Settings) BoolE(k string) (bool, error) {
	v, err := s.GetE(k)
	if err != nil {
		return false, err
	}
	switch v.(type) {
	case bool:
		return v.(bool), nil
	case *bool:
		return *v.(*bool), nil
	}
	// Isn't a bool.
	return false, DataTypeErr{name: k, is: reflect.TypeOf(v).String(), not: _bool}
}

// Bool returns the key's value as a bool. A false will be returned if the key
// either doesn't exist or the setting's type is not bool.
func Bool(k string) bool { return settings.Bool(k) }

// Bool returns the key's value as a bool. A false will be returned if the key
// either doesn't exist or the setting's type is not bool.
func (s *Settings) Bool(k string) bool {
	v, _ := s.BoolE(k)
	return v
}

// IntE returns the key's value as an int. A SettingNotFoundErr is returned if
// the key doesn't exist. A DataTypeErr will be returned if the setting's type
// is not int.
func IntE(k string) (int, error) { return settings.IntE(k) }

// IntE returns the key's value as an int. A SettingNotFoundErr is returned if
// the key doesn't exist. A DataTypeErr will be returned if the setting's type
// is not int.
func (s *Settings) IntE(k string) (int, error) {
	s.mu.Lock()
	defer s.mu.Unlock()
	return s.int(k)
}

// This assumes the lock has already been obtained. Unexported methods don't
// need to be suffixed with E to show they return an error.
func (s *Settings) int(k string) (int, error) {
	v, err := s.get(k)
	if err != nil {
		return 0, err
	}
	switch v.(type) {
	case int:
		return v.(int), nil
	case *int:
		return *v.(*int), nil
	}

	// Isn't an int.
	return 0, DataTypeErr{name: k, is: reflect.TypeOf(v).String(), not: _int}
}

// Int returns the key's value as an int. A 0 will be returned if the key
// either doesn't exist or is not an int setting.
func Int(k string) int { return settings.Int(k) }

// Int returns the key's value as an int. A 0 will be returned if the key
// either doesn't exist or is not an int setting.
func (s *Settings) Int(k string) int {
	v, _ := s.IntE(k)
	return v
}

// Int64E returns the key's value as an int64. A SettingNotFoundErr is returned
// if the key doesn't exist. A DataTypeErr will be returned if the setting's
// type is neither an int64 not an int.
func Int64E(k string) (int64, error) { return settings.Int64E(k) }

// Int64E returns the key's value as an int64. A SettingNotFoundErr is returned
// if the key doesn't exist. A DataTypeErr will be returned if the setting's
// type is neither an int64 not an int.
func (s *Settings) Int64E(k string) (int64, error) {
	s.mu.Lock()
	defer s.mu.Unlock()
	return s.int64(k)
}

// It is assumed that the caller has the lock. Unexported methods don't need
// to be suffixed with an E to signify they return an error.
func (s *Settings) int64(k string) (int64, error) {
	v, err := s.get(k)
	if err != nil {
		return 0, err
	}
	switch v.(type) {
	case int64:
		return v.(int64), nil
	case *int64:
		return *v.(*int64), nil
	case int:
		return int64(v.(int)), nil
	case *int:
		return int64(*v.(*int)), nil
	}

	// Is neither an int64 nor an int.
	return 0, DataTypeErr{name: k, is: reflect.TypeOf(v).String(), not: _int64}
}

// Int64 returns the key's value as an int64. A 0 will be returned if the key
// either doesn't exist or is neither an int64 nor an int setting.
func Int64(k string) int64 { return settings.Int64(k) }

// Int64 returns the key's value as an int64. A 0 will be returned if the key
// either doesn't exist or is neither an int64 nor an int setting.
func (s *Settings) Int64(k string) int64 {
	v, _ := s.Int64E(k)
	return v
}

// StringE returns the key's value as a string. A SettingNotFoundErr is
// returned if the key doesn't exist. A DataTypeErr will be returned if the
// setting's type is not a string.
func StringE(k string) (string, error) { return settings.StringE(k) }

// StringE returns the key's value as a string. A SettingNotFoundErr is
// returned if the key doesn't exist. A DataTypeErr will be returned if the
// setting's type is not a string.
func (s *Settings) StringE(k string) (string, error) {
	s.mu.Lock()
	defer s.mu.Unlock()
	return s.string(k)
}

// It is assumed that the caller holds the lock. Unexported methods don't need
// to be suffixed with E to signify they return an error.
func (s *Settings) string(k string) (string, error) {
	v, err := s.get(k)
	if err != nil {
		return "", err
	}
	switch v.(type) {
	case string:
		return v.(string), nil
	case *string:
		return *v.(*string), nil
	}

	// Isn't a string.
	return "", DataTypeErr{name: k, is: reflect.TypeOf(v).String(), not: _string}
}

// String returns the key's value as a string. An empty string, "", will be
// returned if the key either doesn't exist or is not a string setting.
func String(k string) string { return settings.String(k) }

// String returns the key's value as a string. An empty string, "", will be
// returned if the key either doesn't exist or is not a string setting.
func (s *Settings) String(k string) string {
	v, _ := s.StringE(k)
	return v
}

// ConfFilename returns the configuration filename.
func ConfFilename() string { return settings.ConfFilename() }
func (s *Settings) ConfFilename() string {
	s.mu.Lock()
	defer s.mu.Unlock()
	return s.confFilename
}
<|endoftext|>


<commit_before>// Copyright 2016 Factom Foundation
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package factom

import (
	"encoding/json"
)

// GetECBalance returns the balance in factoshi (factoid * 1e8) of a given Entry
// Credit Public Address.
func GetECBalance(key string) (int64, error) {
	type balanceResponse struct {
		Balance int64 `json:"balance"`
	}

	params := addressRequest{Address: key}
	req := NewJSON2Request("entry-credit-balance", APICounter(), params)
	resp, err := factomdRequest(req)
	if err != nil {
		return -1, err
	}
	if resp.Error != nil {
		return -1, resp.Error
	}

	balance := new(balanceResponse)
	if err := json.Unmarshal(resp.JSONResult(), balance); err != nil {
		return -1, err
	}

	return balance.Balance, nil
}

// GetFactoidBalance returns the balance in factoshi (factoid * 1e8) of a given
// Factoid Public Address.
func GetFactoidBalance(key string) (int64, error) {
	type balanceResponse struct {
		Balance int64 `json:"balance"`
	}

	params := addressRequest{Address: key}
	req := NewJSON2Request("factoid-balance", APICounter(), params)
	resp, err := factomdRequest(req)
	if err != nil {
		return -1, err
	}
	if resp.Error != nil {
		return -1, resp.Error
	}

	balance := new(balanceResponse)
	if err := json.Unmarshal(resp.JSONResult(), balance); err != nil {
		return -1, err
	}

	return balance.Balance, nil
}

// GetRate returns the number of factoshis per entry credit
func GetRate() (uint64, error) {
	type rateResponse struct {
		Rate uint64 `json:"rate"`
	}

	req := NewJSON2Request("entry-credit-rate", APICounter(), nil)
	resp, err := factomdRequest(req)
	if err != nil {
		return 0, err
	}
	if resp.Error != nil {
		return 0, resp.Error
	}

	rate := new(rateResponse)
	if err := json.Unmarshal(resp.JSONResult(), rate); err != nil {
		return 0, err
	}

	return rate.Rate, nil
}

// GetDBlock requests a Directory Block from factomd by its Key Merkel Root
func GetDBlock(keymr string) (*DBlock, error) {
	params := keyMRRequest{KeyMR: keymr}
	req := NewJSON2Request("directory-block", APICounter(), params)
	resp, err := factomdRequest(req)
	if err != nil {
		return nil, err
	}
	if resp.Error != nil {
		return nil, resp.Error
	}

	db := new(DBlock)
	if err := json.Unmarshal(resp.JSONResult(), db); err != nil {
		return nil, err
	}

	return db, nil
}

func GetDBlockHead() (string, error) {
	req := NewJSON2Request("directory-block-head", APICounter(), nil)
	resp, err := factomdRequest(req)
	if err != nil {
		return "", err
	}
	if resp.Error != nil {
		return "", resp.Error
	}

	head := new(DBHead)
	if err := json.Unmarshal(resp.JSONResult(), head); err != nil {
		return "", err
	}

	return head.KeyMR, nil
}

func GetDBlockHeight() (int, error) {
	req := NewJSON2Request("directory-block-height", APICounter(), nil)
	resp, err := factomdRequest(req)
	if err != nil {
		return 0, err
	}
	if resp.Error != nil {
		return 0, resp.Error
	}

	height := new(DirectoryBlockHeightResponse)
	if err := json.Unmarshal(resp.JSONResult(), height); err != nil {
		return 0, err
	}

	return int(height.Height), nil
}

// GetEntry requests an Entry from factomd by its Entry Hash
func GetEntry(hash string) (*Entry, error) {
	params := hashRequest{Hash: hash}
	req := NewJSON2Request("entry", APICounter(), params)
	resp, err := factomdRequest(req)
	if err != nil {
		return nil, err
	}
	if resp.Error != nil {
		return nil, resp.Error
	}

	e := new(Entry)
	if err := json.Unmarshal(resp.JSONResult(), e); err != nil {
		return nil, err
	}

	return e, nil
}

func GetChainHead(chainid string) (string, error) {
	type chainHeadResponse struct {
		ChainHead string `json:"chainhead"`
	}

	params := chainIDRequest{ChainID: chainid}
	req := NewJSON2Request("chain-head", APICounter(), params)
	resp, err := factomdRequest(req)
	if err != nil {
		return "", err
	}
	if resp.Error != nil {
		return "", resp.Error
	}

	head := new(chainHeadResponse)
	if err := json.Unmarshal(resp.JSONResult(), head); err != nil {
		return "", err
	}

	return head.ChainHead, nil
}

// GetAllEBlockEntries requests every Entry in a specific Entry Block
func GetAllEBlockEntries(keymr string) ([]*Entry, error) {
	es := make([]*Entry, 0)

	eb, err := GetEBlock(keymr)
	if err != nil {
		return es, err
	}

	for _, v := range eb.EntryList {
		e, err := GetEntry(v.EntryHash)
		if err != nil {
			return es, err
		}
		es = append(es, e)
	}

	return es, nil
}

// GetEBlock requests an Entry Block from factomd by its Key Merkel Root
func GetEBlock(keymr string) (*EBlock, error) {
	params := keyMRRequest{KeyMR: keymr}
	req := NewJSON2Request("entry-block", APICounter(), params)
	resp, err := factomdRequest(req)
	if err != nil {
		return nil, err
	}
	if resp.Error != nil {
		return nil, resp.Error
	}

	eb := new(EBlock)
	if err := json.Unmarshal(resp.JSONResult(), eb); err != nil {
		return nil, err
	}

	return eb, nil
}

func GetRaw(keymr string) ([]byte, error) {
	params := hashRequest{Hash: keymr}
	req := NewJSON2Request("raw-data", APICounter(), params)
	resp, err := factomdRequest(req)
	if err != nil {
		return nil, err
	}
	if resp.Error != nil {
		return nil, resp.Error
	}

	raw := new(RawData)
	if err := json.Unmarshal(resp.JSONResult(), raw); err != nil {
		return nil, err
	}

	return raw.GetDataBytes()
}

func GetAllChainEntries(chainid string) ([]*Entry, error) {
	es := make([]*Entry, 0)

	head, err := GetChainHead(chainid)
	if err != nil {
		return es, err
	}

	for ebhash := head; ebhash != ZeroHash; {
		eb, err := GetEBlock(ebhash)
		if err != nil {
			return es, err
		}
		s, err := GetAllEBlockEntries(ebhash)
		if err != nil {
			return es, err
		}
		es = append(s, es...)

		ebhash = eb.Header.PrevKeyMR
	}

	return es, nil
}

func GetFirstEntry(chainid string) (*Entry, error) {
	e := new(Entry)

	head, err := GetChainHead(chainid)
	if err != nil {
		return e, err
	}

	eb, err := GetEBlock(head)
	if err != nil {
		return e, err
	}

	for eb.Header.PrevKeyMR != ZeroHash {
		ebhash := eb.Header.PrevKeyMR
		eb, err = GetEBlock(ebhash)
		if err != nil {
			return e, err
		}
	}

	return GetEntry(eb.EntryList[0].EntryHash)
}

func GetProperties() (string, string, string, error) {
	type propertiesResponse struct {
		FactomdVersion string `json:"factomdversion"`
		APIVersion     string `json:"apiversion"`
		WalletVersion  string `json:"walletversion"`
	}

	req := NewJSON2Request("properties", APICounter(), nil)
	resp, err := factomdRequest(req)
	if err != nil {
		return "", "", "", err
	}
	if resp.Error != nil {
		return "", "", "", resp.Error
	}

	props := new(propertiesResponse)
	if err := json.Unmarshal(resp.JSONResult(), props); err != nil {
		return "", "", "", err
	}

	wresp, err := walletRequest(req)
	if err != nil {
		return props.FactomdVersion, props.APIVersion, props.WalletVersion, err
	}
	if wresp.Error != nil {
		return props.FactomdVersion, props.APIVersion, props.WalletVersion,
			wresp.Error
	}

	wprops := new(propertiesResponse)
	if err := json.Unmarshal(wresp.JSONResult(), wprops); err != nil {
		return "", "", "", err
	}

	return props.FactomdVersion, props.APIVersion, wprops.WalletVersion, nil
}
<commit_msg>var name fix<commit_after>// Copyright 2016 Factom Foundation
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package factom

import (
	"encoding/json"
)

// GetECBalance returns the balance in factoshi (factoid * 1e8) of a given Entry
// Credit Public Address.
func GetECBalance(addr string) (int64, error) {
	type balanceResponse struct {
		Balance int64 `json:"balance"`
	}

	params := addressRequest{Address: addr}
	req := NewJSON2Request("entry-credit-balance", APICounter(), params)
	resp, err := factomdRequest(req)
	if err != nil {
		return -1, err
	}
	if resp.Error != nil {
		return -1, resp.Error
	}

	balance := new(balanceResponse)
	if err := json.Unmarshal(resp.JSONResult(), balance); err != nil {
		return -1, err
	}

	return balance.Balance, nil
}

// GetFactoidBalance returns the balance in factoshi (factoid * 1e8) of a given
// Factoid Public Address.
func GetFactoidBalance(addr string) (int64, error) {
	type balanceResponse struct {
		Balance int64 `json:"balance"`
	}

	params := addressRequest{Address: addr}
	req := NewJSON2Request("factoid-balance", APICounter(), params)
	resp, err := factomdRequest(req)
	if err != nil {
		return -1, err
	}
	if resp.Error != nil {
		return -1, resp.Error
	}

	balance := new(balanceResponse)
	if err := json.Unmarshal(resp.JSONResult(), balance); err != nil {
		return -1, err
	}

	return balance.Balance, nil
}

// GetRate returns the number of factoshis per entry credit
func GetRate() (uint64, error) {
	type rateResponse struct {
		Rate uint64 `json:"rate"`
	}

	req := NewJSON2Request("entry-credit-rate", APICounter(), nil)
	resp, err := factomdRequest(req)
	if err != nil {
		return 0, err
	}
	if resp.Error != nil {
		return 0, resp.Error
	}

	rate := new(rateResponse)
	if err := json.Unmarshal(resp.JSONResult(), rate); err != nil {
		return 0, err
	}

	return rate.Rate, nil
}

// GetDBlock requests a Directory Block from factomd by its Key Merkel Root
func GetDBlock(keymr string) (*DBlock, error) {
	params := keyMRRequest{KeyMR: keymr}
	req := NewJSON2Request("directory-block", APICounter(), params)
	resp, err := factomdRequest(req)
	if err != nil {
		return nil, err
	}
	if resp.Error != nil {
		return nil, resp.Error
	}

	db := new(DBlock)
	if err := json.Unmarshal(resp.JSONResult(), db); err != nil {
		return nil, err
	}

	return db, nil
}

func GetDBlockHead() (string, error) {
	req := NewJSON2Request("directory-block-head", APICounter(), nil)
	resp, err := factomdRequest(req)
	if err != nil {
		return "", err
	}
	if resp.Error != nil {
		return "", resp.Error
	}

	head := new(DBHead)
	if err := json.Unmarshal(resp.JSONResult(), head); err != nil {
		return "", err
	}

	return head.KeyMR, nil
}

func GetDBlockHeight() (int, error) {
	req := NewJSON2Request("directory-block-height", APICounter(), nil)
	resp, err := factomdRequest(req)
	if err != nil {
		return 0, err
	}
	if resp.Error != nil {
		return 0, resp.Error
	}

	height := new(DirectoryBlockHeightResponse)
	if err := json.Unmarshal(resp.JSONResult(), height); err != nil {
		return 0, err
	}

	return int(height.Height), nil
}

// GetEntry requests an Entry from factomd by its Entry Hash
func GetEntry(hash string) (*Entry, error) {
	params := hashRequest{Hash: hash}
	req := NewJSON2Request("entry", APICounter(), params)
	resp, err := factomdRequest(req)
	if err != nil {
		return nil, err
	}
	if resp.Error != nil {
		return nil, resp.Error
	}

	e := new(Entry)
	if err := json.Unmarshal(resp.JSONResult(), e); err != nil {
		return nil, err
	}

	return e, nil
}

func GetChainHead(chainid string) (string, error) {
	type chainHeadResponse struct {
		ChainHead string `json:"chainhead"`
	}

	params := chainIDRequest{ChainID: chainid}
	req := NewJSON2Request("chain-head", APICounter(), params)
	resp, err := factomdRequest(req)
	if err != nil {
		return "", err
	}
	if resp.Error != nil {
		return "", resp.Error
	}

	head := new(chainHeadResponse)
	if err := json.Unmarshal(resp.JSONResult(), head); err != nil {
		return "", err
	}

	return head.ChainHead, nil
}

// GetAllEBlockEntries requests every Entry in a specific Entry Block
func GetAllEBlockEntries(keymr string) ([]*Entry, error) {
	es := make([]*Entry, 0)

	eb, err := GetEBlock(keymr)
	if err != nil {
		return es, err
	}

	for _, v := range eb.EntryList {
		e, err := GetEntry(v.EntryHash)
		if err != nil {
			return es, err
		}
		es = append(es, e)
	}

	return es, nil
}

// GetEBlock requests an Entry Block from factomd by its Key Merkel Root
func GetEBlock(keymr string) (*EBlock, error) {
	params := keyMRRequest{KeyMR: keymr}
	req := NewJSON2Request("entry-block", APICounter(), params)
	resp, err := factomdRequest(req)
	if err != nil {
		return nil, err
	}
	if resp.Error != nil {
		return nil, resp.Error
	}

	eb := new(EBlock)
	if err := json.Unmarshal(resp.JSONResult(), eb); err != nil {
		return nil, err
	}

	return eb, nil
}

func GetRaw(keymr string) ([]byte, error) {
	params := hashRequest{Hash: keymr}
	req := NewJSON2Request("raw-data", APICounter(), params)
	resp, err := factomdRequest(req)
	if err != nil {
		return nil, err
	}
	if resp.Error != nil {
		return nil, resp.Error
	}

	raw := new(RawData)
	if err := json.Unmarshal(resp.JSONResult(), raw); err != nil {
		return nil, err
	}

	return raw.GetDataBytes()
}

func GetAllChainEntries(chainid string) ([]*Entry, error) {
	es := make([]*Entry, 0)

	head, err := GetChainHead(chainid)
	if err != nil {
		return es, err
	}

	for ebhash := head; ebhash != ZeroHash; {
		eb, err := GetEBlock(ebhash)
		if err != nil {
			return es, err
		}
		s, err := GetAllEBlockEntries(ebhash)
		if err != nil {
			return es, err
		}
		es = append(s, es...)

		ebhash = eb.Header.PrevKeyMR
	}

	return es, nil
}

func GetFirstEntry(chainid string) (*Entry, error) {
	e := new(Entry)

	head, err := GetChainHead(chainid)
	if err != nil {
		return e, err
	}

	eb, err := GetEBlock(head)
	if err != nil {
		return e, err
	}

	for eb.Header.PrevKeyMR != ZeroHash {
		ebhash := eb.Header.PrevKeyMR
		eb, err = GetEBlock(ebhash)
		if err != nil {
			return e, err
		}
	}

	return GetEntry(eb.EntryList[0].EntryHash)
}

func GetProperties() (string, string, string, error) {
	type propertiesResponse struct {
		FactomdVersion string `json:"factomdversion"`
		APIVersion     string `json:"apiversion"`
		WalletVersion  string `json:"walletversion"`
	}

	req := NewJSON2Request("properties", APICounter(), nil)
	resp, err := factomdRequest(req)
	if err != nil {
		return "", "", "", err
	}
	if resp.Error != nil {
		return "", "", "", resp.Error
	}

	props := new(propertiesResponse)
	if err := json.Unmarshal(resp.JSONResult(), props); err != nil {
		return "", "", "", err
	}

	wresp, err := walletRequest(req)
	if err != nil {
		return props.FactomdVersion, props.APIVersion, props.WalletVersion, err
	}
	if wresp.Error != nil {
		return props.FactomdVersion, props.APIVersion, props.WalletVersion,
			wresp.Error
	}

	wprops := new(propertiesResponse)
	if err := json.Unmarshal(wresp.JSONResult(), wprops); err != nil {
		return "", "", "", err
	}

	return props.FactomdVersion, props.APIVersion, wprops.WalletVersion, nil
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"fmt"
	"io"
	"path/filepath"
	"time"

	"github.com/google/go-github/github"
	"github.com/pkg/errors"
	"golang.org/x/sync/errgroup"
)

type GHR struct {
	GitHub GitHub

	outStream io.Writer
}

func (g *GHR) CreateRelease(ctx context.Context, req *github.RepositoryRelease, recreate bool) (*github.RepositoryRelease, error) {

	// When draft release creation is requested,
	// create it witout any check (it can).
	if *req.Draft {
		fmt.Fprintln(g.outStream, "==> Create a draft release")
		return g.GitHub.CreateRelease(ctx, req)
	}

	// Check release is exist or not.
	// If release is not found, then create a new release.
	release, err := g.GitHub.GetRelease(ctx, *req.TagName)
	if err != nil {
		if err != RelaseNotFound {
			return nil, errors.Wrap(err, "failed to get release")
		}
		Debugf("Release (with tag %s) is not found: create a new one",
			*req.TagName)

		if recreate {
			fmt.Fprintf(g.outStream,
				"WARNING: '-recreate' is specified but release (%s) is not found",
				*req.TagName)
		}

		fmt.Fprintln(g.outStream, "==> Create a new release")
		return g.GitHub.CreateRelease(ctx, req)
	}

	// recreate is not true. Then use that exiting release.
	if !recreate {
		Debugf("Release (with tag %s) exists: use exsiting one",
			*req.TagName)

		fmt.Fprintf(g.outStream, "WARNING: found release (%s). Use existing one.",
			*req.TagName)
		return release, nil
	}

	// When recreate is requested, delete exsiting release
	// and create a new release.
	fmt.Fprintln(g.outStream, "==> Recreate a release")
	if err := g.DeleteRelease(ctx, *release.ID, *req.TagName); err != nil {
		return nil, err
	}

	return g.GitHub.CreateRelease(ctx, req)
}

func (g *GHR) DeleteRelease(ctx context.Context, ID int, tag string) error {

	err := g.GitHub.DeleteRelease(ctx, ID)
	if err != nil {
		return err
	}

	err = g.GitHub.DeleteTag(ctx, tag)
	if err != nil {
		return err
	}

	// This is because sometimes process of creating release on GitHub is more
	// fast than deleting tag.
	time.Sleep(5 * time.Second)

	return nil
}

func (g *GHR) UploadAssets(ctx context.Context, releaseID int, localAssets []string, parallel int) error {
	start := time.Now()
	defer func() {
		Debugf("UploadAssets: time: %d ms", int(time.Since(start).Seconds()*1000))
	}()

	eg, ctx := errgroup.WithContext(ctx)
	semaphore := make(chan struct{}, parallel)
	for _, localAsset := range localAssets {
		localAsset := localAsset
		eg.Go(func() error {
			semaphore <- struct{}{}
			defer func() {
				<-semaphore
			}()

			fmt.Fprintf(g.outStream, "--> Uploading: %15s\n", filepath.Base(localAsset))
			_, err := g.GitHub.UploadAsset(ctx, releaseID, localAsset)
			if err != nil {
				return errors.Wrapf(err,
					"failed to upload asset: %s", localAsset)
			}
			return nil
		})
	}

	if err := eg.Wait(); err != nil {
		return errors.Wrap(err, "one of goroutines is failed")
	}

	return nil
}

func (g *GHR) DeleteAssets(ctx context.Context, releaseID int, localAssets []string, parallel int) error {
	start := time.Now()
	defer func() {
		Debugf("DeleteAssets: time: %d ms", int(time.Since(start).Seconds()*1000))
	}()

	eg, ctx := errgroup.WithContext(ctx)

	assets, err := g.GitHub.ListAssets(ctx, releaseID)
	if err != nil {
		return errors.Wrap(err, "failed to list assets")
	}

	semaphore := make(chan struct{}, parallel)
	for _, localAsset := range localAssets {
		for _, asset := range assets {
			// https://golang.org/doc/faq#closures_and_goroutines
			localAsset, asset := localAsset, asset

			// Uploaded asset name is same as basename of local file
			if *asset.Name == filepath.Base(localAsset) {
				eg.Go(func() error {
					semaphore <- struct{}{}
					defer func() {
						<-semaphore
					}()

					fmt.Fprintf(g.outStream, "--> Deleting: %15s\n", *asset.Name)
					if err := g.GitHub.DeleteAsset(ctx, *asset.ID); err != nil {
						return errors.Wrapf(err,
							"failed to delete asset: %s", *asset.Name)
					}
					return nil
				})
			}
		}
	}

	if err := eg.Wait(); err != nil {
		return errors.Wrap(err, "one of goroutines is failed")
	}

	return nil
}
<commit_msg>chore(ghr): fix typo<commit_after>package main

import (
	"context"
	"fmt"
	"io"
	"path/filepath"
	"time"

	"github.com/google/go-github/github"
	"github.com/pkg/errors"
	"golang.org/x/sync/errgroup"
)

type GHR struct {
	GitHub GitHub

	outStream io.Writer
}

func (g *GHR) CreateRelease(ctx context.Context, req *github.RepositoryRelease, recreate bool) (*github.RepositoryRelease, error) {

	// When draft release creation is requested,
	// create it witout any check (it can).
	if *req.Draft {
		fmt.Fprintln(g.outStream, "==> Create a draft release")
		return g.GitHub.CreateRelease(ctx, req)
	}

	// Check release is exist or not.
	// If release is not found, then create a new release.
	release, err := g.GitHub.GetRelease(ctx, *req.TagName)
	if err != nil {
		if err != RelaseNotFound {
			return nil, errors.Wrap(err, "failed to get release")
		}
		Debugf("Release (with tag %s) is not found: create a new one",
			*req.TagName)

		if recreate {
			fmt.Fprintf(g.outStream,
				"WARNING: '-recreate' is specified but release (%s) is not found",
				*req.TagName)
		}

		fmt.Fprintln(g.outStream, "==> Create a new release")
		return g.GitHub.CreateRelease(ctx, req)
	}

	// recreate is not true. Then use that existing release.
	if !recreate {
		Debugf("Release (with tag %s) exists: use existing one",
			*req.TagName)

		fmt.Fprintf(g.outStream, "WARNING: found release (%s). Use existing one.",
			*req.TagName)
		return release, nil
	}

	// When recreate is requested, delete existing release
	// and create a new release.
	fmt.Fprintln(g.outStream, "==> Recreate a release")
	if err := g.DeleteRelease(ctx, *release.ID, *req.TagName); err != nil {
		return nil, err
	}

	return g.GitHub.CreateRelease(ctx, req)
}

func (g *GHR) DeleteRelease(ctx context.Context, ID int, tag string) error {

	err := g.GitHub.DeleteRelease(ctx, ID)
	if err != nil {
		return err
	}

	err = g.GitHub.DeleteTag(ctx, tag)
	if err != nil {
		return err
	}

	// This is because sometimes process of creating release on GitHub is more
	// fast than deleting tag.
	time.Sleep(5 * time.Second)

	return nil
}

func (g *GHR) UploadAssets(ctx context.Context, releaseID int, localAssets []string, parallel int) error {
	start := time.Now()
	defer func() {
		Debugf("UploadAssets: time: %d ms", int(time.Since(start).Seconds()*1000))
	}()

	eg, ctx := errgroup.WithContext(ctx)
	semaphore := make(chan struct{}, parallel)
	for _, localAsset := range localAssets {
		localAsset := localAsset
		eg.Go(func() error {
			semaphore <- struct{}{}
			defer func() {
				<-semaphore
			}()

			fmt.Fprintf(g.outStream, "--> Uploading: %15s\n", filepath.Base(localAsset))
			_, err := g.GitHub.UploadAsset(ctx, releaseID, localAsset)
			if err != nil {
				return errors.Wrapf(err,
					"failed to upload asset: %s", localAsset)
			}
			return nil
		})
	}

	if err := eg.Wait(); err != nil {
		return errors.Wrap(err, "one of goroutines is failed")
	}

	return nil
}

func (g *GHR) DeleteAssets(ctx context.Context, releaseID int, localAssets []string, parallel int) error {
	start := time.Now()
	defer func() {
		Debugf("DeleteAssets: time: %d ms", int(time.Since(start).Seconds()*1000))
	}()

	eg, ctx := errgroup.WithContext(ctx)

	assets, err := g.GitHub.ListAssets(ctx, releaseID)
	if err != nil {
		return errors.Wrap(err, "failed to list assets")
	}

	semaphore := make(chan struct{}, parallel)
	for _, localAsset := range localAssets {
		for _, asset := range assets {
			// https://golang.org/doc/faq#closures_and_goroutines
			localAsset, asset := localAsset, asset

			// Uploaded asset name is same as basename of local file
			if *asset.Name == filepath.Base(localAsset) {
				eg.Go(func() error {
					semaphore <- struct{}{}
					defer func() {
						<-semaphore
					}()

					fmt.Fprintf(g.outStream, "--> Deleting: %15s\n", *asset.Name)
					if err := g.GitHub.DeleteAsset(ctx, *asset.ID); err != nil {
						return errors.Wrapf(err,
							"failed to delete asset: %s", *asset.Name)
					}
					return nil
				})
			}
		}
	}

	if err := eg.Wait(); err != nil {
		return errors.Wrap(err, "one of goroutines is failed")
	}

	return nil
}
<|endoftext|>


<commit_before>// Copyright 2011, Bryan Matsuo. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

/*  Filename:    git.go
 *  Author:      Bryan Matsuo <bryan.matsuo@gmail.com>
 *  Created:     Sun Nov  6 01:17:31 PDT 2011
 *  Description:
 */

import (
	"github.com/bmatsuo/go-script/script"
	"path/filepath"
	"errors"
	"strings"
	"fmt"
	"os"
)

type ErrorRepoConfig error

func NewErrorRepoConfig(err string) ErrorRepoConfig { return ErrorRepoConfig(errors.New(err)) }

type gitRepo struct {
	root  string
	shell script.Scriptor
}

func NewGitRepo(root string) (Repository, error) {
	repo := new(gitRepo)
	repo.root = root
	repo.shell = script.Bash
	return repo, repo.checkRoot()
}

func (repo *gitRepo) checkRoot() error {
	repo_dir := repo.root + "/.git"
	dir, staterr := os.Stat(repo_dir)
	if staterr != nil {
		return staterr
	}
	if !dir.IsDirectory() {
		return fmt.Errorf("Git file %s is not a directory.")
	}
	return nil
}

func (repo *gitRepo) Root() string { return repo.root }
func (repo *gitRepo) Type() string { return "Git" }

func (repo *gitRepo) Name() (string, error) {
	// TODO: look at the contents of the .git/config file
	abs, err := filepath.Abs(repo.root)
	if err != nil {
		return "", err
	}
	return filepath.Base(abs), nil
}

func (repo *gitRepo) Tags() ([]string, error) {
	tagcmd := `git tag -l`
	if repo.root != "." {
		tagcmd = fmt.Sprintf("cd %s\n%s", script.ShellQuote(repo.root), tagcmd)
	}
	tagout, _, errexec := script.Output(repo.shell.NewScript(tagcmd))
	if errexec != nil {
		return nil, errexec
	}
	tags := strings.Fields(strings.Trim(string(tagout), "\n"))
	return tags, nil
}

func (repo *gitRepo) TagDelete(tag string) error {
	tagcmd := fmt.Sprintf(`git tag -d %s`, tag)
	if repo.root != "." {
		tagcmd = fmt.Sprintf("cd %s\n%s", script.ShellQuote(repo.root), tagcmd)
	}
	_, errexec := repo.shell.NewScript(tagcmd).Execute()
	return errexec
}

// If there is an extra value, it is used as a tag annotation.
// If there are two extra values, the second is used as a commit hash.
func (repo *gitRepo) Tag(name string, extra ...interface{}) error {
	tagcmd := fmt.Sprintf(`git tag`)
	if len(extra) > 0 {
		note := extra[0]
		switch note.(type) {
		case string:
			tagcmd = fmt.Sprintf(`%s -a -m %s`, tagcmd, script.ShellQuote(note.(string)))
		default:
			return errors.New("expected string annotation")
		}
	}
	tagcmd = fmt.Sprintf(`%s %s`, tagcmd, name)
	if len(extra) > 1 {
		tagcmd = fmt.Sprintf(`%s %s`, tagcmd, script.ShellQuote(extra[0].(string)))
	}
	if repo.root != "." {
		tagcmd = fmt.Sprintf("cd %s\n%s", script.ShellQuote(repo.root), tagcmd)
	}
	_, errexec := repo.shell.NewScript(tagcmd).Execute()
	return errexec
}
<commit_msg>Fix a bug with git commit hashes in the GitRepo.Tag method.<commit_after>// Copyright 2011, Bryan Matsuo. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

/*  Filename:    git.go
 *  Author:      Bryan Matsuo <bryan.matsuo@gmail.com>
 *  Created:     Sun Nov  6 01:17:31 PDT 2011
 *  Description:
 */

import (
	"github.com/bmatsuo/go-script/script"
	"path/filepath"
	"errors"
	"strings"
	"fmt"
	"os"
)

type ErrorRepoConfig error

func NewErrorRepoConfig(err string) ErrorRepoConfig { return ErrorRepoConfig(errors.New(err)) }

type gitRepo struct {
	root  string
	shell script.Scriptor
}

func NewGitRepo(root string) (Repository, error) {
	repo := new(gitRepo)
	repo.root = root
	repo.shell = script.Bash
	return repo, repo.checkRoot()
}

func (repo *gitRepo) checkRoot() error {
	repo_dir := repo.root + "/.git"
	dir, staterr := os.Stat(repo_dir)
	if staterr != nil {
		return staterr
	}
	if !dir.IsDirectory() {
		return fmt.Errorf("Git file %s is not a directory.")
	}
	return nil
}

func (repo *gitRepo) Root() string { return repo.root }
func (repo *gitRepo) Type() string { return "Git" }

func (repo *gitRepo) Name() (string, error) {
	// TODO: look at the contents of the .git/config file
	abs, err := filepath.Abs(repo.root)
	if err != nil {
		return "", err
	}
	return filepath.Base(abs), nil
}

func (repo *gitRepo) Tags() ([]string, error) {
	tagcmd := `git tag -l`
	if repo.root != "." {
		tagcmd = fmt.Sprintf("cd %s\n%s", script.ShellQuote(repo.root), tagcmd)
	}
	tagout, _, errexec := script.Output(repo.shell.NewScript(tagcmd))
	if errexec != nil {
		return nil, errexec
	}
	tags := strings.Fields(strings.Trim(string(tagout), "\n"))
	return tags, nil
}

func (repo *gitRepo) TagDelete(tag string) error {
	tagcmd := fmt.Sprintf(`git tag -d %s`, tag)
	if repo.root != "." {
		tagcmd = fmt.Sprintf("cd %s\n%s", script.ShellQuote(repo.root), tagcmd)
	}
	_, errexec := repo.shell.NewScript(tagcmd).Execute()
	return errexec
}

// If there is an extra value, it is used as a tag annotation.
// If there are two extra values, the second is used as a commit hash.
func (repo *gitRepo) Tag(name string, extra ...interface{}) error {
	tagcmd := fmt.Sprintf(`git tag`)
	if len(extra) > 0 {
		note := extra[0]
		switch note.(type) {
		case string:
			tagcmd = fmt.Sprintf(`%s -a -m %s`, tagcmd, script.ShellQuote(note.(string)))
		default:
			return errors.New("expected string annotation")
		}
	}
	tagcmd = fmt.Sprintf(`%s %s`, tagcmd, name)
	if len(extra) > 1 {
		commit := extra[1]
		switch commit.(type) {
		case string:
			tagcmd = fmt.Sprintf(`%s %s`, tagcmd, script.ShellQuote(commit.(string)))
		default:
			return errors.New("expected string commit hash")
		}
	}
	if repo.root != "." {
		tagcmd = fmt.Sprintf("cd %s\n%s", script.ShellQuote(repo.root), tagcmd)
	}
	_, errexec := repo.shell.NewScript(tagcmd).Execute()
	return errexec
}
<|endoftext|>


<commit_before>/*
Copyright 2017 Google Inc.

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

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

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

// Package vtexplain analyzes a set of sql statements and returns the
// corresponding vtgate and vttablet query plans that will be executed
// on the given statements
package vtexplain

import (
	"encoding/json"
	"fmt"

	log "github.com/golang/glog"
	"golang.org/x/net/context"

	"github.com/youtube/vitess/go/vt/discovery"
	"github.com/youtube/vitess/go/vt/key"
	"github.com/youtube/vitess/go/vt/topo"
	"github.com/youtube/vitess/go/vt/vtgate"
	"github.com/youtube/vitess/go/vt/vtgate/engine"
	"github.com/youtube/vitess/go/vt/vtgate/gateway"
	"github.com/youtube/vitess/go/vt/vttablet/sandboxconn"

	topodatapb "github.com/youtube/vitess/go/vt/proto/topodata"
	vschemapb "github.com/youtube/vitess/go/vt/proto/vschema"
	vtgatepb "github.com/youtube/vitess/go/vt/proto/vtgate"
)

var (
	explainTopo    *ExplainTopo
	vtgateExecutor *vtgate.Executor
	healthCheck    *discovery.FakeHealthCheck

	vtgateSession = &vtgatepb.Session{
		TargetString: "@master",
		Autocommit:   true,
	}
)

func initVtgateExecutor(vSchemaStr string, opts *Options) error {
	explainTopo = &ExplainTopo{NumShards: opts.NumShards}
	healthCheck = discovery.NewFakeHealthCheck()

	resolver := newFakeResolver(healthCheck, explainTopo, vtexplainCell)

	err := buildTopology(vSchemaStr, opts.NumShards)
	if err != nil {
		return err
	}

	streamSize := 10
	vtgateExecutor = vtgate.NewExecutor(context.Background(), explainTopo, vtexplainCell, "", resolver, opts.Normalize, streamSize)

	return nil
}

func newFakeResolver(hc discovery.HealthCheck, serv topo.SrvTopoServer, cell string) *vtgate.Resolver {
	gw := gateway.GetCreator()(hc, topo.Server{}, serv, cell, 3)
	gw.WaitForTablets(context.Background(), []topodatapb.TabletType{topodatapb.TabletType_REPLICA})
	tc := vtgate.NewTxConn(gw, vtgatepb.TransactionMode_MULTI)
	sc := vtgate.NewScatterConn("", tc, gw)
	return vtgate.NewResolver(serv, cell, sc)
}

func buildTopology(vschemaStr string, numShardsPerKeyspace int) error {
	explainTopo.Lock.Lock()
	defer explainTopo.Lock.Unlock()

	explainTopo.Keyspaces = make(map[string]*vschemapb.Keyspace)
	err := json.Unmarshal([]byte(vschemaStr), &explainTopo.Keyspaces)
	if err != nil {
		return err
	}

	explainTopo.TabletConns = make(map[string]*sandboxconn.SandboxConn)
	for ks, vschema := range explainTopo.Keyspaces {
		numShards := 1
		if vschema.Sharded {
			numShards = numShardsPerKeyspace
		}
		for i := 0; i < numShards; i++ {
			kr, err := key.EvenShardsKeyRange(i, numShards)
			if err != nil {
				return err
			}
			shard := key.KeyRangeString(kr)
			hostname := fmt.Sprintf("%s/%s", ks, shard)
			log.Infof("registering test tablet %s for keyspace %s shard %s", hostname, ks, shard)
			sc := healthCheck.AddTestTablet(vtexplainCell, hostname, 1, ks, shard, topodatapb.TabletType_MASTER, true, 1, nil)
			explainTopo.TabletConns[hostname] = sc
		}
	}

	return err
}

func vtgateExecute(sql string) ([]*engine.Plan, map[string][]*TabletQuery, error) {
	_, err := vtgateExecutor.Execute(context.Background(), vtgateSession, sql, nil)
	if err != nil {
		return nil, nil, fmt.Errorf("vtgate Execute: %v", err)
	}

	// use the plan cache to get the set of plans used for this query, then
	// clear afterwards for the next run
	planCache := vtgateExecutor.Plans()
	plans := make([]*engine.Plan, 0, 4)
	for _, item := range planCache.Items() {
		plans = append(plans, item.Value.(*engine.Plan))
	}
	planCache.Clear()

	tabletQueries := make(map[string][]*TabletQuery)
	for tablet, tc := range explainTopo.TabletConns {
		if len(tc.Queries) == 0 {
			continue
		}

		queries := make([]*TabletQuery, 0, 16)
		for _, bq := range tc.Queries {
			tq := &TabletQuery{SQL: bq.Sql, BindVars: bq.BindVariables}
			queries = append(queries, tq)
		}
		tc.Queries = nil

		tabletQueries[tablet] = queries
	}

	return plans, tabletQueries, nil
}
<commit_msg>clean up local array allocations as per PR feedback<commit_after>/*
Copyright 2017 Google Inc.

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

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

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

// Package vtexplain analyzes a set of sql statements and returns the
// corresponding vtgate and vttablet query plans that will be executed
// on the given statements
package vtexplain

import (
	"encoding/json"
	"fmt"

	log "github.com/golang/glog"
	"golang.org/x/net/context"

	"github.com/youtube/vitess/go/vt/discovery"
	"github.com/youtube/vitess/go/vt/key"
	"github.com/youtube/vitess/go/vt/topo"
	"github.com/youtube/vitess/go/vt/vtgate"
	"github.com/youtube/vitess/go/vt/vtgate/engine"
	"github.com/youtube/vitess/go/vt/vtgate/gateway"
	"github.com/youtube/vitess/go/vt/vttablet/sandboxconn"

	topodatapb "github.com/youtube/vitess/go/vt/proto/topodata"
	vschemapb "github.com/youtube/vitess/go/vt/proto/vschema"
	vtgatepb "github.com/youtube/vitess/go/vt/proto/vtgate"
)

var (
	explainTopo    *ExplainTopo
	vtgateExecutor *vtgate.Executor
	healthCheck    *discovery.FakeHealthCheck

	vtgateSession = &vtgatepb.Session{
		TargetString: "@master",
		Autocommit:   true,
	}
)

func initVtgateExecutor(vSchemaStr string, opts *Options) error {
	explainTopo = &ExplainTopo{NumShards: opts.NumShards}
	healthCheck = discovery.NewFakeHealthCheck()

	resolver := newFakeResolver(healthCheck, explainTopo, vtexplainCell)

	err := buildTopology(vSchemaStr, opts.NumShards)
	if err != nil {
		return err
	}

	streamSize := 10
	vtgateExecutor = vtgate.NewExecutor(context.Background(), explainTopo, vtexplainCell, "", resolver, opts.Normalize, streamSize)

	return nil
}

func newFakeResolver(hc discovery.HealthCheck, serv topo.SrvTopoServer, cell string) *vtgate.Resolver {
	gw := gateway.GetCreator()(hc, topo.Server{}, serv, cell, 3)
	gw.WaitForTablets(context.Background(), []topodatapb.TabletType{topodatapb.TabletType_REPLICA})
	tc := vtgate.NewTxConn(gw, vtgatepb.TransactionMode_MULTI)
	sc := vtgate.NewScatterConn("", tc, gw)
	return vtgate.NewResolver(serv, cell, sc)
}

func buildTopology(vschemaStr string, numShardsPerKeyspace int) error {
	explainTopo.Lock.Lock()
	defer explainTopo.Lock.Unlock()

	explainTopo.Keyspaces = make(map[string]*vschemapb.Keyspace)
	err := json.Unmarshal([]byte(vschemaStr), &explainTopo.Keyspaces)
	if err != nil {
		return err
	}

	explainTopo.TabletConns = make(map[string]*sandboxconn.SandboxConn)
	for ks, vschema := range explainTopo.Keyspaces {
		numShards := 1
		if vschema.Sharded {
			numShards = numShardsPerKeyspace
		}
		for i := 0; i < numShards; i++ {
			kr, err := key.EvenShardsKeyRange(i, numShards)
			if err != nil {
				return err
			}
			shard := key.KeyRangeString(kr)
			hostname := fmt.Sprintf("%s/%s", ks, shard)
			log.Infof("registering test tablet %s for keyspace %s shard %s", hostname, ks, shard)
			sc := healthCheck.AddTestTablet(vtexplainCell, hostname, 1, ks, shard, topodatapb.TabletType_MASTER, true, 1, nil)
			explainTopo.TabletConns[hostname] = sc
		}
	}

	return err
}

func vtgateExecute(sql string) ([]*engine.Plan, map[string][]*TabletQuery, error) {
	_, err := vtgateExecutor.Execute(context.Background(), vtgateSession, sql, nil)
	if err != nil {
		return nil, nil, fmt.Errorf("vtgate Execute: %v", err)
	}

	// use the plan cache to get the set of plans used for this query, then
	// clear afterwards for the next run
	planCache := vtgateExecutor.Plans()
	var plans []*engine.Plan
	for _, item := range planCache.Items() {
		plans = append(plans, item.Value.(*engine.Plan))
	}
	planCache.Clear()

	tabletQueries := make(map[string][]*TabletQuery)
	for tablet, tc := range explainTopo.TabletConns {
		if len(tc.Queries) == 0 {
			continue
		}

		queries := make([]*TabletQuery, 0, len(tc.Queries))
		for _, bq := range tc.Queries {
			tq := &TabletQuery{SQL: bq.Sql, BindVars: bq.BindVariables}
			queries = append(queries, tq)
		}
		tc.Queries = nil

		tabletQueries[tablet] = queries
	}

	return plans, tabletQueries, nil
}
<|endoftext|>