<commit_before>// BucketReader gets a list of files awaiting processing in the S3
// intake buckets and adds each item to the queue for processing.
package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"github.com/APTrust/bagman"
	"github.com/APTrust/bagman/fluctus/client"
	"github.com/crowdmob/goamz/aws"
	"log"
	"net/http"
	"os"
	"strings"
	"time"
)

// Send S3 files to queue in batches of 500.
// Wait X milliseconds between batches. The wait time is really
// only necessary when the queue is running on an AWS small EC2
// instance, where the number of open network connections is
// severely restricted.
const (
	batchSize        = 500
	waitMilliseconds = 5000
)

var (
	config        bagman.Config
	jsonLog       *log.Logger
	messageLog    *log.Logger
	fluctusClient *client.Client
)

func main() {
	err := initialize()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Initialization failed for bucket_reader: %v", err)
		os.Exit(1)
	}
	run()
}

func initialize() (err error) {
	// Load the config or die.
	requestedConfig := flag.String("config", "", "configuration to run")
	flag.Parse()
	config = bagman.LoadRequestedConfig(requestedConfig)
	jsonLog, messageLog = bagman.InitLoggers(config.LogDirectory, "bucket_reader")
	fluctusClient, err = client.New(
		config.FluctusURL,
		os.Getenv("FLUCTUS_API_USER"),
		os.Getenv("FLUCTUS_API_KEY"),
		messageLog)
	return err
}

func run() {
	s3Client, err := bagman.NewS3Client(aws.USEast)
	if err != nil {
		messageLog.Println("[ERROR]", err)
		return
	}
	bucketSummaries, err := s3Client.CheckAllBuckets(config.Buckets)
	if err != nil {
		messageLog.Println("[ERROR]", err)
		return
	}
	url := fmt.Sprintf("%s/mput?topic=%s", config.NsqdHttpAddress,
		config.BagProcessorTopic)
	messageLog.Printf("[INFO] Sending S3 file info to %s \n", url)
	s3Files := filterLargeFiles(bucketSummaries)
	messageLog.Printf("[INFO] %d S3 Files are within our size limit\n",
		len(s3Files))
	filesToProcess := s3Files
	// SkipAlreadyProcessed will almost always be true.
	// The exception is when we want to reprocess items to test new code.
	if config.SkipAlreadyProcessed == true {
		messageLog.Println("[INFO] Skipping already processed files, because config says so")
		filesToProcess = filterProcessedFiles(s3Files)
	} else {
		messageLog.Println("[INFO] Reprocessing already processed files, because config says so")
	}
	start := 0
	end := min(len(filesToProcess), batchSize)
	messageLog.Printf("[INFO] %d Unprocessed files\n", len(filesToProcess))
	for start <= end {
		batch := filesToProcess[start:end]
		messageLog.Printf("[INFO] Queuing batch of %d items\n", len(batch))
		enqueue(url, batch)
		start = end + 1
		if start < len(filesToProcess) {
			end = min(len(filesToProcess), start+batchSize)
		}
		// Sleep so we don't max out connections on EC2 small.
		// The utility server is running a lot of other network I/O
		// in addition to our queue.
		time.Sleep(time.Millisecond * waitMilliseconds)
	}
}

// min returns the minimum of x or y. The Math package has this function
// but you have to cast to floats.
func min(x, y int) int {
	if x < y {
		return x
	} else {
		return y
	}
}

// filterLargeFiles returns only those S3 files that are not larger
// than config.MaxFileSize. This is useful when running tests and
// demos on your local machine, so that you can limit your test
// runs to files under 100k (or whatever you set in config.json).
// You don't want to pull down lots of multi-gig files when you're
// just running local tests. In production, set maxFileSize to
// zero, or to some huge value to get all files.
func filterLargeFiles(bucketSummaries []*bagman.BucketSummary) (s3Files []*bagman.S3File) {
	for _, bucketSummary := range bucketSummaries {
		for _, key := range bucketSummary.Keys {
			if config.MaxFileSize == 0 || key.Size < config.MaxFileSize {
				s3Files = append(s3Files, &bagman.S3File{bucketSummary.BucketName, key})
			}
		}
	}
	return s3Files
}

// Remove S3 files that have been processed successfully.
// No need to reprocess those!
func filterProcessedFiles(s3Files []*bagman.S3File) (filesToProcess []*bagman.S3File) {
	for _, s3File := range s3Files {
		bagDate, err := time.Parse(bagman.S3DateFormat, s3File.Key.LastModified)
		if err != nil {
			messageLog.Printf("[ERROR] Cannot parse S3File mod date '%s'. "+
				"File %s will be re-processed.",
				s3File.Key.LastModified, s3File.Key.Key)
			filesToProcess = append(filesToProcess, s3File)
			continue
		}
		etag := strings.Replace(s3File.Key.ETag, "\"", "", 2)
		status, err := fluctusClient.GetBagStatus(etag, s3File.Key.Key, bagDate)
		if err != nil {
			messageLog.Printf("[ERROR] Cannot get Fluctus bag status for %s. "+
				"Will re-process bag. Error was %v", s3File.Key.Key, err)
			filesToProcess = append(filesToProcess, s3File)
		} else if status == nil ||
			(status.Status == "Received" && time.Since(status.Date) > time.Hour*12) ||
			(status.Status == "Processing" && status.Retry == true) {
			reason := "Bag has never been processed."
			if status != nil {
				reason = "Bag failed prior processing attempt, and retry flag is true."
			} else {
				err = createFluctusRecord(s3File)
				if err != nil {
					// TODO: Notify someone?
					messageLog.Printf("[ERROR] Could not create Fluctus ProcessedItem "+
						"for %s: %v", s3File.Key.Key, err)
				}
			}
			messageLog.Printf("[INFO] Will process bag %s: %s", s3File.Key.Key, reason)
			filesToProcess = append(filesToProcess, s3File)
		} else if status.Status != "Failed" {
			messageLog.Printf("[INFO] Skipping %s: already processed successfully.", s3File.Key.Key)
		} else if status.Retry == false {
			messageLog.Printf("[INFO] Skipping %s: retry flag is set to false.", s3File.Key.Key)
		}
	}
	return filesToProcess
}

func createFluctusRecord(s3File *bagman.S3File) (err error) {
	status := &bagman.ProcessStatus{}
	status.Date = time.Now().UTC()
	status.Action = "Ingest"
	status.Name = s3File.Key.Key
	bagDate, _ := time.Parse(bagman.S3DateFormat, s3File.Key.LastModified)
	status.BagDate = bagDate
	status.Bucket = s3File.BucketName
	// Strip the quotes off the ETag
	status.ETag = strings.Replace(s3File.Key.ETag, "\"", "", 2)
	status.Stage = "Receive"
	status.Status = "Received"
	status.Note = "Item is in receiving bucket. Processing has not started."
	status.Institution = bagman.OwnerOf(s3File.BucketName)
	status.Outcome = status.Status

	// Retry should be true until we know for sure that there
	// is something wrong with the bag.
	status.Retry = true

	err = fluctusClient.UpdateBagStatus(status)
	if err != nil {
		return err
	}
	messageLog.Printf("[INFO] Created Fluctus ProcessedItem for %s\n",
		s3File.Key.Key)
	return nil
}

// enqueue adds a batch of items to the nsqd work queue
func enqueue(url string, s3Files []*bagman.S3File) {
	jsonData := make([]string, len(s3Files))
	for i, s3File := range s3Files {
		json, err := json.Marshal(s3File)
		if err != nil {
			messageLog.Printf("[ERROR] Error marshalling s3 file to JSON: %v", err)
		} else {
			jsonData[i] = string(json)
			messageLog.Println("[INFO]", "Put", s3File.Key.Key, "into fetch queue")
			//fmt.Println(s3File.Key.Key)
		}
	}
	batch := strings.Join(jsonData, "\n")
	resp, err := http.Post(url, "application/json", bytes.NewBuffer([]byte(batch)))
	if err != nil {
		messageLog.Printf("[ERROR] nsqd returned an error: %v", err)
	}
	if resp == nil {
		msg := "[ERROR] No response from nsqd. Is it running? bucket_reader is quitting."
		messageLog.Printf(msg)
		fmt.Println(msg)
		os.Exit(1)
	} else if resp.StatusCode != 200 {
		messageLog.Printf("[ERROR] nsqd returned status code %d on last mput", resp.StatusCode)
	}
}
<commit_msg>Get recently processed records in bulk when bucket reader starts<commit_after>// BucketReader gets a list of files awaiting processing in the S3
// intake buckets and adds each item to the queue for processing.
package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"github.com/APTrust/bagman"
	"github.com/APTrust/bagman/fluctus/client"
	"github.com/crowdmob/goamz/aws"
	"log"
	"net/http"
	"os"
	"strings"
	"time"
)

// Send S3 files to queue in batches of 500.
// Wait X milliseconds between batches. The wait time is really
// only necessary when the queue is running on an AWS small EC2
// instance, where the number of open network connections is
// severely restricted.
const (
	batchSize        = 500
	waitMilliseconds = 5000
)

var (
	config        bagman.Config
	jsonLog       *log.Logger
	messageLog    *log.Logger
	fluctusClient *client.Client
	statusCache   map[string]*bagman.ProcessStatus
)

func main() {
	err := initialize()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Initialization failed for bucket_reader: %v", err)
		os.Exit(1)
	}
	run()
}

func initialize() (err error) {
	// Load the config or die.
	requestedConfig := flag.String("config", "", "configuration to run")
	flag.Parse()
	config = bagman.LoadRequestedConfig(requestedConfig)
	jsonLog, messageLog = bagman.InitLoggers(config.LogDirectory, "bucket_reader")
	fluctusClient, err = client.New(
		config.FluctusURL,
		os.Getenv("FLUCTUS_API_USER"),
		os.Getenv("FLUCTUS_API_KEY"),
		messageLog)
	return err
}

func run() {
	s3Client, err := bagman.NewS3Client(aws.USEast)
	if err != nil {
		messageLog.Println("[ERROR]", err)
		return
	}
	bucketSummaries, err := s3Client.CheckAllBuckets(config.Buckets)
	if err != nil {
		messageLog.Println("[ERROR]", err)
		return
	}
	loadStatusCache()
	url := fmt.Sprintf("%s/mput?topic=%s", config.NsqdHttpAddress,
		config.BagProcessorTopic)
	messageLog.Printf("[INFO] Sending S3 file info to %s \n", url)
	s3Files := filterLargeFiles(bucketSummaries)
	messageLog.Printf("[INFO] %d S3 Files are within our size limit\n",
		len(s3Files))
	filesToProcess := s3Files
	// SkipAlreadyProcessed will almost always be true.
	// The exception is when we want to reprocess items to test new code.
	if config.SkipAlreadyProcessed == true {
		messageLog.Println("[INFO] Skipping already processed files, because config says so")
		filesToProcess = filterProcessedFiles(s3Files)
	} else {
		messageLog.Println("[INFO] Reprocessing already processed files, because config says so")
	}
	start := 0
	end := min(len(filesToProcess), batchSize)
	messageLog.Printf("[INFO] %d Unprocessed files\n", len(filesToProcess))
	for start <= end {
		batch := filesToProcess[start:end]
		messageLog.Printf("[INFO] Queuing batch of %d items\n", len(batch))
		enqueue(url, batch)
		start = end + 1
		if start < len(filesToProcess) {
			end = min(len(filesToProcess), start+batchSize)
		}
		// Sleep so we don't max out connections on EC2 small.
		// The utility server is running a lot of other network I/O
		// in addition to our queue.
		time.Sleep(time.Millisecond * waitMilliseconds)
	}
}

// min returns the minimum of x or y. The Math package has this function
// but you have to cast to floats.
func min(x, y int) int {
	if x < y {
		return x
	} else {
		return y
	}
}

// filterLargeFiles returns only those S3 files that are not larger
// than config.MaxFileSize. This is useful when running tests and
// demos on your local machine, so that you can limit your test
// runs to files under 100k (or whatever you set in config.json).
// You don't want to pull down lots of multi-gig files when you're
// just running local tests. In production, set maxFileSize to
// zero, or to some huge value to get all files.
func filterLargeFiles(bucketSummaries []*bagman.BucketSummary) (s3Files []*bagman.S3File) {
	for _, bucketSummary := range bucketSummaries {
		for _, key := range bucketSummary.Keys {
			if config.MaxFileSize == 0 || key.Size < config.MaxFileSize {
				s3Files = append(s3Files, &bagman.S3File{bucketSummary.BucketName, key})
			}
		}
	}
	return s3Files
}

// Remove S3 files that have been processed successfully.
// No need to reprocess those!
func filterProcessedFiles(s3Files []*bagman.S3File) (filesToProcess []*bagman.S3File) {
	for _, s3File := range s3Files {
		bagDate, err := time.Parse(bagman.S3DateFormat, s3File.Key.LastModified)
		if err != nil {
			messageLog.Printf("[ERROR] Cannot parse S3File mod date '%s'. "+
				"File %s will be re-processed.",
				s3File.Key.LastModified, s3File.Key.Key)
			filesToProcess = append(filesToProcess, s3File)
			continue
		}
		etag := strings.Replace(s3File.Key.ETag, "\"", "", 2)
		status := findInStatusCache(etag, s3File.Key.Key, bagDate)
		if status == nil {
			status, err = fluctusClient.GetBagStatus(etag, s3File.Key.Key, bagDate)
		}
		if err != nil {
			messageLog.Printf("[ERROR] Cannot get Fluctus bag status for %s. "+
				"Will re-process bag. Error was %v", s3File.Key.Key, err)
			filesToProcess = append(filesToProcess, s3File)
		} else if status == nil ||
			(status.Status == "Received" && time.Since(status.Date) > time.Hour*12) ||
			(status.Status == "Processing" && status.Retry == true) {
			reason := "Bag has not yet been successfully processed."
			if status == nil {
				err = createFluctusRecord(s3File)
				if err != nil {
					// TODO: Notify someone?
					messageLog.Printf("[ERROR] Could not create Fluctus ProcessedItem "+
						"for %s: %v", s3File.Key.Key, err)
				}
			}
			messageLog.Printf("[INFO] Will process bag %s: %s", s3File.Key.Key, reason)
			filesToProcess = append(filesToProcess, s3File)
		} else if status.Status != "Failed" {
			messageLog.Printf("[INFO] Skipping %s: already processed successfully.", s3File.Key.Key)
		} else if status.Retry == false {
			messageLog.Printf("[INFO] Skipping %s: retry flag is set to false.", s3File.Key.Key)
		}
	}
	return filesToProcess
}

// Loads status of all bags received in the past two hours from fluctus
// in a single call.
func loadStatusCache() {
	twoHoursAgo := time.Now().Add(time.Hour * -2)
	statusRecords, err := fluctusClient.BulkStatusGet(twoHoursAgo)
	if err != nil {
		messageLog.Println("[WARNING] Could not get bulk status records")
	} else {
		messageLog.Printf("[INFO] Got %d status records from the fluctopus\n", len(statusRecords))
		statusCache = make(map[string]*bagman.ProcessStatus, len(statusRecords))
		for i := range(statusRecords) {
			record := statusRecords[i]
			key := fmt.Sprintf("%s%s%s", record.ETag, record.Name, record.BagDate)
			statusCache[key] = record
		}
	}
}

// Finds the status of the specified tar bag in the cache that
// we retrieved from Fluctus. The cache can save us hundreds or
// thousands of HTTP calls each time the bucket reader runs.
func findInStatusCache(etag, name string, bagDate time.Time) (*bagman.ProcessStatus) {
	key := fmt.Sprintf("%s%s%s", etag, name, bagDate)
	item, exists := statusCache[key]
	if exists {
		messageLog.Println("[INFO] Found item in cache: %s", name)
		return item
	}
	messageLog.Println("[INFO] Item not in cache. Will have to ask the fluctopus for %s", name)
	return nil
}

func createFluctusRecord(s3File *bagman.S3File) (err error) {
	status := &bagman.ProcessStatus{}
	status.Date = time.Now().UTC()
	status.Action = "Ingest"
	status.Name = s3File.Key.Key
	bagDate, _ := time.Parse(bagman.S3DateFormat, s3File.Key.LastModified)
	status.BagDate = bagDate
	status.Bucket = s3File.BucketName
	// Strip the quotes off the ETag
	status.ETag = strings.Replace(s3File.Key.ETag, "\"", "", 2)
	status.Stage = "Receive"
	status.Status = "Received"
	status.Note = "Item is in receiving bucket. Processing has not started."
	status.Institution = bagman.OwnerOf(s3File.BucketName)
	status.Outcome = status.Status

	// Retry should be true until we know for sure that there
	// is something wrong with the bag.
	status.Retry = true

	err = fluctusClient.UpdateBagStatus(status)
	if err != nil {
		return err
	}
	messageLog.Printf("[INFO] Created Fluctus ProcessedItem for %s\n",
		s3File.Key.Key)
	return nil
}

// enqueue adds a batch of items to the nsqd work queue
func enqueue(url string, s3Files []*bagman.S3File) {
	jsonData := make([]string, len(s3Files))
	for i, s3File := range s3Files {
		json, err := json.Marshal(s3File)
		if err != nil {
			messageLog.Printf("[ERROR] Error marshalling s3 file to JSON: %v", err)
		} else {
			jsonData[i] = string(json)
			messageLog.Println("[INFO]", "Put", s3File.Key.Key, "into fetch queue")
		}
	}
	batch := strings.Join(jsonData, "\n")
	resp, err := http.Post(url, "application/json", bytes.NewBuffer([]byte(batch)))
	if err != nil {
		messageLog.Printf("[ERROR] nsqd returned an error: %v", err)
	}
	if resp == nil {
		msg := "[ERROR] No response from nsqd. Is it running? bucket_reader is quitting."
		messageLog.Printf(msg)
		fmt.Println(msg)
		os.Exit(1)
	} else if resp.StatusCode != 200 {
		messageLog.Printf("[ERROR] nsqd returned status code %d on last mput", resp.StatusCode)
	}
}
<|endoftext|>


<commit_before>package prgs

import (
	"os"
	"os/exec"
	"strings"
	"testing"

	. "github.com/VonC/godbg"
	"github.com/VonC/senvgo/envs"
	"github.com/VonC/senvgo/paths"
	. "github.com/smartystreets/goconvey/convey"
)

type testGetter struct{}

func (tg testGetter) Get() []Prg {
	return []Prg{&prg{}}
}
func TestMain(t *testing.T) {

	envs.Prgsenvname = "PRGSTEST"

	Convey("Prerequisite: Prgsenv is set", t, func() {
		SetBuffers(nil)
		defer func() {
			if r := recover(); r != nil {
				p := getRootPath().Add("test2/")
				if err := os.Setenv(envs.Prgsenvname, p.String()); err != nil {
					panic(err)
				}
				p = envs.Prgsenv()
				So(p.String(), ShouldEndWith, `\test2\`)
				So(len(p.String()), ShouldEqual, 9)
			}
		}()
		p := envs.Prgsenv()
		So(p.String(), ShouldEqual, `..\test2\`)
	})

	Convey("prgs can get prgs", t, func() {
		SetBuffers(nil)
		dg.Get()
		getter = testGetter{}
		So(len(Getter().Get()), ShouldEqual, 1)
		dg = defaultGetter{}
		getter = dg
	})

	Convey("Prg implements a Prger", t, func() {
		Convey("Prg has a name", func() {
			p := &prg{name: "prg1"}
			So(p.Name(), ShouldEqual, "prg1")
			var prg Prg = p
			So(prg.Name(), ShouldEqual, "prg1")
			_prgs = []Prg{p, p}
			So(len(Getter().Get()), ShouldEqual, 2)
		})
	})

}

func getRootPath() *paths.Path {
	p := paths.NewPath("..").Abs().NoSep()
	ps := p.Subst()
	// Perrdbgf("p='%v' => p.Subst()='%v'", p.String(), ps.String())
	if p == p.Subst() {
		drives := "PQRSTUVWXYZ"
		for _, drive := range drives {
			scmd := "subst " + string(drive) + ": " + p.String()
			Perrdbgf("scmd='%s'", scmd)
			c := exec.Command("cmd", "/C", scmd)
			out, err := c.CombinedOutput()
			if strings.Contains(string(out), "Drive already SUBSTed") {
				continue
			}
			if err != nil {
				Perrdbgf("out='%s'; err='%s'", out, err.Error())
				panic(err)
			}
			if string(out) == "" {
				p = paths.NewPath(string(drive) + ":/")
				break
			}
		}
	} else {
		p = ps
	}
	return p
}
<commit_msg>prgs test: update testGetter<commit_after>package prgs

import (
	"os"
	"os/exec"
	"strings"
	"testing"

	. "github.com/VonC/godbg"
	"github.com/VonC/senvgo/envs"
	"github.com/VonC/senvgo/paths"
	. "github.com/smartystreets/goconvey/convey"
)

type testGetter struct{}

func (tg testGetter) Get() []Prg {
	return []Prg{&prg{}, &prg{}}
}
func TestMain(t *testing.T) {

	envs.Prgsenvname = "PRGSTEST"

	Convey("Prerequisite: Prgsenv is set", t, func() {
		SetBuffers(nil)
		defer func() {
			if r := recover(); r != nil {
				p := getRootPath().Add("test2/")
				if err := os.Setenv(envs.Prgsenvname, p.String()); err != nil {
					panic(err)
				}
				p = envs.Prgsenv()
				So(p.String(), ShouldEndWith, `\test2\`)
				So(len(p.String()), ShouldEqual, 9)
			}
		}()
		p := envs.Prgsenv()
		So(p.String(), ShouldEqual, `..\test2\`)
	})

	Convey("prgs can get prgs", t, func() {
		SetBuffers(nil)
		dg.Get()
		getter = testGetter{}
		So(len(Getter().Get()), ShouldEqual, 2)
		dg = defaultGetter{}
		getter = dg
	})

	Convey("Prg implements a Prger", t, func() {
		Convey("Prg has a name", func() {
			p := &prg{name: "prg1"}
			So(p.Name(), ShouldEqual, "prg1")
			var prg Prg = p
			So(prg.Name(), ShouldEqual, "prg1")
			_prgs = []Prg{p, p}
			So(len(Getter().Get()), ShouldEqual, 2)
		})
	})

}

func getRootPath() *paths.Path {
	p := paths.NewPath("..").Abs().NoSep()
	ps := p.Subst()
	// Perrdbgf("p='%v' => p.Subst()='%v'", p.String(), ps.String())
	if p == p.Subst() {
		drives := "PQRSTUVWXYZ"
		for _, drive := range drives {
			scmd := "subst " + string(drive) + ": " + p.String()
			Perrdbgf("scmd='%s'", scmd)
			c := exec.Command("cmd", "/C", scmd)
			out, err := c.CombinedOutput()
			if strings.Contains(string(out), "Drive already SUBSTed") {
				continue
			}
			if err != nil {
				Perrdbgf("out='%s'; err='%s'", out, err.Error())
				panic(err)
			}
			if string(out) == "" {
				p = paths.NewPath(string(drive) + ":/")
				break
			}
		}
	} else {
		p = ps
	}
	return p
}
<|endoftext|>


<commit_before><commit_msg>Use proper irc nick<commit_after><|endoftext|>


<commit_before>// repmbox handles repbin mailboxes.
//
// Release 20150606.
// You can reach me with
// repclient --recipientPubKey 7VW3oPLzQc7VS2anLyDtrdARDdSwa7QTF7h3N2t6J2VN_DTshmJFEDa7XM2w9nHBq4CgtvK4kYdBp8G3wFPkYcGd1
// Don't forget to put your own key into your message! (create with repmbox -add)
package main

import (
	"bufio"
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"os/signal"
	"os/user"
	"path"
	"strconv"
	"strings"
	"time"
)

type sender struct {
	Sender     string
	PublicKey  string
	PrivateKey string
}

type config struct {
	PrivateKey string
	Server     string
	Start      int
	Count      int
	Sender     []sender
}

type senderKey struct {
	user    string
	privKey string
}

func genConfig() (*config, error) {
	// generate private key with repclient
	cmd := exec.Command("repclient", "--genkey", "--appdata")
	var out bytes.Buffer
	cmd.Stderr = &out
	if err := cmd.Run(); err != nil {
		return nil, err
	}
	var cfg config
	lines := strings.Split(out.String(), "\n")
	for _, line := range lines {
		parts := strings.Split(line, "\t")
		if len(parts) >= 2 && parts[0] == "STATUS (PrivateKey):" {
			cfg.PrivateKey = parts[1]
			break
		}
	}
	if cfg.PrivateKey == "" {
		return nil, fmt.Errorf("could not parse private key from output:\n%s", out.String())
	}
	cfg.Start = -1
	cfg.Count = 100
	return &cfg, nil
}

func loadConfig(configFile, configDir string) (*config, error) {
	if _, err := os.Stat(configFile); err != nil {
		return nil, fmt.Errorf("config file '%s' doesn't exist, generate with:\n"+
			"mkdir -p %s && repmbox --genconfig > %s", configFile, configDir, configFile)
	}
	data, err := ioutil.ReadFile(configFile)
	if err != nil {
		return nil, err
	}
	var cfg config
	if err := json.Unmarshal(data, &cfg); err != nil {
		return nil, err
	}
	// check server entry
	if cfg.Server == "" {
		return nil, fmt.Errorf("specify Server entry in config file '%s'", configFile)
	}
	return &cfg, nil
}

func (cfg *config) save(configFile string) error {
	jsn, err := json.MarshalIndent(cfg, "", "    ")
	if err != nil {
		return err
	}
	if err := ioutil.WriteFile(configFile, jsn, 0600); err != nil {
		return err
	}
	return nil
}

func (cfg *config) show() error {
	jsn, err := json.MarshalIndent(cfg, "", "    ")
	if err != nil {
		return err
	}
	fmt.Println(string(jsn))
	return nil
}

func (cfg *config) addSender(addSender, configFile string) error {
	var snd sender
	snd.Sender = addSender
	// generate key pair for sender
	cmd := exec.Command("repclient", "--gentemp",
		"--privkey", cfg.PrivateKey,
		"--appdata")
	var out bytes.Buffer
	cmd.Stderr = &out
	if err := cmd.Run(); err != nil {
		return err
	}
	lines := strings.Split(out.String(), "\n")
	for _, line := range lines {
		parts := strings.Split(line, "\t")
		if len(parts) >= 2 && parts[0] == "STATUS (PrivateKey):" {
			snd.PrivateKey = parts[1]
		}
		if len(parts) >= 2 && parts[0] == "STATUS (PublicKey):" {
			snd.PublicKey = parts[1]
			break
		}
	}
	if snd.PrivateKey == "" {
		return fmt.Errorf("could not parse private key from output:\n%s", out.String())
	}
	if snd.PublicKey == "" {
		return fmt.Errorf("could not parse public key from output:\n%s", out.String())
	}
	cfg.Sender = append(cfg.Sender, snd)
	if err := cfg.save(configFile); err != nil {
		return err
	}
	fmt.Printf("mailbox for %s added:\n", addSender)
	fmt.Println(snd.PublicKey)
	return nil
}

func (cfg *config) getList() ([]string, bool, error) {
	cmd := exec.Command("repclient",
		"--index",
		"--server", cfg.Server,
		"--privkey", cfg.PrivateKey,
		"--start", strconv.Itoa(cfg.Start+1),
		"--count", strconv.Itoa(cfg.Count),
		"--appdata")
	var out bytes.Buffer
	cmd.Stderr = &out
	if err := cmd.Run(); err != nil {
		// check if error indicates no new messages
		lines := strings.Split(out.String(), "\n")
		for _, line := range lines {
			if line == "FATAL: List error: listparse: No entries in list" {
				// return empty list
				return nil, false, nil
			}
		}
		// show and return error
		fmt.Print(out.String())
		return nil, false, err
	}
	var list []string
	var more bool
	lines := strings.Split(out.String(), "\n")
	for _, line := range lines {
		parts := strings.Split(line, "\t")
		if len(parts) >= 2 {
			if parts[0] == "STATUS (MessageList):" {
				particles := strings.Split(parts[1], " ")
				if len(particles) >= 2 {
					list = append(list, particles[1])
				} else {
					return nil, false, fmt.Errorf("could not parse line: %s", line)
				}
			} else if parts[0] == "STATUS (ListResult):" {
				particles := strings.Split(parts[1], " ")
				if len(particles) >= 3 {
					var err error
					more, err = strconv.ParseBool(particles[2])
					if err != nil {
						return nil, false, err
					}
					break
				}
			}
		}
	}
	return list, more, nil
}

func (cfg *config) getSenderKeys() map[string]senderKey {
	keys := make(map[string]senderKey)
	for _, sdr := range cfg.Sender {
		pubKeys := strings.Split(sdr.PublicKey, "_")
		privKeys := strings.Split(sdr.PrivateKey, "_")
		keys[pubKeys[0]] = senderKey{
			user:    sdr.Sender,
			privKey: privKeys[0],
		}
		keys[pubKeys[1]] = senderKey{
			user:    sdr.Sender,
			privKey: privKeys[1],
		}
	}
	return keys
}

func (cfg *config) getMessages(list []string, outdir, stmdir string, show, verbose bool) error {
	// make sure STM directory exists
	if err := os.MkdirAll(stmdir, 0700); err != nil {
		return err
	}
	for _, msg := range list {
		fmt.Printf("retrieving message %s\n", msg)
		cmd := exec.Command("repclient",
			"--decrypt",
			"--keymgt", "3",
			"--server", cfg.Server,
			"--stmdir", stmdir,
			"--appdata",
			msg)
		var out bytes.Buffer
		cmd.Stdout = &out
		stderr, err := cmd.StderrPipe()
		if err != nil {
			return err
		}
		r, w, err := os.Pipe()
		if err != nil {
			return err
		}
		cmd.ExtraFiles = append(cmd.ExtraFiles, r)
		if err := cmd.Start(); err != nil {
			return err
		}
		var user string
		var stmfile string
		var keyNotAvailable bool
		keys := cfg.getSenderKeys()
		scanner := bufio.NewScanner(stderr)
		for scanner.Scan() {
			line := scanner.Text()
			if verbose {
				fmt.Println(line)
			}
			parts := strings.Split(line, "\t")
			if len(parts) >= 2 {
				if parts[0] == "STATUS (KeyMGTRequest):" {
					key, ok := keys[parts[1]]
					if !ok {
						if _, err := w.WriteString("not available\n"); err != nil {
							return err
						}
						keyNotAvailable = true
						break
					} else {
						if _, err := w.WriteString(key.privKey + "\n"); err != nil {
							return err
						}
						user = key.user
					}
				} else if parts[0] == "STATUS (STMFile):" {
					stmfile = parts[1]
				}
			} else {
				return fmt.Errorf("could not parse repclient output: %s", line)
			}
		}
		if err := scanner.Err(); err != nil {
			return err
		}
		err = cmd.Wait()
		if !keyNotAvailable && err != nil {
			return fmt.Errorf("repclient call failed with: %s", err)
		}
		if stmfile != "" {
			fmt.Printf("new repost message from %s written to:\n%s\n", user, stmfile)
		} else if keyNotAvailable {
			fmt.Println("key not available, skipping message forever!")
		} else {
			// make sure output directory exists
			resdir := path.Join(outdir, user)
			if err := os.MkdirAll(resdir, 0700); err != nil {
				return err
			}
			// write message
			filename := path.Join(resdir, msg)
			if err := ioutil.WriteFile(path.Join(resdir, msg), out.Bytes(), 0600); err != nil {
				return err
			}
			fmt.Printf("new message from %s written to:\n%s\n", user, filename)
			// show message
			if show {
				fmt.Println("message content:")
				fmt.Println(out.String())
			}
		}
	}
	return nil
}

func (cfg *config) downloadNewMessages(outdir, stmdir, configFile string, show, verbose bool) error {
	more := true
	for more {
		var list []string
		var err error
		// get list
		list, more, err = cfg.getList()
		if err != nil {
			return err
		}
		if len(list) == 0 {
			if verbose {
				fmt.Println("no new messages")
			}
			break
		}
		// get new messages
		if err := cfg.getMessages(list, outdir, stmdir, show, verbose); err != nil {
			return err
		}
		// increase start
		cfg.Start += len(list)
		if err := cfg.save(configFile); err != nil {
			return err
		}
		if verbose {
			fmt.Printf("more: %s\n", strconv.FormatBool(more))
		}
	}
	return nil
}

func appDataDir(appName string) (string, error) {
	user, err := user.Current()
	if err != nil {
		return "", err
	}
	return path.Join(user.HomeDir, ".config", appName), nil
}

func writePIDFile(configDir string) (string, error) {
	// make sure config directory exists
	if err := os.MkdirAll(configDir, 0700); err != nil {
		return "", err
	}
	pidFile := path.Join(configDir, "repmbox.pid")
	if _, err := os.Stat(pidFile); err == nil {
		return "", fmt.Errorf("PID file '%s' already exists, another instance running?", pidFile)
	}
	fp, err := os.Create(pidFile)
	if err != nil {
		return "", err
	}
	if _, err := fp.WriteString(strconv.Itoa(os.Getpid()) + "\n"); err != nil {
		return "", err
	}
	if err := fp.Close(); err != nil {
		return "", err
	}
	return pidFile, nil
}

func mainFunc(configDir string) error {
	// define options
	addSender := flag.String("add", "", "Add new mailbox for given sender name")
	configFile := flag.String("configfile", path.Join(configDir, "repmbox.config"), "Path to configuration file")
	genconfig := flag.Bool("genconfig", false, "Generate config file")
	listSender := flag.Bool("list", false, "List mailboxes")
	loop := flag.Bool("loop", false, "Retrieve new messages every 5 minutes")
	outdir := flag.String("outdir", path.Join(configDir, "messages"), "Directory for downloaded messages")
	show := flag.Bool("show", false, "Show messages on stdout (additionally)")
	stmdir := flag.String("stmdir", path.Join(configDir, "stmdir"), "Directory for STM messages")
	verbose := flag.Bool("v", false, "Be verbose")
	// parse options
	flag.Parse()
	if *genconfig {
		cfg, err := genConfig()
		if err != nil {
			return err
		}
		if err := cfg.show(); err != nil {
			return err
		}
		return nil
	}
	// load config file
	cfg, err := loadConfig(*configFile, configDir)
	if err != nil {
		return err
	}
	if *listSender {
		for _, snd := range cfg.Sender {
			fmt.Println(snd.Sender, snd.PublicKey)
		}
		return nil
	}
	// write PID file
	pidFile, err := writePIDFile(configDir)
	if err != nil {
		return err
	}
	defer os.Remove(pidFile)
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	go func() {
		<-c // blocks until signal is received
		os.Remove(pidFile)
		os.Exit(2)
	}()
	if *addSender != "" {
		if err := cfg.addSender(*addSender, *configFile); err != nil {
			return err
		}
	} else {
		for true {
			if err := cfg.downloadNewMessages(*outdir, *stmdir, *configFile, *show, *verbose); err != nil {
				return err
			}
			if *loop {
				time.Sleep(5 * time.Minute)
			} else {
				break
			}
		}
	}
	return nil
}

func fatal(err error) {
	fmt.Fprintf(os.Stderr, "%s: error: %s\n", os.Args[0], err)
	os.Exit(1)
}

func main() {
	configDir, err := appDataDir("repmbox")
	if err != nil {
		fatal(err)
	}
	if err := mainFunc(configDir); err != nil {
		fatal(err)
	}
}
<commit_msg>don't show debug output<commit_after>// repmbox handles repbin mailboxes.
//
// Release 20150606.
// You can reach me with
// repclient --recipientPubKey 7VW3oPLzQc7VS2anLyDtrdARDdSwa7QTF7h3N2t6J2VN_DTshmJFEDa7XM2w9nHBq4CgtvK4kYdBp8G3wFPkYcGd1
// Don't forget to put your own key into your message! (create with repmbox -add)
package main

import (
	"bufio"
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"os/signal"
	"os/user"
	"path"
	"strconv"
	"strings"
	"time"
)

type sender struct {
	Sender     string
	PublicKey  string
	PrivateKey string
}

type config struct {
	PrivateKey string
	Server     string
	Start      int
	Count      int
	Sender     []sender
}

type senderKey struct {
	user    string
	privKey string
}

func genConfig() (*config, error) {
	// generate private key with repclient
	cmd := exec.Command("repclient", "--genkey", "--appdata")
	var out bytes.Buffer
	cmd.Stderr = &out
	if err := cmd.Run(); err != nil {
		return nil, err
	}
	var cfg config
	lines := strings.Split(out.String(), "\n")
	for _, line := range lines {
		parts := strings.Split(line, "\t")
		if len(parts) >= 2 && parts[0] == "STATUS (PrivateKey):" {
			cfg.PrivateKey = parts[1]
			break
		}
	}
	if cfg.PrivateKey == "" {
		return nil, fmt.Errorf("could not parse private key from output:\n%s", out.String())
	}
	cfg.Start = -1
	cfg.Count = 100
	return &cfg, nil
}

func loadConfig(configFile, configDir string) (*config, error) {
	if _, err := os.Stat(configFile); err != nil {
		return nil, fmt.Errorf("config file '%s' doesn't exist, generate with:\n"+
			"mkdir -p %s && repmbox --genconfig > %s", configFile, configDir, configFile)
	}
	data, err := ioutil.ReadFile(configFile)
	if err != nil {
		return nil, err
	}
	var cfg config
	if err := json.Unmarshal(data, &cfg); err != nil {
		return nil, err
	}
	// check server entry
	if cfg.Server == "" {
		return nil, fmt.Errorf("specify Server entry in config file '%s'", configFile)
	}
	return &cfg, nil
}

func (cfg *config) save(configFile string) error {
	jsn, err := json.MarshalIndent(cfg, "", "    ")
	if err != nil {
		return err
	}
	if err := ioutil.WriteFile(configFile, jsn, 0600); err != nil {
		return err
	}
	return nil
}

func (cfg *config) show() error {
	jsn, err := json.MarshalIndent(cfg, "", "    ")
	if err != nil {
		return err
	}
	fmt.Println(string(jsn))
	return nil
}

func (cfg *config) addSender(addSender, configFile string) error {
	var snd sender
	snd.Sender = addSender
	// generate key pair for sender
	cmd := exec.Command("repclient", "--gentemp",
		"--privkey", cfg.PrivateKey,
		"--appdata")
	var out bytes.Buffer
	cmd.Stderr = &out
	if err := cmd.Run(); err != nil {
		return err
	}
	lines := strings.Split(out.String(), "\n")
	for _, line := range lines {
		parts := strings.Split(line, "\t")
		if len(parts) >= 2 && parts[0] == "STATUS (PrivateKey):" {
			snd.PrivateKey = parts[1]
		}
		if len(parts) >= 2 && parts[0] == "STATUS (PublicKey):" {
			snd.PublicKey = parts[1]
			break
		}
	}
	if snd.PrivateKey == "" {
		return fmt.Errorf("could not parse private key from output:\n%s", out.String())
	}
	if snd.PublicKey == "" {
		return fmt.Errorf("could not parse public key from output:\n%s", out.String())
	}
	cfg.Sender = append(cfg.Sender, snd)
	if err := cfg.save(configFile); err != nil {
		return err
	}
	fmt.Printf("mailbox for %s added:\n", addSender)
	fmt.Println(snd.PublicKey)
	return nil
}

func (cfg *config) getList() ([]string, bool, error) {
	cmd := exec.Command("repclient",
		"--index",
		"--server", cfg.Server,
		"--privkey", cfg.PrivateKey,
		"--start", strconv.Itoa(cfg.Start+1),
		"--count", strconv.Itoa(cfg.Count),
		"--appdata")
	var out bytes.Buffer
	cmd.Stderr = &out
	if err := cmd.Run(); err != nil {
		// check if error indicates no new messages
		lines := strings.Split(out.String(), "\n")
		for _, line := range lines {
			if line == "FATAL: List error: listparse: No entries in list" {
				// return empty list
				return nil, false, nil
			}
		}
		// show and return error
		fmt.Print(out.String())
		return nil, false, err
	}
	var list []string
	var more bool
	lines := strings.Split(out.String(), "\n")
	for _, line := range lines {
		parts := strings.Split(line, "\t")
		if len(parts) >= 2 {
			if parts[0] == "STATUS (MessageList):" {
				particles := strings.Split(parts[1], " ")
				if len(particles) >= 2 {
					list = append(list, particles[1])
				} else {
					return nil, false, fmt.Errorf("could not parse line: %s", line)
				}
			} else if parts[0] == "STATUS (ListResult):" {
				particles := strings.Split(parts[1], " ")
				if len(particles) >= 3 {
					var err error
					more, err = strconv.ParseBool(particles[2])
					if err != nil {
						return nil, false, err
					}
					break
				}
			}
		}
	}
	return list, more, nil
}

func (cfg *config) getSenderKeys() map[string]senderKey {
	keys := make(map[string]senderKey)
	for _, sdr := range cfg.Sender {
		pubKeys := strings.Split(sdr.PublicKey, "_")
		privKeys := strings.Split(sdr.PrivateKey, "_")
		keys[pubKeys[0]] = senderKey{
			user:    sdr.Sender,
			privKey: privKeys[0],
		}
		keys[pubKeys[1]] = senderKey{
			user:    sdr.Sender,
			privKey: privKeys[1],
		}
	}
	return keys
}

func (cfg *config) getMessages(list []string, outdir, stmdir string, show, verbose bool) error {
	// make sure STM directory exists
	if err := os.MkdirAll(stmdir, 0700); err != nil {
		return err
	}
	for _, msg := range list {
		fmt.Printf("retrieving message %s\n", msg)
		cmd := exec.Command("repclient",
			"--decrypt",
			"--keymgt", "3",
			"--server", cfg.Server,
			"--stmdir", stmdir,
			"--appdata",
			msg)
		var out bytes.Buffer
		cmd.Stdout = &out
		stderr, err := cmd.StderrPipe()
		if err != nil {
			return err
		}
		r, w, err := os.Pipe()
		if err != nil {
			return err
		}
		cmd.ExtraFiles = append(cmd.ExtraFiles, r)
		if err := cmd.Start(); err != nil {
			return err
		}
		var user string
		var stmfile string
		var keyNotAvailable bool
		keys := cfg.getSenderKeys()
		scanner := bufio.NewScanner(stderr)
		for scanner.Scan() {
			line := scanner.Text()
			parts := strings.Split(line, "\t")
			if len(parts) >= 2 {
				if parts[0] == "STATUS (KeyMGTRequest):" {
					key, ok := keys[parts[1]]
					if !ok {
						if _, err := w.WriteString("not available\n"); err != nil {
							return err
						}
						keyNotAvailable = true
						break
					} else {
						if _, err := w.WriteString(key.privKey + "\n"); err != nil {
							return err
						}
						user = key.user
					}
				} else if parts[0] == "STATUS (STMFile):" {
					stmfile = parts[1]
				}
			} else {
				return fmt.Errorf("could not parse repclient output: %s", line)
			}
		}
		if err := scanner.Err(); err != nil {
			return err
		}
		err = cmd.Wait()
		if !keyNotAvailable && err != nil {
			return fmt.Errorf("repclient call failed with: %s", err)
		}
		if stmfile != "" {
			fmt.Printf("new repost message from %s written to:\n%s\n", user, stmfile)
		} else if keyNotAvailable {
			fmt.Println("key not available, skipping message forever!")
		} else {
			// make sure output directory exists
			resdir := path.Join(outdir, user)
			if err := os.MkdirAll(resdir, 0700); err != nil {
				return err
			}
			// write message
			filename := path.Join(resdir, msg)
			if err := ioutil.WriteFile(path.Join(resdir, msg), out.Bytes(), 0600); err != nil {
				return err
			}
			fmt.Printf("new message from %s written to:\n%s\n", user, filename)
			// show message
			if show {
				fmt.Println("message content:")
				fmt.Println(out.String())
			}
		}
	}
	return nil
}

func (cfg *config) downloadNewMessages(outdir, stmdir, configFile string, show, verbose bool) error {
	more := true
	for more {
		var list []string
		var err error
		// get list
		list, more, err = cfg.getList()
		if err != nil {
			return err
		}
		if len(list) == 0 {
			if verbose {
				fmt.Println("no new messages")
			}
			break
		}
		// get new messages
		if err := cfg.getMessages(list, outdir, stmdir, show, verbose); err != nil {
			return err
		}
		// increase start
		cfg.Start += len(list)
		if err := cfg.save(configFile); err != nil {
			return err
		}
		if verbose {
			fmt.Printf("more: %s\n", strconv.FormatBool(more))
		}
	}
	return nil
}

func appDataDir(appName string) (string, error) {
	user, err := user.Current()
	if err != nil {
		return "", err
	}
	return path.Join(user.HomeDir, ".config", appName), nil
}

func writePIDFile(configDir string) (string, error) {
	// make sure config directory exists
	if err := os.MkdirAll(configDir, 0700); err != nil {
		return "", err
	}
	pidFile := path.Join(configDir, "repmbox.pid")
	if _, err := os.Stat(pidFile); err == nil {
		return "", fmt.Errorf("PID file '%s' already exists, another instance running?", pidFile)
	}
	fp, err := os.Create(pidFile)
	if err != nil {
		return "", err
	}
	if _, err := fp.WriteString(strconv.Itoa(os.Getpid()) + "\n"); err != nil {
		return "", err
	}
	if err := fp.Close(); err != nil {
		return "", err
	}
	return pidFile, nil
}

func mainFunc(configDir string) error {
	// define options
	addSender := flag.String("add", "", "Add new mailbox for given sender name")
	configFile := flag.String("configfile", path.Join(configDir, "repmbox.config"), "Path to configuration file")
	genconfig := flag.Bool("genconfig", false, "Generate config file")
	listSender := flag.Bool("list", false, "List mailboxes")
	loop := flag.Bool("loop", false, "Retrieve new messages every 5 minutes")
	outdir := flag.String("outdir", path.Join(configDir, "messages"), "Directory for downloaded messages")
	show := flag.Bool("show", false, "Show messages on stdout (additionally)")
	stmdir := flag.String("stmdir", path.Join(configDir, "stmdir"), "Directory for STM messages")
	verbose := flag.Bool("v", false, "Be verbose")
	// parse options
	flag.Parse()
	if *genconfig {
		cfg, err := genConfig()
		if err != nil {
			return err
		}
		if err := cfg.show(); err != nil {
			return err
		}
		return nil
	}
	// load config file
	cfg, err := loadConfig(*configFile, configDir)
	if err != nil {
		return err
	}
	if *listSender {
		for _, snd := range cfg.Sender {
			fmt.Println(snd.Sender, snd.PublicKey)
		}
		return nil
	}
	// write PID file
	pidFile, err := writePIDFile(configDir)
	if err != nil {
		return err
	}
	defer os.Remove(pidFile)
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	go func() {
		<-c // blocks until signal is received
		os.Remove(pidFile)
		os.Exit(2)
	}()
	if *addSender != "" {
		if err := cfg.addSender(*addSender, *configFile); err != nil {
			return err
		}
	} else {
		for true {
			if err := cfg.downloadNewMessages(*outdir, *stmdir, *configFile, *show, *verbose); err != nil {
				return err
			}
			if *loop {
				time.Sleep(5 * time.Minute)
			} else {
				break
			}
		}
	}
	return nil
}

func fatal(err error) {
	fmt.Fprintf(os.Stderr, "%s: error: %s\n", os.Args[0], err)
	os.Exit(1)
}

func main() {
	configDir, err := appDataDir("repmbox")
	if err != nil {
		fatal(err)
	}
	if err := mainFunc(configDir); err != nil {
		fatal(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/HewlettPackard/oneview-golang/ov"
	"github.com/HewlettPackard/oneview-golang/utils"
	"os"
)

func main() {

	var (
		ClientOV       *ov.OVClient
		new_volume     = "TestVolume"
		name_to_update = "UpdatedName"
	)

	ovc := ClientOV.NewOVClient(
		os.Getenv("ONEVIEW_OV_USER"),
		os.Getenv("ONEVIEW_OV_PASSWORD"),
		os.Getenv("ONEVIEW_OV_DOMAIN"),
		os.Getenv("ONEVIEW_OV_ENDPOINT"),
		false,
		1000,
		"*")

	// Create storage volume with name <new_volume>
	properties := &ov.Properties{
		Name:                new_volume,
		Storagepool:         utils.NewNstring("/rest/storage-pools/F693B0B6-AD80-40C0-935D-AA99009ED046"),
		Size:                107374741824,
		ProvisioningType:    "Thin",
		DataProtectionLevel: "NetworkRaid10Mirror2Way",
	}

	storageVolume := ov.StorageVolume{TemplateURI: utils.NewNstring("/rest/storage-volume-templates/292c2ff4-3e9d-4936-9b24-aa99009f91a3"), Properties: properties, IsPermanent: true}

	err := ovc.CreateStorageVolume(storageVolume)
	if err != nil {
		fmt.Println("Could not create the volume", err)
	}

	// Update the given storage volume
	update_vol, _ := ovc.GetStorageVolumeByName(new_volume)

	updated_storage_volume := ov.StorageVolume{
		ProvisioningTypeForUpdate: update_vol.ProvisioningTypeForUpdate,
		IsPermanent:               update_vol.IsPermanent,
		IsShareable:               update_vol.IsShareable,
		Name:                      name_to_update,
		ProvisionedCapacity:       "107374741824",
		DeviceSpecificAttributes:  update_vol.DeviceSpecificAttributes,
		URI:             update_vol.URI,
		ETAG:            update_vol.ETAG,
		Description:     "empty",
		TemplateVersion: "1.1",
	}

	err = ovc.UpdateStorageVolume(updated_storage_volume)
	if err != nil {
		fmt.Println("Could not update the volume", err)
	}

	// Get All the volumes present
	fmt.Println("\nGetting all the storage volumes present in the system: \n")
	sort := "name:desc"
	vol_list, err := ovc.GetStorageVolumes("", sort)
	if err != nil {
		fmt.Println("Error Getting the storage volumes ", err)
	}
	for i := 0; i < len(vol_list.Members); i++ {
		fmt.Println(vol_list.Members[i].Name)
	}

	// Get volume by name
	fmt.Println("\nGetting details of volume with name: ", name_to_update)
	vol_by_name, _ := ovc.GetStorageVolumeByName(name_to_update)
	fmt.Println(vol_by_name)

	// Delete the created volume
	fmt.Println("\nDeleting the volume with name : UpdatedName")
	err = ovc.DeleteStorageVolume(name_to_update)
	if err != nil {
		fmt.Println("Delete Unsuccessful", err)
	}
}
<commit_msg>Update storage_volume.go<commit_after>
The Go Playground
Imports
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
package main

import (
	"fmt"
	"github.com/HewlettPackard/oneview-golang/ov"
	"github.com/HewlettPackard/oneview-golang/utils"
	"os"
)

func main() {

	var (
		ClientOV       *ov.OVClient
		new_volume     = "TestVolume"
		name_to_update = "UpdatedName"
	)

	ovc := ClientOV.NewOVClient(
		os.Getenv("ONEVIEW_OV_USER"),
		os.Getenv("ONEVIEW_OV_PASSWORD"),
		os.Getenv("ONEVIEW_OV_DOMAIN"),
		os.Getenv("ONEVIEW_OV_ENDPOINT"),
		false,
		1000,
		"*")

	// Create storage volume with name <new_volume>
	properties := &ov.Properties{
		Name:                new_volume,
		Storagepool:         utils.NewNstring("/rest/storage-pools/F693B0B6-AD80-40C0-935D-AA99009ED046"),
		Size:                107374741824,
		ProvisioningType:    "Thin",
		DataProtectionLevel: "NetworkRaid10Mirror2Way",
	}

	storageVolume := ov.StorageVolume{TemplateURI: utils.NewNstring("/rest/storage-volume-templates/292c2ff4-3e9d-4936-9b24-aa99009f91a3"), Properties: properties, IsPermanent: true}

	err := ovc.CreateStorageVolume(storageVolume)
	if err != nil {
		fmt.Println("Could not create the volume", err)
	}

	// Update the given storage volume
	update_vol, _ := ovc.GetStorageVolumeByName(new_volume)

	updated_storage_volume := ov.StorageVolume{
		ProvisioningTypeForUpdate: update_vol.ProvisioningTypeForUpdate,
		IsPermanent:               update_vol.IsPermanent,
		IsShareable:               update_vol.IsShareable,
		Name:                      name_to_update,
		ProvisionedCapacity:       "107374741824",
		DeviceSpecificAttributes:  update_vol.DeviceSpecificAttributes,
		URI:             update_vol.URI,
		ETAG:            update_vol.ETAG,
		Description:     "empty",
		TemplateVersion: "1.1",
	}

	err = ovc.UpdateStorageVolume(updated_storage_volume)
	if err != nil {
		fmt.Println("Could not update the volume", err)
	}

	// Get All the volumes present
	fmt.Println("\nGetting all the storage volumes present in the system: \n")
	sort := "name:desc"
	vol_list, err := ovc.GetStorageVolumes("", sort)
	if err != nil {
		fmt.Println("Error Getting the storage volumes ", err)
	}
	for i := 0; i < len(vol_list.Members); i++ {
		fmt.Println(vol_list.Members[i].Name)
	}

	// Get volume by name
	fmt.Println("\nGetting details of volume with name: ", name_to_update)
	vol_by_name, _ := ovc.GetStorageVolumeByName(name_to_update)
	fmt.Println(vol_by_name)

	// Delete the created volume
	fmt.Println("\nDeleting the volume with name : UpdatedName")
	err = ovc.DeleteStorageVolume(name_to_update)
	if err != nil {
		fmt.Println("Delete Unsuccessful", err)
	}
}
package main

import (
	"fmt"
)

func main() {
	fmt.Println("Hello, playground")
}

<|endoftext|>


<commit_before>package controller

import (
	"bytes"
	"crypto/sha1"
	"io"
	"io/ioutil"
	"os"
	"strings"
	"time"
	"encoding/hex"
)

//The module mainly encapsulates complex file operations.
//But recommended, will reduce the operating efficiency..

//Create a folder
func CreateDir(src string) error {
	return os.MkdirAll(src, os.ModePerm)
}

//Load file
func LoadFile(src string) ([]byte, error) {
	fd, err := os.Open(src)
	if err != nil {
		return nil, err
	}
	defer fd.Close()
	c, err := ioutil.ReadAll(fd)
	if err != nil {
		return nil, err
	}
	return c, nil
}

//Write file
//If the file does not exist, it is created.
func WriteFile(src string, content []byte) error {
	return ioutil.WriteFile(src, content, os.ModeAppend)
}

//Append data to a file
func WriteFileAppend(src string, content []byte, isForward bool) error {
	if IsFile(src) == false {
		return WriteFile(src, content)
	}
	c, err := LoadFile(src)
	if err != nil {
		return err
	}
	var s [][]byte
	if isForward == false {
		s = [][]byte{
			c,
			content,
		}
	} else {
		s = [][]byte{
			content,
			c,
		}
	}
	sep := []byte("")
	var newContent []byte = bytes.Join(s, sep)
	return WriteFile(src, newContent)
}

//Modify the file name
//Can be used to cut files.
func CutFile(src string, newSrc string) error {
	return os.Rename(src, newSrc)
}

//Copy file
func CopyFile(src string, dest string) (bool, error) {
	srcF, err := os.Open(src)
	if err != nil {
		return false, err
	}
	defer srcF.Close()
	destF, err := os.Create(dest)
	if err != nil {
		return false, err
	}
	defer destF.Close()
	_, err = io.Copy(destF, srcF)
	if err != nil {
		return false, err
	}
	return true, err
}

//Delete file
func DeleteFile(src string) error {
	return os.RemoveAll(src)
}

//Determine whether the file exists
func IsExist(src string) bool {
	_, err := os.Stat(src)
	return err == nil || os.IsExist(err)
}

//Determine whether the file
func IsFile(src string) bool {
	info, err := os.Stat(src)
	return err == nil && !info.IsDir()
}

//To determine whether the folder
func IsFolder(src string) bool {
	info, err := os.Stat(src)
	return err == nil && info.IsDir()
}

//Gets a list of files under the folder
// src string
// filter string eg : gif|jpg
// isSrc bool
func GetFileList(src string,filter string,isSrc bool) ([]string, error) {
	var fs []string
	dir, err := ioutil.ReadDir(src)
	if err != nil {
		return nil, err
	}
	var filters []string
	if filter != ""{
		filters = strings.Split(filter,"|")
	}
	for _, v := range dir {
		var appendSrc string
		if isSrc == true{
			appendSrc = src + GetPathSep() + v.Name()
		}else{
			appendSrc = v.Name()
		}
		if v.IsDir() == true {
			fs = append(fs, appendSrc)
			continue
		}
		if filter == "" {
			fs = append(fs, appendSrc)
			continue
		}
		names := strings.Split(v.Name(),".")
		if len(names) == 1{
			fs = append(fs, appendSrc)
			continue
		}
		t := names[len(names)-1]
		for _,filterValue := range filters{
			if t != filterValue{
				continue
			}
			fs = append(fs, appendSrc)
		}
	}
	return fs, nil
}

//Gets the number of files in the folder
func GetFileListCount(src string) (int, error) {
	dir, err := ioutil.ReadDir(src)
	if err != nil {
		return 0, err
	}
	var res int
	for range dir {
		res += 1
	}
	return res, nil
}

//Gets the system path separator
func GetPathSep() string {
	return string(os.PathSeparator)
}

//Get the file size
func GetFileSize(src string) int64 {
	info, err := os.Stat(src)
	if err != nil {
		return 0
	}
	return info.Size()
}

//Gets the file name and type
func GetFileNames(src string) (map[string]string, error) {
	info, err := GetFileInfo(src)
	if err != nil {
		return nil, err
	}
	res := map[string]string{
		"name":     info.Name(),
		"type":     "",
		"onlyName": info.Name(),
	}
	if res["name"] == "" {
		return res, nil
	}
	names := strings.Split(res["name"], ".")
	if len(names) < 2 {
		return res, nil
	}
	res["type"] = names[len(names)-1]
	res["onlyName"] = names[0]
	for i := range names {
		if i != 0 && i < len(names)-1 {
			res["onlyName"] = res["onlyName"] + "." + names[i]
		}
	}
	return res, nil
}

//Get file information
func GetFileInfo(src string) (os.FileInfo, error) {
	return os.Stat(src)
}

//Calculates the file sha1 value
func GetFileSha1(src string) (string, error) {
	content, err := LoadFile(src)
	if err != nil {
		return "", err
	}
	if content != nil {
		sha := sha1.New()
		sha.Write(content)
		res := sha.Sum(nil)
		return hex.EncodeToString(res), nil
	}
	return "", nil
}

//Gets the directory path for the time build
//eg : Return and create the path ,"[src]/201611/"
//eg : Return and create the path ,"[src]/201611/2016110102-03[appendFileType]"
func GetTimeDirSrc(src string, appendFileType string) (string, error) {
	t := time.Now()
	sep := GetPathSep()
	newSrc := src + sep + t.Format("200601")
	err = CreateDir(newSrc)
	newSrc = newSrc + sep
	if appendFileType != "" {
		newSrc = newSrc + t.Format("20060102-03") + appendFileType
	}
	return newSrc, err
}
<commit_msg>Update file-operate.go<commit_after>package controller

import (
	"bytes"
	"crypto/sha1"
	"io"
	"io/ioutil"
	"os"
	"strings"
	"time"
	"encoding/hex"
)

//The module mainly encapsulates complex file operations.
//But recommended, will reduce the operating efficiency..

//Create a folder
func CreateDir(src string) error {
	return os.MkdirAll(src, os.ModePerm)
}

//Load file
func LoadFile(src string) ([]byte, error) {
	fd, err := os.Open(src)
	if err != nil {
		return nil, err
	}
	defer fd.Close()
	c, err := ioutil.ReadAll(fd)
	if err != nil {
		return nil, err
	}
	return c, nil
}

//Write file
//If the file does not exist, it is created.
func WriteFile(src string, content []byte) error {
	return ioutil.WriteFile(src, content, 0644)
}

//Append data to a file
func WriteFileAppend(src string, content []byte, isForward bool) error {
	if IsFile(src) == false {
		return WriteFile(src, content)
	}
	c, err := LoadFile(src)
	if err != nil {
		return err
	}
	var s [][]byte
	if isForward == false {
		s = [][]byte{
			c,
			content,
		}
	} else {
		s = [][]byte{
			content,
			c,
		}
	}
	sep := []byte("")
	var newContent []byte = bytes.Join(s, sep)
	return WriteFile(src, newContent)
}

//Modify the file name
//Can be used to cut files.
func CutFile(src string, newSrc string) error {
	return os.Rename(src, newSrc)
}

//Copy file
func CopyFile(src string, dest string) (bool, error) {
	srcF, err := os.Open(src)
	if err != nil {
		return false, err
	}
	defer srcF.Close()
	destF, err := os.Create(dest)
	if err != nil {
		return false, err
	}
	defer destF.Close()
	_, err = io.Copy(destF, srcF)
	if err != nil {
		return false, err
	}
	return true, err
}

//Delete file
func DeleteFile(src string) error {
	return os.RemoveAll(src)
}

//Determine whether the file exists
func IsExist(src string) bool {
	_, err := os.Stat(src)
	return err == nil || os.IsExist(err)
}

//Determine whether the file
func IsFile(src string) bool {
	info, err := os.Stat(src)
	return err == nil && !info.IsDir()
}

//To determine whether the folder
func IsFolder(src string) bool {
	info, err := os.Stat(src)
	return err == nil && info.IsDir()
}

//Gets a list of files under the folder
// src string
// filter string eg : gif|jpg
// isSrc bool
func GetFileList(src string,filter string,isSrc bool) ([]string, error) {
	var fs []string
	dir, err := ioutil.ReadDir(src)
	if err != nil {
		return nil, err
	}
	var filters []string
	if filter != ""{
		filters = strings.Split(filter,"|")
	}
	for _, v := range dir {
		var appendSrc string
		if isSrc == true{
			appendSrc = src + GetPathSep() + v.Name()
		}else{
			appendSrc = v.Name()
		}
		if v.IsDir() == true {
			fs = append(fs, appendSrc)
			continue
		}
		if filter == "" {
			fs = append(fs, appendSrc)
			continue
		}
		names := strings.Split(v.Name(),".")
		if len(names) == 1{
			fs = append(fs, appendSrc)
			continue
		}
		t := names[len(names)-1]
		for _,filterValue := range filters{
			if t != filterValue{
				continue
			}
			fs = append(fs, appendSrc)
		}
	}
	return fs, nil
}

//Gets the number of files in the folder
func GetFileListCount(src string) (int, error) {
	dir, err := ioutil.ReadDir(src)
	if err != nil {
		return 0, err
	}
	var res int
	for range dir {
		res += 1
	}
	return res, nil
}

//Gets the system path separator
func GetPathSep() string {
	return string(os.PathSeparator)
}

//Get the file size
func GetFileSize(src string) int64 {
	info, err := os.Stat(src)
	if err != nil {
		return 0
	}
	return info.Size()
}

//Gets the file name and type
func GetFileNames(src string) (map[string]string, error) {
	info, err := GetFileInfo(src)
	if err != nil {
		return nil, err
	}
	res := map[string]string{
		"name":     info.Name(),
		"type":     "",
		"onlyName": info.Name(),
	}
	if res["name"] == "" {
		return res, nil
	}
	names := strings.Split(res["name"], ".")
	if len(names) < 2 {
		return res, nil
	}
	res["type"] = names[len(names)-1]
	res["onlyName"] = names[0]
	for i := range names {
		if i != 0 && i < len(names)-1 {
			res["onlyName"] = res["onlyName"] + "." + names[i]
		}
	}
	return res, nil
}

//Get file information
func GetFileInfo(src string) (os.FileInfo, error) {
	return os.Stat(src)
}

//Calculates the file sha1 value
func GetFileSha1(src string) (string, error) {
	content, err := LoadFile(src)
	if err != nil {
		return "", err
	}
	if content != nil {
		sha := sha1.New()
		sha.Write(content)
		res := sha.Sum(nil)
		return hex.EncodeToString(res), nil
	}
	return "", nil
}

//Gets the directory path for the time build
//eg : Return and create the path ,"[src]/201611/"
//eg : Return and create the path ,"[src]/201611/2016110102-03[appendFileType]"
func GetTimeDirSrc(src string, appendFileType string) (string, error) {
	t := time.Now()
	sep := GetPathSep()
	newSrc := src + sep + t.Format("200601")
	err = CreateDir(newSrc)
	newSrc = newSrc + sep
	if appendFileType != "" {
		newSrc = newSrc + t.Format("20060102-03") + appendFileType
	}
	return newSrc, err
}
<|endoftext|>


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

package gabi

import (
	"crypto/rand"
	"encoding/xml"
	"io"
	"io/ioutil"
	"math/big"
	"os"
	"strconv"
	"time"

	"errors"
	"github.com/credentials/safeprime"
)

const (
	//XMLHeader can be a used as the XML header when writing keys in XML format.
	XMLHeader = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"
	// DefaultEpochLength is the default epoch length for public keys.
	DefaultEpochLength = 432000
)

// PrivateKey represents an issuer's private key.
type PrivateKey struct {
	XMLName    xml.Name `xml:"http://www.zurich.ibm.com/security/idemix IssuerPrivateKey"`
	Counter    uint     `xml:"Counter"`
	ExpiryDate int64    `xml:"ExpiryDate"`
	P          *big.Int `xml:"Elements>p"`
	Q          *big.Int `xml:"Elements>q"`
	PPrime     *big.Int `xml:"Elements>pPrime"`
	QPrime     *big.Int `xml:"Elements>qPrime"`
}

// NewPrivateKey creates a new issuer private key using the provided parameters.
func NewPrivateKey(p, q *big.Int, counter uint, expiryDate time.Time) *PrivateKey {
	sk := PrivateKey{P: p, Q: q, PPrime: new(big.Int), QPrime: new(big.Int), Counter: counter, ExpiryDate: expiryDate.Unix()}

	sk.PPrime.Sub(p, bigONE)
	sk.PPrime.Rsh(sk.PPrime, 1)

	sk.QPrime.Sub(q, bigONE)
	sk.QPrime.Rsh(sk.QPrime, 1)

	return &sk
}

// NewPrivateKeyFromXML creates a new issuer private key using the xml data
// provided.
func NewPrivateKeyFromXML(xmlInput string) (*PrivateKey, error) {
	privk := &PrivateKey{}
	err := xml.Unmarshal([]byte(xmlInput), privk)
	if err != nil {
		return nil, err
	}
	return privk, nil
}

// NewPrivateKeyFromFile create a new issuer private key from an xml file.
func NewPrivateKeyFromFile(filename string) (*PrivateKey, error) {
	f, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	privk := &PrivateKey{}

	b, err := ioutil.ReadAll(f)
	if err != nil {
		return nil, err
	}

	err = xml.Unmarshal(b, privk)
	if err != nil {
		return nil, err
	}
	return privk, nil
}

// Print prints the key to stdout.
func (privk *PrivateKey) Print() error {
	_, err := privk.WriteTo(os.Stdout)
	return err
}

// WriteTo writes the XML-serialized public key to the given writer.
func (privk *PrivateKey) WriteTo(writer io.Writer) (int64, error) {
	// Write the standard XML header
	numHeaderBytes, err := writer.Write([]byte(XMLHeader))
	if err != nil {
		return 0, err
	}

	// And the actual xml body (with indentation)
	b, err := xml.MarshalIndent(privk, "", "   ")
	if err != nil {
		return int64(numHeaderBytes), err
	}
	numBodyBytes, err := writer.Write(b)
	return int64(numHeaderBytes + numBodyBytes), err
}

// WriteToFile writes the private key to an xml file. If any existing file with
// the same filename should be overwritten, set forceOverwrite to true.
func (privk *PrivateKey) WriteToFile(filename string, forceOverwrite bool) (int64, error) {
	var f *os.File
	var err error
	if forceOverwrite {
		f, err = os.Create(filename)
	} else {
		// This should return an error if the file already exists
		f, err = os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666)
	}
	if err != nil {
		return 0, err
	}
	defer f.Close()

	return privk.WriteTo(f)
}

// xmlBases is an auxiliary struct to encode/decode the odd way bases are
// represented in the xml representation of public keys
type xmlBases struct {
	Num   int        `xml:"num,attr"`
	Bases []*xmlBase `xml:",any"`
}

type xmlBase struct {
	XMLName xml.Name
	Bigint  string `xml:",innerxml"` // Has to be a string for ",innerxml" to work
}

// xmlFeatures is an auxiliary struct to make the XML encoding/decoding a bit
// easier while keeping the struct for PublicKey somewhat simple.
type xmlFeatures struct {
	Epoch struct {
		Length int `xml:"length,attr"`
	}
}

// Bases is a type that is introduced to simplify the encoding/decoding of
// a PublicKey whilst using the xml support of Go's standard library.
type Bases []*big.Int

// UnmarshalXML is an internal function to simplify decoding a PublicKey from
// XML.
func (bl *Bases) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
	var t xmlBases

	if err := d.DecodeElement(&t, &start); err != nil {
		return err
	}

	arr := make([]*big.Int, t.Num)
	for i := range arr {
		arr[i], _ = new(big.Int).SetString(t.Bases[i].Bigint, 10)
	}

	*bl = Bases(arr)
	return nil
}

// MarshalXML is an internal function to simplify encoding a PublicKey to XML.
func (bl *Bases) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
	l := len(*bl)
	bases := make([]*xmlBase, l)

	for i := range bases {
		bases[i] = &xmlBase{
			XMLName: xml.Name{Local: "Base_" + strconv.Itoa(i)},
			Bigint:  (*bl)[i].String(),
		}
	}

	t := xmlBases{
		Num:   l,
		Bases: bases,
	}
	return e.EncodeElement(t, start)
}

// EpochLength is a type that is introduced to simplify the encoding/decoding of
// a PublicKey whilst using the xml support of Go's standard library.
type EpochLength int

// UnmarshalXML is an internal function to simplify decoding a PublicKey from
// XML.
func (el *EpochLength) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
	var t xmlFeatures

	if err := d.DecodeElement(&t, &start); err != nil {
		return err
	}
	*el = EpochLength(t.Epoch.Length)
	return nil
}

// MarshalXML is an internal function to simplify encoding a PublicKey to XML.
func (el *EpochLength) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
	var t xmlFeatures
	t.Epoch.Length = int(*el)
	return e.EncodeElement(t, start)
}

// PublicKey represents an issuer's public key.
type PublicKey struct {
	XMLName     xml.Name          `xml:"http://www.zurich.ibm.com/security/idemix IssuerPublicKey"`
	Counter     uint              `xml:"Counter"`
	ExpiryDate  int64             `xml:"ExpiryDate"`
	N           *big.Int          `xml:"Elements>n"` // Modulus n
	Z           *big.Int          `xml:"Elements>Z"` // Generator Z
	S           *big.Int          `xml:"Elements>S"` // Generator S
	R           Bases             `xml:"Elements>Bases"`
	EpochLength EpochLength       `xml:"Features"`
	Params      *SystemParameters `xml:"-"`
}

// NewPublicKey creates and returns a new public key based on the provided parameters.
func NewPublicKey(N, Z, S *big.Int, R []*big.Int, counter uint, expiryDate time.Time) *PublicKey {
	return &PublicKey{
		Counter:     counter,
		ExpiryDate:  expiryDate.Unix(),
		N:           N,
		Z:           Z,
		S:           S,
		R:           R,
		EpochLength: DefaultEpochLength,
		Params:      DefaultSystemParameters[N.BitLen()],
	}
}

// NewPublicKeyFromXML creates a new issuer public key using the xml data
// provided.
func NewPublicKeyFromXML(xmlInput string) (*PublicKey, error) {
	// TODO: this might fail in the future. The DefaultSystemParameters and the
	// public key might not match!
	pubk := &PublicKey{}
	err := xml.Unmarshal([]byte(xmlInput), pubk)
	if err != nil {
		return nil, err
	}
	keylength := pubk.N.BitLen()
	if sysparam, ok := DefaultSystemParameters[keylength]; ok {
		pubk.Params = sysparam
	} else {
		return nil, errors.New("Unknown keylength")
	}
	return pubk, nil
}

// NewPublicKeyFromFile create a new issuer public key from an xml file.
func NewPublicKeyFromFile(filename string) (*PublicKey, error) {
	f, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	pubk := &PublicKey{}

	b, err := ioutil.ReadAll(f)
	if err != nil {
		return nil, err
	}

	err = xml.Unmarshal(b, pubk)
	if err != nil {
		return nil, err
	}
	return pubk, nil
}

// Print prints the key to stdout.
func (pubk *PublicKey) Print() error {
	_, err := pubk.WriteTo(os.Stdout)
	return err
}

// WriteTo writes the XML-serialized public key to the given writer.
func (pubk *PublicKey) WriteTo(writer io.Writer) (int64, error) {
	// Write the standard XML header
	numHeaderBytes, err := writer.Write([]byte(XMLHeader))
	if err != nil {
		return 0, err
	}

	// And the actual xml body (with indentation)
	b, err := xml.MarshalIndent(pubk, "", "   ")
	if err != nil {
		return int64(numHeaderBytes), err
	}
	numBodyBytes, err := writer.Write(b)
	return int64(numHeaderBytes + numBodyBytes), err
}

// WriteToFile writes the public key to an xml file. If any existing file with
// the same filename should be overwritten, set forceOverwrite to true.
func (pubk *PublicKey) WriteToFile(filename string, forceOverwrite bool) (int64, error) {
	var f *os.File
	var err error
	if forceOverwrite {
		f, err = os.Create(filename)
	} else {
		// This should return an error if the file already exists
		f, err = os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666)
	}
	if err != nil {
		return 0, err
	}
	defer f.Close()

	return pubk.WriteTo(f)
}

// randomSafePrime produces a safe prime of the requested number of bits
func randomSafePrime(bits int) (*big.Int, error) {
	p2 := new(big.Int)
	for {
		p, err := rand.Prime(rand.Reader, bits)
		if err != nil {
			return nil, err
		}
		p2.Rsh(p, 1) // p2 = (p - 1)/2
		if p2.ProbablyPrime(20) {
			return p, nil
		}
	}
}

// GenerateKeyPair generates a private/public keypair for an Issuer
func GenerateKeyPair(param *SystemParameters, attrsAmount int, counter uint, expiryDate time.Time) (*PrivateKey, *PublicKey, error) {
	primeSize := param.Ln / 2

	// p and q need to be safe primes
	p, err := safeprime.Generate(int(primeSize))
	if err != nil {
		return nil, nil, err
	}

	q, err := safeprime.Generate(int(primeSize))
	if err != nil {
		return nil, nil, err
	}

	priv := &PrivateKey{P: p, Q: q, PPrime: new(big.Int), QPrime: new(big.Int), Counter: counter, ExpiryDate: expiryDate.Unix()}

	// compute p' and q'
	priv.PPrime.Sub(priv.P, bigONE)
	priv.PPrime.Rsh(priv.PPrime, 1)

	priv.QPrime.Sub(priv.Q, bigONE)
	priv.QPrime.Rsh(priv.QPrime, 1)

	// compute n
	pubk := &PublicKey{Params: param, EpochLength: DefaultEpochLength, Counter: counter, ExpiryDate: expiryDate.Unix()}
	pubk.N = new(big.Int).Mul(priv.P, priv.Q)

	// Find an acceptable value for S; we follow lead of the Silvia code here:
	// Pick a random l_n value and check whether it is a quadratic residue modulo n

	var s *big.Int
	for {
		s, err = randomBigInt(param.Ln)
		if err != nil {
			return nil, nil, err
		}
		// check if S \elem Z_n
		if s.Cmp(pubk.N) > 0 {
			continue
		}
		if legendreSymbol(s, priv.P) == 1 && legendreSymbol(s, priv.Q) == 1 {
			break
		}
	}

	pubk.S = s

	// Derive Z from S
	var x *big.Int
	for {
		x, _ = randomBigInt(primeSize)
		if x.Cmp(bigTWO) > 0 && x.Cmp(pubk.N) < 0 {
			break
		}
	}

	// Compute Z = S^x mod n
	pubk.Z = new(big.Int).Exp(pubk.S, x, pubk.N)

	// Derive R_i for i = 0...attrsAmount from S
	pubk.R = make([]*big.Int, attrsAmount)
	for i := 0; i < attrsAmount; i++ {
		pubk.R[i] = new(big.Int)

		var x *big.Int
		for {
			x, _ = randomBigInt(primeSize)
			if x.Cmp(bigTWO) > 0 && x.Cmp(pubk.N) < 0 {
				break
			}
		}
		// Compute R_i = S^x mod n
		pubk.R[i].Exp(pubk.S, x, pubk.N)
	}

	return priv, pubk, nil
}
<commit_msg>Small refactoring.<commit_after>// Copyright 2016 Maarten Everts. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package gabi

import (
	"crypto/rand"
	"encoding/xml"
	"io"
	"io/ioutil"
	"math/big"
	"os"
	"strconv"
	"time"

	"errors"
	"github.com/credentials/safeprime"
)

const (
	//XMLHeader can be a used as the XML header when writing keys in XML format.
	XMLHeader = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"
	// DefaultEpochLength is the default epoch length for public keys.
	DefaultEpochLength = 432000
)

// PrivateKey represents an issuer's private key.
type PrivateKey struct {
	XMLName    xml.Name `xml:"http://www.zurich.ibm.com/security/idemix IssuerPrivateKey"`
	Counter    uint     `xml:"Counter"`
	ExpiryDate int64    `xml:"ExpiryDate"`
	P          *big.Int `xml:"Elements>p"`
	Q          *big.Int `xml:"Elements>q"`
	PPrime     *big.Int `xml:"Elements>pPrime"`
	QPrime     *big.Int `xml:"Elements>qPrime"`
}

// NewPrivateKey creates a new issuer private key using the provided parameters.
func NewPrivateKey(p, q *big.Int, counter uint, expiryDate time.Time) *PrivateKey {
	sk := PrivateKey{P: p, Q: q, PPrime: new(big.Int), QPrime: new(big.Int), Counter: counter, ExpiryDate: expiryDate.Unix()}

	sk.PPrime.Sub(p, bigONE)
	sk.PPrime.Rsh(sk.PPrime, 1)

	sk.QPrime.Sub(q, bigONE)
	sk.QPrime.Rsh(sk.QPrime, 1)

	return &sk
}

// NewPrivateKeyFromXML creates a new issuer private key using the xml data
// provided.
func NewPrivateKeyFromXML(xmlInput string) (*PrivateKey, error) {
	privk := &PrivateKey{}
	err := xml.Unmarshal([]byte(xmlInput), privk)
	if err != nil {
		return nil, err
	}
	return privk, nil
}

// NewPrivateKeyFromFile create a new issuer private key from an xml file.
func NewPrivateKeyFromFile(filename string) (*PrivateKey, error) {
	f, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	privk := &PrivateKey{}

	b, err := ioutil.ReadAll(f)
	if err != nil {
		return nil, err
	}

	err = xml.Unmarshal(b, privk)
	if err != nil {
		return nil, err
	}
	return privk, nil
}

// Print prints the key to stdout.
func (privk *PrivateKey) Print() error {
	_, err := privk.WriteTo(os.Stdout)
	return err
}

// WriteTo writes the XML-serialized public key to the given writer.
func (privk *PrivateKey) WriteTo(writer io.Writer) (int64, error) {
	// Write the standard XML header
	numHeaderBytes, err := writer.Write([]byte(XMLHeader))
	if err != nil {
		return 0, err
	}

	// And the actual xml body (with indentation)
	b, err := xml.MarshalIndent(privk, "", "   ")
	if err != nil {
		return int64(numHeaderBytes), err
	}
	numBodyBytes, err := writer.Write(b)
	return int64(numHeaderBytes + numBodyBytes), err
}

// WriteToFile writes the private key to an xml file. If any existing file with
// the same filename should be overwritten, set forceOverwrite to true.
func (privk *PrivateKey) WriteToFile(filename string, forceOverwrite bool) (int64, error) {
	var f *os.File
	var err error
	if forceOverwrite {
		f, err = os.Create(filename)
	} else {
		// This should return an error if the file already exists
		f, err = os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666)
	}
	if err != nil {
		return 0, err
	}
	defer f.Close()

	return privk.WriteTo(f)
}

// xmlBases is an auxiliary struct to encode/decode the odd way bases are
// represented in the xml representation of public keys
type xmlBases struct {
	Num   int        `xml:"num,attr"`
	Bases []*xmlBase `xml:",any"`
}

type xmlBase struct {
	XMLName xml.Name
	Bigint  string `xml:",innerxml"` // Has to be a string for ",innerxml" to work
}

// xmlFeatures is an auxiliary struct to make the XML encoding/decoding a bit
// easier while keeping the struct for PublicKey somewhat simple.
type xmlFeatures struct {
	Epoch struct {
		Length int `xml:"length,attr"`
	}
}

// Bases is a type that is introduced to simplify the encoding/decoding of
// a PublicKey whilst using the xml support of Go's standard library.
type Bases []*big.Int

// UnmarshalXML is an internal function to simplify decoding a PublicKey from
// XML.
func (bl *Bases) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
	var t xmlBases

	if err := d.DecodeElement(&t, &start); err != nil {
		return err
	}

	arr := make([]*big.Int, t.Num)
	for i := range arr {
		arr[i], _ = new(big.Int).SetString(t.Bases[i].Bigint, 10)
	}

	*bl = Bases(arr)
	return nil
}

// MarshalXML is an internal function to simplify encoding a PublicKey to XML.
func (bl *Bases) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
	l := len(*bl)
	bases := make([]*xmlBase, l)

	for i := range bases {
		bases[i] = &xmlBase{
			XMLName: xml.Name{Local: "Base_" + strconv.Itoa(i)},
			Bigint:  (*bl)[i].String(),
		}
	}

	t := xmlBases{
		Num:   l,
		Bases: bases,
	}
	return e.EncodeElement(t, start)
}

// EpochLength is a type that is introduced to simplify the encoding/decoding of
// a PublicKey whilst using the xml support of Go's standard library.
type EpochLength int

// UnmarshalXML is an internal function to simplify decoding a PublicKey from
// XML.
func (el *EpochLength) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
	var t xmlFeatures

	if err := d.DecodeElement(&t, &start); err != nil {
		return err
	}
	*el = EpochLength(t.Epoch.Length)
	return nil
}

// MarshalXML is an internal function to simplify encoding a PublicKey to XML.
func (el *EpochLength) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
	var t xmlFeatures
	t.Epoch.Length = int(*el)
	return e.EncodeElement(t, start)
}

// PublicKey represents an issuer's public key.
type PublicKey struct {
	XMLName     xml.Name          `xml:"http://www.zurich.ibm.com/security/idemix IssuerPublicKey"`
	Counter     uint              `xml:"Counter"`
	ExpiryDate  int64             `xml:"ExpiryDate"`
	N           *big.Int          `xml:"Elements>n"` // Modulus n
	Z           *big.Int          `xml:"Elements>Z"` // Generator Z
	S           *big.Int          `xml:"Elements>S"` // Generator S
	R           Bases             `xml:"Elements>Bases"`
	EpochLength EpochLength       `xml:"Features"`
	Params      *SystemParameters `xml:"-"`
}

// NewPublicKey creates and returns a new public key based on the provided parameters.
func NewPublicKey(N, Z, S *big.Int, R []*big.Int, counter uint, expiryDate time.Time) *PublicKey {
	return &PublicKey{
		Counter:     counter,
		ExpiryDate:  expiryDate.Unix(),
		N:           N,
		Z:           Z,
		S:           S,
		R:           R,
		EpochLength: DefaultEpochLength,
		Params:      DefaultSystemParameters[N.BitLen()],
	}
}

// NewPublicKeyFromXML creates a new issuer public key using the xml data
// provided.
func NewPublicKeyFromXML(xmlInput string) (*PublicKey, error) {
	// TODO: this might fail in the future. The DefaultSystemParameters and the
	// public key might not match!
	pubk := &PublicKey{}
	err := xml.Unmarshal([]byte(xmlInput), pubk)
	if err != nil {
		return nil, err
	}
	keylength := pubk.N.BitLen()
	if sysparam, ok := DefaultSystemParameters[keylength]; ok {
		pubk.Params = sysparam
	} else {
		return nil, errors.New("Unknown keylength")
	}
	return pubk, nil
}

// NewPublicKeyFromFile create a new issuer public key from an xml file.
func NewPublicKeyFromFile(filename string) (*PublicKey, error) {
	f, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	pubk := &PublicKey{}

	b, err := ioutil.ReadAll(f)
	if err != nil {
		return nil, err
	}

	err = xml.Unmarshal(b, pubk)
	if err != nil {
		return nil, err
	}
	return pubk, nil
}

// Print prints the key to stdout.
func (pubk *PublicKey) Print() error {
	_, err := pubk.WriteTo(os.Stdout)
	return err
}

// WriteTo writes the XML-serialized public key to the given writer.
func (pubk *PublicKey) WriteTo(writer io.Writer) (int64, error) {
	// Write the standard XML header
	numHeaderBytes, err := writer.Write([]byte(XMLHeader))
	if err != nil {
		return 0, err
	}

	// And the actual xml body (with indentation)
	b, err := xml.MarshalIndent(pubk, "", "   ")
	if err != nil {
		return int64(numHeaderBytes), err
	}
	numBodyBytes, err := writer.Write(b)
	return int64(numHeaderBytes + numBodyBytes), err
}

// WriteToFile writes the public key to an xml file. If any existing file with
// the same filename should be overwritten, set forceOverwrite to true.
func (pubk *PublicKey) WriteToFile(filename string, forceOverwrite bool) (int64, error) {
	var f *os.File
	var err error
	if forceOverwrite {
		f, err = os.Create(filename)
	} else {
		// This should return an error if the file already exists
		f, err = os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666)
	}
	if err != nil {
		return 0, err
	}
	defer f.Close()

	return pubk.WriteTo(f)
}

// randomSafePrime produces a safe prime of the requested number of bits
func randomSafePrime(bits int) (*big.Int, error) {
	p2 := new(big.Int)
	for {
		p, err := rand.Prime(rand.Reader, bits)
		if err != nil {
			return nil, err
		}
		p2.Rsh(p, 1) // p2 = (p - 1)/2
		if p2.ProbablyPrime(20) {
			return p, nil
		}
	}
}

// GenerateKeyPair generates a private/public keypair for an Issuer
func GenerateKeyPair(param *SystemParameters, numAttributes int, counter uint, expiryDate time.Time) (*PrivateKey, *PublicKey, error) {
	primeSize := param.Ln / 2

	// p and q need to be safe primes
	p, err := safeprime.Generate(int(primeSize))
	if err != nil {
		return nil, nil, err
	}

	q, err := safeprime.Generate(int(primeSize))
	if err != nil {
		return nil, nil, err
	}

	priv := &PrivateKey{P: p, Q: q, PPrime: new(big.Int), QPrime: new(big.Int), Counter: counter, ExpiryDate: expiryDate.Unix()}

	// compute p' and q'
	priv.PPrime.Sub(priv.P, bigONE)
	priv.PPrime.Rsh(priv.PPrime, 1)

	priv.QPrime.Sub(priv.Q, bigONE)
	priv.QPrime.Rsh(priv.QPrime, 1)

	// compute n
	pubk := &PublicKey{Params: param, EpochLength: DefaultEpochLength, Counter: counter, ExpiryDate: expiryDate.Unix()}
	pubk.N = new(big.Int).Mul(priv.P, priv.Q)

	// Find an acceptable value for S; we follow lead of the Silvia code here:
	// Pick a random l_n value and check whether it is a quadratic residue modulo n

	var s *big.Int
	for {
		s, err = randomBigInt(param.Ln)
		if err != nil {
			return nil, nil, err
		}
		// check if S \elem Z_n
		if s.Cmp(pubk.N) > 0 {
			continue
		}
		if legendreSymbol(s, priv.P) == 1 && legendreSymbol(s, priv.Q) == 1 {
			break
		}
	}

	pubk.S = s

	// Derive Z from S
	var x *big.Int
	for {
		x, _ = randomBigInt(primeSize)
		if x.Cmp(bigTWO) > 0 && x.Cmp(pubk.N) < 0 {
			break
		}
	}

	// Compute Z = S^x mod n
	pubk.Z = new(big.Int).Exp(pubk.S, x, pubk.N)

	// Derive R_i for i = 0...numAttributes from S
	pubk.R = make([]*big.Int, numAttributes)
	for i := 0; i < numAttributes; i++ {
		pubk.R[i] = new(big.Int)

		var x *big.Int
		for {
			x, _ = randomBigInt(primeSize)
			if x.Cmp(bigTWO) > 0 && x.Cmp(pubk.N) < 0 {
				break
			}
		}
		// Compute R_i = S^x mod n
		pubk.R[i].Exp(pubk.S, x, pubk.N)
	}

	return priv, pubk, nil
}
<|endoftext|>


<commit_before>package ginkgo

import (
	"github.com/onsi/ginkgo/types"
	"time"
)

type example struct {
	subject exampleSubject
	focused bool

	containers []*containerNode

	state               types.ExampleState
	runTime             time.Duration
	failure             types.ExampleFailure
	didInterceptFailure bool
	interceptedFailure  failureData
}

func newExample(subject exampleSubject) *example {
	ex := &example{
		subject: subject,
		focused: subject.getFlag() == flagTypeFocused,
	}

	if subject.getFlag() == flagTypePending {
		ex.state = types.ExampleStatePending
	}

	return ex
}

func (ex *example) addContainerNode(container *containerNode) {
	ex.containers = append([]*containerNode{container}, ex.containers...)
	if container.flag == flagTypeFocused {
		ex.focused = true
	} else if container.flag == flagTypePending {
		ex.state = types.ExampleStatePending
	}
}

func (ex *example) fail(failure failureData) {
	if !ex.didInterceptFailure {
		ex.interceptedFailure = failure
		ex.didInterceptFailure = true
	}
}

func (ex *example) skip() {
	ex.state = types.ExampleStateSkipped
}

func (ex *example) subjectComponentType() types.ExampleComponentType {
	if ex.subject.nodeType() == nodeTypeMeasure {
		return types.ExampleComponentTypeMeasure
	} else {
		return types.ExampleComponentTypeIt
	}
}

func (ex *example) desiredNumberOfSamples() int {
	if ex.subject.nodeType() == nodeTypeMeasure {
		return ex.subject.(*measureNode).samples
	}

	return 1
}

func (ex *example) failed() bool {
	return ex.state == types.ExampleStateFailed || ex.state == types.ExampleStatePanicked || ex.state == types.ExampleStateTimedOut
}

func (ex *example) skippedOrPending() bool {
	return ex.state == types.ExampleStateSkipped || ex.state == types.ExampleStatePending
}

func (ex *example) pending() bool {
	return ex.state == types.ExampleStatePending
}

func (ex *example) run() {
	startTime := time.Now()
	defer func() {
		ex.runTime = time.Since(startTime)
	}()

	for sample := 0; sample < ex.desiredNumberOfSamples(); sample++ {
		ex.state, ex.failure = ex.runSample(sample)

		if ex.state != types.ExampleStatePassed {
			return
		}
	}
}

func (ex *example) runSample(sample int) (exampleState types.ExampleState, exampleFailure types.ExampleFailure) {
	exampleState = types.ExampleStatePassed
	exampleFailure = types.ExampleFailure{}
	innerMostContainerIndexToUnwind := 0

	defer func() {
		if len(ex.containers) > 0 {
			for i := innerMostContainerIndexToUnwind; i >= 0; i-- {
				container := ex.containers[i]
				for _, afterEach := range container.afterEachNodes {
					outcome, failure := afterEach.run()
					afterEachState, afterEachFailure := ex.processOutcomeAndFailure(i, types.ExampleComponentTypeAfterEach, afterEach.codeLocation, outcome, failure)
					if afterEachState != types.ExampleStatePassed && exampleState == types.ExampleStatePassed {
						exampleState = afterEachState
						exampleFailure = afterEachFailure
					}
				}
			}
		}
	}()

	for i, container := range ex.containers {
		innerMostContainerIndexToUnwind = i
		for _, beforeEach := range container.beforeEachNodes {
			outcome, failure := beforeEach.run()
			exampleState, exampleFailure = ex.processOutcomeAndFailure(i, types.ExampleComponentTypeBeforeEach, beforeEach.codeLocation, outcome, failure)
			if exampleState != types.ExampleStatePassed {
				return
			}
		}
	}

	for i, container := range ex.containers {
		for _, justBeforeEach := range container.justBeforeEachNodes {
			outcome, failure := justBeforeEach.run()
			exampleState, exampleFailure = ex.processOutcomeAndFailure(i, types.ExampleComponentTypeJustBeforeEach, justBeforeEach.codeLocation, outcome, failure)
			if exampleState != types.ExampleStatePassed {
				return
			}
		}
	}

	outcome, failure := ex.subject.run()
	exampleState, exampleFailure = ex.processOutcomeAndFailure(len(ex.containers), ex.subjectComponentType(), ex.subject.getCodeLocation(), outcome, failure)

	if exampleState != types.ExampleStatePassed {
		return
	}

	return
}

func (ex *example) processOutcomeAndFailure(containerIndex int, componentType types.ExampleComponentType, codeLocation types.CodeLocation, outcome runOutcome, failure failureData) (exampleState types.ExampleState, exampleFailure types.ExampleFailure) {
	exampleFailure = types.ExampleFailure{}
	exampleState = types.ExampleStatePassed

	if ex.didInterceptFailure {
		exampleState = types.ExampleStateFailed
		failure = ex.interceptedFailure
	} else if outcome == runOutcomePanicked {
		exampleState = types.ExampleStatePanicked
	} else if outcome == runOutcomeTimedOut {
		exampleState = types.ExampleStateTimedOut
	} else {
		return
	}

	exampleFailure = types.ExampleFailure{
		Message:               failure.message,
		Location:              failure.codeLocation,
		ForwardedPanic:        failure.forwardedPanic,
		ComponentIndex:        containerIndex,
		ComponentType:         componentType,
		ComponentCodeLocation: codeLocation,
	}

	return
}

func (ex *example) summary() *types.ExampleSummary {
	componentTexts := make([]string, len(ex.containers)+1)
	componentCodeLocations := make([]types.CodeLocation, len(ex.containers)+1)

	for i, container := range ex.containers {
		componentTexts[i] = container.text
		componentCodeLocations[i] = container.codeLocation
	}

	componentTexts[len(ex.containers)] = ex.subject.getText()
	componentCodeLocations[len(ex.containers)] = ex.subject.getCodeLocation()

	return &types.ExampleSummary{
		IsMeasurement:          ex.subjectComponentType() == types.ExampleComponentTypeMeasure,
		NumberOfSamples:        ex.desiredNumberOfSamples(),
		ComponentTexts:         componentTexts,
		ComponentCodeLocations: componentCodeLocations,
		State:        ex.state,
		RunTime:      ex.runTime,
		Failure:      ex.failure,
		Measurements: ex.measurementsReport(),
	}
}

func (ex *example) measurementsReport() (measurements map[string]*types.ExampleMeasurement) {
	if ex.subjectComponentType() != types.ExampleComponentTypeMeasure {
		return
	}
	if ex.failed() {
		return
	}

	return ex.subject.(*measureNode).measurementsReport()
}

func (ex *example) concatenatedString() string {
	s := ""
	for _, container := range ex.containers {
		s += container.text + " "
	}

	return s + ex.subject.getText()
}
<commit_msg>fix issue where nil was returned instead of an empty map<commit_after>package ginkgo

import (
	"github.com/onsi/ginkgo/types"
	"time"
)

type example struct {
	subject exampleSubject
	focused bool

	containers []*containerNode

	state               types.ExampleState
	runTime             time.Duration
	failure             types.ExampleFailure
	didInterceptFailure bool
	interceptedFailure  failureData
}

func newExample(subject exampleSubject) *example {
	ex := &example{
		subject: subject,
		focused: subject.getFlag() == flagTypeFocused,
	}

	if subject.getFlag() == flagTypePending {
		ex.state = types.ExampleStatePending
	}

	return ex
}

func (ex *example) addContainerNode(container *containerNode) {
	ex.containers = append([]*containerNode{container}, ex.containers...)
	if container.flag == flagTypeFocused {
		ex.focused = true
	} else if container.flag == flagTypePending {
		ex.state = types.ExampleStatePending
	}
}

func (ex *example) fail(failure failureData) {
	if !ex.didInterceptFailure {
		ex.interceptedFailure = failure
		ex.didInterceptFailure = true
	}
}

func (ex *example) skip() {
	ex.state = types.ExampleStateSkipped
}

func (ex *example) subjectComponentType() types.ExampleComponentType {
	if ex.subject.nodeType() == nodeTypeMeasure {
		return types.ExampleComponentTypeMeasure
	} else {
		return types.ExampleComponentTypeIt
	}
}

func (ex *example) desiredNumberOfSamples() int {
	if ex.subject.nodeType() == nodeTypeMeasure {
		return ex.subject.(*measureNode).samples
	}

	return 1
}

func (ex *example) failed() bool {
	return ex.state == types.ExampleStateFailed || ex.state == types.ExampleStatePanicked || ex.state == types.ExampleStateTimedOut
}

func (ex *example) skippedOrPending() bool {
	return ex.state == types.ExampleStateSkipped || ex.state == types.ExampleStatePending
}

func (ex *example) pending() bool {
	return ex.state == types.ExampleStatePending
}

func (ex *example) run() {
	startTime := time.Now()
	defer func() {
		ex.runTime = time.Since(startTime)
	}()

	for sample := 0; sample < ex.desiredNumberOfSamples(); sample++ {
		ex.state, ex.failure = ex.runSample(sample)

		if ex.state != types.ExampleStatePassed {
			return
		}
	}
}

func (ex *example) runSample(sample int) (exampleState types.ExampleState, exampleFailure types.ExampleFailure) {
	exampleState = types.ExampleStatePassed
	exampleFailure = types.ExampleFailure{}
	innerMostContainerIndexToUnwind := 0

	defer func() {
		if len(ex.containers) > 0 {
			for i := innerMostContainerIndexToUnwind; i >= 0; i-- {
				container := ex.containers[i]
				for _, afterEach := range container.afterEachNodes {
					outcome, failure := afterEach.run()
					afterEachState, afterEachFailure := ex.processOutcomeAndFailure(i, types.ExampleComponentTypeAfterEach, afterEach.codeLocation, outcome, failure)
					if afterEachState != types.ExampleStatePassed && exampleState == types.ExampleStatePassed {
						exampleState = afterEachState
						exampleFailure = afterEachFailure
					}
				}
			}
		}
	}()

	for i, container := range ex.containers {
		innerMostContainerIndexToUnwind = i
		for _, beforeEach := range container.beforeEachNodes {
			outcome, failure := beforeEach.run()
			exampleState, exampleFailure = ex.processOutcomeAndFailure(i, types.ExampleComponentTypeBeforeEach, beforeEach.codeLocation, outcome, failure)
			if exampleState != types.ExampleStatePassed {
				return
			}
		}
	}

	for i, container := range ex.containers {
		for _, justBeforeEach := range container.justBeforeEachNodes {
			outcome, failure := justBeforeEach.run()
			exampleState, exampleFailure = ex.processOutcomeAndFailure(i, types.ExampleComponentTypeJustBeforeEach, justBeforeEach.codeLocation, outcome, failure)
			if exampleState != types.ExampleStatePassed {
				return
			}
		}
	}

	outcome, failure := ex.subject.run()
	exampleState, exampleFailure = ex.processOutcomeAndFailure(len(ex.containers), ex.subjectComponentType(), ex.subject.getCodeLocation(), outcome, failure)

	if exampleState != types.ExampleStatePassed {
		return
	}

	return
}

func (ex *example) processOutcomeAndFailure(containerIndex int, componentType types.ExampleComponentType, codeLocation types.CodeLocation, outcome runOutcome, failure failureData) (exampleState types.ExampleState, exampleFailure types.ExampleFailure) {
	exampleFailure = types.ExampleFailure{}
	exampleState = types.ExampleStatePassed

	if ex.didInterceptFailure {
		exampleState = types.ExampleStateFailed
		failure = ex.interceptedFailure
	} else if outcome == runOutcomePanicked {
		exampleState = types.ExampleStatePanicked
	} else if outcome == runOutcomeTimedOut {
		exampleState = types.ExampleStateTimedOut
	} else {
		return
	}

	exampleFailure = types.ExampleFailure{
		Message:               failure.message,
		Location:              failure.codeLocation,
		ForwardedPanic:        failure.forwardedPanic,
		ComponentIndex:        containerIndex,
		ComponentType:         componentType,
		ComponentCodeLocation: codeLocation,
	}

	return
}

func (ex *example) summary() *types.ExampleSummary {
	componentTexts := make([]string, len(ex.containers)+1)
	componentCodeLocations := make([]types.CodeLocation, len(ex.containers)+1)

	for i, container := range ex.containers {
		componentTexts[i] = container.text
		componentCodeLocations[i] = container.codeLocation
	}

	componentTexts[len(ex.containers)] = ex.subject.getText()
	componentCodeLocations[len(ex.containers)] = ex.subject.getCodeLocation()

	return &types.ExampleSummary{
		IsMeasurement:          ex.subjectComponentType() == types.ExampleComponentTypeMeasure,
		NumberOfSamples:        ex.desiredNumberOfSamples(),
		ComponentTexts:         componentTexts,
		ComponentCodeLocations: componentCodeLocations,
		State:        ex.state,
		RunTime:      ex.runTime,
		Failure:      ex.failure,
		Measurements: ex.measurementsReport(),
	}
}

func (ex *example) measurementsReport() (measurements map[string]*types.ExampleMeasurement) {
	measurements = map[string]*types.ExampleMeasurement{}
	if ex.subjectComponentType() != types.ExampleComponentTypeMeasure {
		return
	}
	if ex.failed() {
		return
	}

	return ex.subject.(*measureNode).measurementsReport()
}

func (ex *example) concatenatedString() string {
	s := ""
	for _, container := range ex.containers {
		s += container.text + " "
	}

	return s + ex.subject.getText()
}
<|endoftext|>