<commit_before>package pretty

import (
	"fmt"
	"html/template"
	"io"
	"os"

	"github.com/docker/go-units"
	"github.com/pachyderm/pachyderm/src/client/pfs"
	"github.com/pachyderm/pachyderm/src/server/pkg/pretty"
)

// PrintRepoHeader prints a repo header.
func PrintRepoHeader(w io.Writer) {
	fmt.Fprint(w, "NAME\tCREATED\tSIZE\t\n")
}

// PrintRepoInfo pretty-prints repo info.
func PrintRepoInfo(w io.Writer, repoInfo *pfs.RepoInfo) {
	fmt.Fprintf(w, "%s\t", repoInfo.Repo.Name)
	fmt.Fprintf(
		w,
		"%s\t",
		pretty.Ago(repoInfo.Created),
	)
	fmt.Fprintf(w, "%s\t\n", units.BytesSize(float64(repoInfo.SizeBytes)))
}

// PrintDetailedRepoInfo pretty-prints detailed repo info.
func PrintDetailedRepoInfo(repoInfo *pfs.RepoInfo) error {
	template, err := template.New("RepoInfo").Funcs(funcMap).Parse(
		`Name: {{.Repo.Name}}{{if .Description}}
Description: {{.Description}}{{end}}
Created: {{prettyAgo .Created}}
Size: {{prettySize .SizeBytes}}{{if .Provenance}}
Provenance: {{range .Provenance}} {{.Name}} {{end}} {{end}}
`)
	if err != nil {
		return err
	}
	err = template.Execute(os.Stdout, repoInfo)
	if err != nil {
		return err
	}
	return nil
}

// PrintBranchHeader prints a branch header.
func PrintBranchHeader(w io.Writer) {
	fmt.Fprint(w, "BRANCH\tHEAD\t\n")
}

// PrintBranch pretty-prints a Branch.
func PrintBranch(w io.Writer, branch *pfs.BranchInfo) {
	fmt.Fprintf(w, "%s\t", branch.Name)
	fmt.Fprintf(w, "%s\t\n", branch.Head.ID)
}

// PrintCommitInfoHeader prints a commit info header.
func PrintCommitInfoHeader(w io.Writer) {
	fmt.Fprint(w, "REPO\tID\tPARENT\tSTARTED\tDURATION\tSIZE\t\n")
}

// PrintCommitInfo pretty-prints commit info.
func PrintCommitInfo(w io.Writer, commitInfo *pfs.CommitInfo) {
	fmt.Fprintf(w, "%s\t", commitInfo.Commit.Repo.Name)
	fmt.Fprintf(w, "%s\t", commitInfo.Commit.ID)
	if commitInfo.ParentCommit != nil {
		fmt.Fprintf(w, "%s\t", commitInfo.ParentCommit.ID)
	} else {
		fmt.Fprint(w, "<none>\t")
	}
	fmt.Fprintf(
		w,
		"%s\t",
		pretty.Ago(commitInfo.Started),
	)
	duration := "-\t"
	if commitInfo.Finished != nil {
		duration = fmt.Sprintf("%s\t", pretty.Duration(commitInfo.Started, commitInfo.Finished))
	}
	fmt.Fprintf(w, duration)
	fmt.Fprintf(w, "%s\t\n", units.BytesSize(float64(commitInfo.SizeBytes)))
}

// PrintDetailedCommitInfo pretty-prints detailed commit info.
func PrintDetailedCommitInfo(commitInfo *pfs.CommitInfo) error {
	template, err := template.New("CommitInfo").Funcs(funcMap).Parse(
		`Commit: {{.Commit.Repo.Name}}/{{.Commit.ID}}{{if .ParentCommit}}
Parent: {{.ParentCommit.ID}} {{end}}
Started: {{prettyAgo .Started}}{{if .Finished}}
Finished: {{prettyAgo .Finished}} {{end}}
Size: {{prettySize .SizeBytes}}{{if .Provenance}}
Provenance: {{range .Provenance}} {{.Repo.Name}}/{{.ID}} {{end}} {{end}}
`)
	if err != nil {
		return err
	}
	err = template.Execute(os.Stdout, commitInfo)
	if err != nil {
		return err
	}
	return nil
}

// PrintFileInfoHeader prints a file info header.
func PrintFileInfoHeader(w io.Writer) {
	fmt.Fprint(w, "NAME\tTYPE\tSIZE\t\n")
}

// PrintFileInfo pretty-prints file info.
// If recurse is false and directory size is 0, display "-" instead
// If fast is true and file size is 0, display "-" instead
func PrintFileInfo(w io.Writer, fileInfo *pfs.FileInfo) {
	fmt.Fprintf(w, "%s\t", fileInfo.File.Path)
	if fileInfo.FileType == pfs.FileType_FILE {
		fmt.Fprint(w, "file\t")
	} else {
		fmt.Fprint(w, "dir\t")
	}
	fmt.Fprintf(w, "%s\t\n", units.BytesSize(float64(fileInfo.SizeBytes)))
}

// PrintDetailedFileInfo pretty-prints detailed file info.
func PrintDetailedFileInfo(fileInfo *pfs.FileInfo) error {
	template, err := template.New("FileInfo").Funcs(funcMap).Parse(
		`Path: {{.File.Path}}
Type: {{fileType .FileType}}
Size: {{prettySize .SizeBytes}}
Children: {{range .Children}} {{.}} {{end}}
`)
	if err != nil {
		return err
	}
	if err := template.Execute(os.Stdout, fileInfo); err != nil {
		return err
	}
	return nil
}

type uint64Slice []uint64

func (s uint64Slice) Len() int           { return len(s) }
func (s uint64Slice) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
func (s uint64Slice) Less(i, j int) bool { return s[i] < s[j] }

func fileType(fileType pfs.FileType) string {
	if fileType == pfs.FileType_FILE {
		return "file"
	}
	return "dir"
}

var funcMap = template.FuncMap{
	"prettyAgo":  pretty.Ago,
	"prettySize": pretty.Size,
	"fileType":   fileType,
}
<commit_msg>Don't display commit size if a commit is open<commit_after>package pretty

import (
	"fmt"
	"html/template"
	"io"
	"os"

	"github.com/docker/go-units"
	"github.com/pachyderm/pachyderm/src/client/pfs"
	"github.com/pachyderm/pachyderm/src/server/pkg/pretty"
)

// PrintRepoHeader prints a repo header.
func PrintRepoHeader(w io.Writer) {
	fmt.Fprint(w, "NAME\tCREATED\tSIZE\t\n")
}

// PrintRepoInfo pretty-prints repo info.
func PrintRepoInfo(w io.Writer, repoInfo *pfs.RepoInfo) {
	fmt.Fprintf(w, "%s\t", repoInfo.Repo.Name)
	fmt.Fprintf(
		w,
		"%s\t",
		pretty.Ago(repoInfo.Created),
	)
	fmt.Fprintf(w, "%s\t\n", units.BytesSize(float64(repoInfo.SizeBytes)))
}

// PrintDetailedRepoInfo pretty-prints detailed repo info.
func PrintDetailedRepoInfo(repoInfo *pfs.RepoInfo) error {
	template, err := template.New("RepoInfo").Funcs(funcMap).Parse(
		`Name: {{.Repo.Name}}{{if .Description}}
Description: {{.Description}}{{end}}
Created: {{prettyAgo .Created}}
Size: {{prettySize .SizeBytes}}{{if .Provenance}}
Provenance: {{range .Provenance}} {{.Name}} {{end}} {{end}}
`)
	if err != nil {
		return err
	}
	err = template.Execute(os.Stdout, repoInfo)
	if err != nil {
		return err
	}
	return nil
}

// PrintBranchHeader prints a branch header.
func PrintBranchHeader(w io.Writer) {
	fmt.Fprint(w, "BRANCH\tHEAD\t\n")
}

// PrintBranch pretty-prints a Branch.
func PrintBranch(w io.Writer, branch *pfs.BranchInfo) {
	fmt.Fprintf(w, "%s\t", branch.Name)
	fmt.Fprintf(w, "%s\t\n", branch.Head.ID)
}

// PrintCommitInfoHeader prints a commit info header.
func PrintCommitInfoHeader(w io.Writer) {
	fmt.Fprint(w, "REPO\tID\tPARENT\tSTARTED\tDURATION\tSIZE\t\n")
}

// PrintCommitInfo pretty-prints commit info.
func PrintCommitInfo(w io.Writer, commitInfo *pfs.CommitInfo) {
	fmt.Fprintf(w, "%s\t", commitInfo.Commit.Repo.Name)
	fmt.Fprintf(w, "%s\t", commitInfo.Commit.ID)
	if commitInfo.ParentCommit != nil {
		fmt.Fprintf(w, "%s\t", commitInfo.ParentCommit.ID)
	} else {
		fmt.Fprint(w, "<none>\t")
	}
	fmt.Fprintf(
		w,
		"%s\t",
		pretty.Ago(commitInfo.Started),
	)
	if commitInfo.Finished != nil {
		fmt.Fprintf(w, fmt.Sprintf("%s\t", pretty.Duration(commitInfo.Started, commitInfo.Finished)))
		fmt.Fprintf(w, "%s\t\n", units.BytesSize(float64(commitInfo.SizeBytes)))
	} else {
		fmt.Fprintf(w, "-\t")
		// Open commits don't have meaningful size information
		fmt.Fprintf(w, "-\t\n")
	}
}

// PrintDetailedCommitInfo pretty-prints detailed commit info.
func PrintDetailedCommitInfo(commitInfo *pfs.CommitInfo) error {
	template, err := template.New("CommitInfo").Funcs(funcMap).Parse(
		`Commit: {{.Commit.Repo.Name}}/{{.Commit.ID}}{{if .ParentCommit}}
Parent: {{.ParentCommit.ID}} {{end}}
Started: {{prettyAgo .Started}}{{if .Finished}}
Finished: {{prettyAgo .Finished}} {{end}}
Size: {{prettySize .SizeBytes}}{{if .Provenance}}
Provenance: {{range .Provenance}} {{.Repo.Name}}/{{.ID}} {{end}} {{end}}
`)
	if err != nil {
		return err
	}
	err = template.Execute(os.Stdout, commitInfo)
	if err != nil {
		return err
	}
	return nil
}

// PrintFileInfoHeader prints a file info header.
func PrintFileInfoHeader(w io.Writer) {
	fmt.Fprint(w, "NAME\tTYPE\tSIZE\t\n")
}

// PrintFileInfo pretty-prints file info.
// If recurse is false and directory size is 0, display "-" instead
// If fast is true and file size is 0, display "-" instead
func PrintFileInfo(w io.Writer, fileInfo *pfs.FileInfo) {
	fmt.Fprintf(w, "%s\t", fileInfo.File.Path)
	if fileInfo.FileType == pfs.FileType_FILE {
		fmt.Fprint(w, "file\t")
	} else {
		fmt.Fprint(w, "dir\t")
	}
	fmt.Fprintf(w, "%s\t\n", units.BytesSize(float64(fileInfo.SizeBytes)))
}

// PrintDetailedFileInfo pretty-prints detailed file info.
func PrintDetailedFileInfo(fileInfo *pfs.FileInfo) error {
	template, err := template.New("FileInfo").Funcs(funcMap).Parse(
		`Path: {{.File.Path}}
Type: {{fileType .FileType}}
Size: {{prettySize .SizeBytes}}
Children: {{range .Children}} {{.}} {{end}}
`)
	if err != nil {
		return err
	}
	if err := template.Execute(os.Stdout, fileInfo); err != nil {
		return err
	}
	return nil
}

type uint64Slice []uint64

func (s uint64Slice) Len() int           { return len(s) }
func (s uint64Slice) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
func (s uint64Slice) Less(i, j int) bool { return s[i] < s[j] }

func fileType(fileType pfs.FileType) string {
	if fileType == pfs.FileType_FILE {
		return "file"
	}
	return "dir"
}

var funcMap = template.FuncMap{
	"prettyAgo":  pretty.Ago,
	"prettySize": pretty.Size,
	"fileType":   fileType,
}
<|endoftext|>


<commit_before>// since.go

package main

import (
	"flag"
	"fmt"
	jwalk "github.com/MichaelTJones/walk"
	// "github.com/whosonfirst/walk"  Not designed for windows, and I doesn't do what I want, so I'll delete it.
	"log"
	"os"
	"path/filepath"
	"runtime"
	"sort"
	"strings"
	"sync"
	"time"
)

/*
   REVISION HISTORY
   -------- -------
   21 Oct 2018 -- First started playing w/ MichaelTJones' code.  I added a help flag
   21 Oct 2022 -- In the code again, after running golangci-lint.  Changed how help flag contents is output.  If an absolute time is given, use that, else use duration.
   26 Oct 2022 -- Added '~' processing.  And output timing info.
   28 Oct 2022 -- On linux this takes an hour to run when I invoke it using my home directory.  I'm looking into why.  I think because it's following a symlink to bigbkupG.
                  Naw, it's also following symlinks to DSM.
                  I posted on golang-nuts for help.  I'm adding the DevID that was recommended, and removing multiple start directories as the pre-processing was complex to work out.
   29 Oct 2022 -- jwalk doesn't work, as it exits too early.  filepath/walk takes ~2 min here on leox.  I'm adding a wait group, and now it works, taking ~7 sec on leox.
                  I'll leave in the done channel, as a model of something that's supposed to work but doesn't.  At least for now.
                  Turns out that the syscall used by GetDeviceID won't compile on Windows, so I have to use platform specific code for it.  I'll do that now.
*/

var LastAlteredDate = "Oct 29, 2022"

//var duration = flag.String("d", "", "find files modified within DURATION")
var duration = flag.Duration("dur", 10*time.Minute, "find files modified within this duration")
var format = flag.String("f", "2006-01-02 03:04:05", "time format")
var instant = flag.String("t", "", "find files modified since TIME")
var quiet = flag.Bool("q", false, "do not print filenames")
var verbose = flag.Bool("v", false, "print summary statistics")
var days = flag.Int("d", 0, "days duration")
var weeks = flag.Int("w", 0, "weeks duration")
var wg sync.WaitGroup

type devID uint64

func main() {

	runtime.GOMAXPROCS(runtime.NumCPU())

	execName, _ := os.Executable()
	ExecFI, _ := os.Stat(execName)
	ExecTimeStamp := ExecFI.ModTime().Format("Mon Jan-2-2006_15:04:05 MST")

	flag.Usage = func() {
		fmt.Fprintf(flag.CommandLine.Output(), " %s last modified %s, compiled with %s, last linked %s.\n", os.Args[0], LastAlteredDate, runtime.Version(), ExecTimeStamp)
		fmt.Fprintf(flag.CommandLine.Output(), " Usage: since <options> <start-dir-list> \n")
		fmt.Fprintf(flag.CommandLine.Output(), " Valid time units for duration are ns, us, ms, s, m, h. \n")
		fmt.Fprintf(flag.CommandLine.Output(), " since -d 5m -- show all files changed within last 5 minutes starting at current directory \n")
		fmt.Fprintf(flag.CommandLine.Output(), " since -d 5m $HOME or %%userprofile -- show all files changed within last 5 minutes starting at home directory \n")
		flag.PrintDefaults()
	}
	flag.Parse()

	fmt.Printf(" since written in Go.  LastAltered %s, compiled with %s, binary timestamp is %s.\n", LastAlteredDate, runtime.Version(), ExecTimeStamp)

	now := time.Now()
	when := now
	switch {
	case *instant != "":
		t, err := time.Parse(*format, *instant)
		if err != nil {
			fmt.Printf("error parsing time %q, %s\n", *instant, err)
			os.Exit(1)
		}
		when = t
	default:
		//d, err := time.ParseDuration(*duration)
		//if err != nil {
		//	fmt.Printf("error parsing duration %q, %s\n", *duration, err)
		//	os.Exit(2)
		//}
		*duration = *duration + time.Duration(*weeks)*7*24*time.Hour + time.Duration(*days)*24*time.Hour
		when = now.Add(-*duration) // subtract duration from now.
	}

	home, err := os.UserHomeDir()
	if err != nil {
		fmt.Fprintf(os.Stderr, " Error from UserHomeDir is %v.\n", err)
	}

	if *verbose {
		fmt.Printf(" weeks = %d, days = %d, duration = %s\n", *weeks, *days, *duration)
		fmt.Printf(" when = %s, home directory is %s\n", when, home)
	}

	// goroutine to collect names of recently-modified files
	var result []string
	done := make(chan bool)
	results := make(chan string, 1024)
	go func() {
		for r := range results {
			result = append(result, r)
		}
		sort.Strings(result) // simulate ordered traversal
		done <- true
	}()

	// parallel walker and walk to find recently-modified files
	var lock sync.Mutex
	var tFiles, tBytes int // total files and bytes
	var rFiles, rBytes int // recent files and bytes
	var rootDeviceID devID
	var dir string

	if len(flag.Args()) < 1 {
		dir, err = os.Getwd()
		if err != nil {
			log.Fatalln(" error from Getwd is", err)
		}
	} else {
		dir = flag.Arg(0) // will only use the first argument, which is all I use anyway.
		dir = strings.Replace(dir, "~", home, 1)
	}
	fi, er := os.Stat(dir)
	if er != nil {
		log.Fatalf(" error from os.Stat(%s) is %v\n", dir, er)
	}
	rootDeviceID = getDeviceID(dir, fi)

	sizeVisitor := func(path string, info os.FileInfo, err error) error { // I'm ignoring any tests on err, as I don't want to abort on trivial errors.
		wg.Add(1)
		defer wg.Done()
		//if err == nil {  turns out that I didn't really want to test against err.  But here it makes no difference that I can find.
		lock.Lock()
		tFiles += 1
		tBytes += int(info.Size())
		lock.Unlock()

		if info.IsDir() {
			if filepath.Ext(path) == ".git" || strings.Contains(path, "vmware") || strings.Contains(path, ".cache") { // adding extra skipDir's saved from 13 min -> 9 sec runtime.
				if *verbose {
					fmt.Printf(" skipping %s.\n", path)
				}
				return filepath.SkipDir
			} else if isSymlink(info.Mode()) { // skip all symlinked directories.  I intend this to catch bigbkupG and DSM.
				if *verbose {
					fmt.Printf(" skipping symlink %s\n", path)
				}
				return filepath.SkipDir
			} else {
				id := getDeviceID(path, info)
				if rootDeviceID != id {
					if *verbose {
						fmt.Printf(" root device id is %d for %q, path device id is %d for %q.  Skipping %s.\n", rootDeviceID, dir, id, path, path)
					}
					return filepath.SkipDir
				}
			}
		}

		if info.ModTime().After(when) {
			lock.Lock()
			rFiles += 1
			rBytes += int(info.Size())
			lock.Unlock()

			if !*quiet {
				// fmt.Printf("%s %s\n", info.ModTime(), path) // simple
				results <- path // allows sorting into "normal" order
			}
		}
		//}
		return nil
	}

	if *quiet { // just so compiler sees this can potentially still be executed.
		err = jwalk.Walk(dir, sizeVisitor) // at least this compiles on Windows.  It doesn't work, but it does compile.
		// err = walk.Walk(dir, sizeVisitor) // a fork of jwalk w/ some needed changes.  But it doesn't work, either.  It's not even designed to compile on Windows.
	} else {
		err = filepath.Walk(dir, sizeVisitor)
	}

	if err != nil {
		log.Printf(" error from walk.Walk is %v\n", err)
	}

	// wait for traversal results and print
	close(results) // no more results
	<-done         // wait for final results and sorting
	wg.Wait()
	𝛥t := float64(time.Since(now)) / 1e9

	for _, r := range result {
		fmt.Printf("%s\n", r)
	}

	fmt.Printf(" since ran for %s\n", time.Since(now))

	// print optional verbose summary report
	if *verbose {
		log.Printf("     total: %8d files (%7.2f%%), %13d bytes (%7.2f%%)\n",
			tFiles, 100.0, tBytes, 100.0)

		rfp := 100 * float64(rFiles) / float64(tFiles)
		rbp := 100 * float64(rBytes) / float64(tBytes)
		log.Printf("    recent: %8d files (%7.2f%%), %13d bytes (%7.2f%%) in %.4f seconds\n",
			rFiles, rfp, rBytes, rbp, 𝛥t)
	}
}

func isSymlink(fm os.FileMode) bool {
	intermed := fm & os.ModeSymlink
	return intermed != 0
}
<commit_msg>10/30/2022 08:14:41 PM since/since.go<commit_after>// since.go

package main

import (
	"flag"
	"fmt"
	jwalk "github.com/MichaelTJones/walk"
	// "github.com/whosonfirst/walk"  Not designed for windows, and I doesn't do what I want, so I'll delete it.
	"log"
	"os"
	"path/filepath"
	"runtime"
	"sort"
	"strings"
	"sync"
	"time"
)

/*
   REVISION HISTORY
   -------- -------
   21 Oct 2018 -- First started playing w/ MichaelTJones' code.  I added a help flag
   21 Oct 2022 -- In the code again, after running golangci-lint.  Changed how help flag contents is output.  If an absolute time is given, use that, else use duration.
   26 Oct 2022 -- Added '~' processing.  And output timing info.
   28 Oct 2022 -- On linux this takes an hour to run when I invoke it using my home directory.  I'm looking into why.  I think because it's following a symlink to bigbkupG.
                  Naw, it's also following symlinks to DSM.
                  I posted on golang-nuts for help.  I'm adding the DevID that was recommended, and removing multiple start directories as the pre-processing was complex to work out.
   29 Oct 2022 -- jwalk doesn't work, as it exits too early.  filepath/walk takes ~2 min here on leox.  I'm adding a wait group, and now it works, taking ~7 sec on leox.
                  I'll leave in the done channel, as a model of something that's supposed to work but doesn't.  At least for now.
                  Turns out that the syscall used by GetDeviceID won't compile on Windows, so I have to use platform specific code for it.  I'll do that now.
*/

var LastAlteredDate = "Oct 30, 2022"

//var duration = flag.String("d", "", "find files modified within DURATION")
var duration = flag.Duration("dur", 10*time.Minute, "find files modified within this duration")
var format = flag.String("f", "2006-01-02 03:04:05", "time format")
var instant = flag.String("t", "", "find files modified since TIME")
var quiet = flag.Bool("q", false, "do not print filenames")
var verbose = flag.Bool("v", false, "print summary statistics")
var days = flag.Int("d", 0, "days duration")
var weeks = flag.Int("w", 0, "weeks duration")
var wg sync.WaitGroup

type devID uint64

func main() {

	runtime.GOMAXPROCS(runtime.NumCPU())

	execName, _ := os.Executable()
	ExecFI, _ := os.Stat(execName)
	ExecTimeStamp := ExecFI.ModTime().Format("Mon Jan-2-2006_15:04:05 MST")

	flag.Usage = func() {
		fmt.Fprintf(flag.CommandLine.Output(), " %s last modified %s, compiled with %s, last linked %s.\n", os.Args[0], LastAlteredDate, runtime.Version(), ExecTimeStamp)
		fmt.Fprintf(flag.CommandLine.Output(), " Usage: since <options> <start-dir-list> \n")
		fmt.Fprintf(flag.CommandLine.Output(), " Valid time units for duration are ns, us, ms, s, m, h. \n")
		fmt.Fprintf(flag.CommandLine.Output(), " since -d 5m -- show all files changed within last 5 minutes starting at current directory \n")
		fmt.Fprintf(flag.CommandLine.Output(), " since -d 5m $HOME or %%userprofile -- show all files changed within last 5 minutes starting at home directory \n")
		flag.PrintDefaults()
	}
	flag.Parse()

	fmt.Printf(" since written in Go.  LastAltered %s, compiled with %s, binary timestamp is %s.\n", LastAlteredDate, runtime.Version(), ExecTimeStamp)

	now := time.Now()
	when := now
	switch {
	case *instant != "":
		t, err := time.Parse(*format, *instant)
		if err != nil {
			fmt.Printf("error parsing time %q, %s\n", *instant, err)
			os.Exit(1)
		}
		when = t
	default:
		//d, err := time.ParseDuration(*duration)
		//if err != nil {
		//	fmt.Printf("error parsing duration %q, %s\n", *duration, err)
		//	os.Exit(2)
		//}
		*duration = *duration + time.Duration(*weeks)*7*24*time.Hour + time.Duration(*days)*24*time.Hour
		when = now.Add(-*duration) // subtract duration from now.
	}

	home, err := os.UserHomeDir()
	if err != nil {
		fmt.Fprintf(os.Stderr, " Error from UserHomeDir is %v.\n", err)
	}

	if *verbose {
		fmt.Printf(" weeks = %d, days = %d, duration = %s\n", *weeks, *days, *duration)
		fmt.Printf(" when = %s, home directory is %s\n", when, home)
	}

	// goroutine to collect names of recently-modified files
	var result []string
	done := make(chan bool)
	results := make(chan string, 1024)
	go func() {
		for r := range results {
			result = append(result, r)
		}
		sort.Strings(result) // simulate ordered traversal
		done <- true
	}()

	// parallel walker and walk to find recently-modified files
	var lock sync.Mutex
	var tFiles, tBytes int // total files and bytes
	var rFiles, rBytes int // recent files and bytes
	var rootDeviceID devID
	var dir string

	if len(flag.Args()) < 1 {
		dir, err = os.Getwd()
		if err != nil {
			log.Fatalln(" error from Getwd is", err)
		}
	} else {
		dir = flag.Arg(0) // will only use the first argument, which is all I use anyway.
		dir = strings.Replace(dir, "~", home, 1)
	}
	fi, er := os.Stat(dir)
	if er != nil {
		log.Fatalf(" error from os.Stat(%s) is %v\n", dir, er)
	}
	rootDeviceID = getDeviceID(dir, fi)

	sizeVisitor := func(path string, info os.FileInfo, err error) error { // I'm ignoring any tests on err, as I don't want to abort on trivial errors.
		wg.Add(1)
		defer wg.Done()
		//if err == nil {  turns out that I didn't really want to test against err.  But here it makes no difference that I can find.
		lock.Lock()
		tFiles += 1
		tBytes += int(info.Size())
		lock.Unlock()

		if info.IsDir() {
			if filepath.Ext(path) == ".git" || strings.Contains(path, "vmware") || strings.Contains(path, ".cache") { // adding extra skipDir's saved from 13 min -> 9 sec runtime.
				if *verbose {
					fmt.Printf(" skipping %s.\n", path)
				}
				return filepath.SkipDir
			} else if isSymlink(info.Mode()) { // skip all symlinked directories.  I intend this to catch bigbkupG and DSM.
				if *verbose {
					fmt.Printf(" skipping symlink %s\n", path)
				}
				return filepath.SkipDir
			} else {
				id := getDeviceID(path, info)
				if rootDeviceID != id {
					if *verbose {
						fmt.Printf(" root device id is %d for %q, path device id is %d for %q.  Skipping %s.\n", rootDeviceID, dir, id, path, path)
					}
					return filepath.SkipDir
				}
			}
		}

		if info.ModTime().After(when) {
			lock.Lock()
			rFiles += 1
			rBytes += int(info.Size())
			lock.Unlock()

			if !*quiet {
				// fmt.Printf("%s %s\n", info.ModTime(), path) // simple
				results <- path // allows sorting into "normal" order
			}
		}
		//}
		return nil
	}

	if *quiet { // just so compiler sees this can potentially still be executed.
		err = jwalk.Walk(dir, sizeVisitor) // at least this compiles on Windows.  It doesn't work, but it does compile.
		// err = walk.Walk(dir, sizeVisitor) // a fork of jwalk w/ some needed changes.  But it doesn't work, either.  It's not even designed to compile on Windows.
	} else {
		err = filepath.Walk(dir, sizeVisitor)
	}

	if err != nil {
		log.Printf(" error from walk.Walk is %v\n", err)
	}

	// wait for traversal results and print
	close(results) // no more results
	<-done         // wait for final results and sorting
	wg.Wait()
	𝛥t := float64(time.Since(now)) / 1e9

	for _, r := range result {
		fmt.Printf("%s\n", r)
	}

	fmt.Printf(" since ran for %s\n", time.Since(now))

	// print optional verbose summary report
	if *verbose {
		log.Printf("     total: %8d files (%7.2f%%), %13d bytes (%7.2f%%)\n",
			tFiles, 100.0, tBytes, 100.0)

		rfp := 100 * float64(rFiles) / float64(tFiles)
		rbp := 100 * float64(rBytes) / float64(tBytes)
		log.Printf("    recent: %8d files (%7.2f%%), %13d bytes (%7.2f%%) in %.4f seconds\n",
			rFiles, rfp, rBytes, rbp, 𝛥t)
	}
}

func isSymlink(fm os.FileMode) bool {
	intermed := fm & os.ModeSymlink
	return intermed != 0
}
<|endoftext|>


<commit_before>package bowling

import "testing"

func TestGutterGame(t *testing.T) {
	game := new(Game)

	for i := 0; i < 20; i++ {
		game.Roll(0)
	}

	score := game.Score()

	if score != 0 {
		t.Error("Gutter game:", "Expected", 0, "was", score)
	}
}

func TestAllOnes(t *testing.T) {
	game := new(Game)

	for i := 0; i < 20; i++ {
		game.Roll(1)
	}

	score := game.Score()

	if score != 20 {
		t.Error("All ones:", "Expected", 20, "was", score)
	}
}
<commit_msg>Refactor test to provide `RollMany` function<commit_after>package bowling

import "testing"

func (g *Game) RollMany(runs int, pins int) {
	for i := 0; i < runs; i++ {
		g.Roll(pins)
	}
}

func TestGutterGame(t *testing.T) {
	game := new(Game)
	game.RollMany(20, 0)
	score := game.Score()

	if score != 0 {
		t.Error("Gutter game:", "Expected", 0, "was", score)
	}
}

func TestAllOnes(t *testing.T) {
	game := new(Game)
	game.RollMany(20, 1)
	score := game.Score()

	if score != 20 {
		t.Error("All ones:", "Expected", 20, "was", score)
	}
}
<|endoftext|>


<commit_before>/**********************************************************\
|                                                          |
|                          hprose                          |
|                                                          |
| Official WebSite: http://www.hprose.com/                 |
|                   http://www.hprose.org/                 |
|                                                          |
\**********************************************************/
/**********************************************************\
 *                                                        *
 * io/serializer.go                                       *
 *                                                        *
 * hprose seriaizer for Go.                               *
 *                                                        *
 * LastModified: Aug 15, 2016                             *
 * Author: Ma Bingyao <andot@hprose.com>                  *
 *                                                        *
\**********************************************************/

package io

import (
	"math"

	"github.com/hprose/hprose-golang/util"
)

// Serializer is a interface for serializing build-in type
type Serializer interface {
	Serialize(writer *Writer, v interface{}) error
}

type refSerializer struct {
	value Serializer
}

func (s refSerializer) Serialize(writer *Writer, v interface{}) error {
	if ok, err := writer.WriteRef(v); ok || err != nil {
		return err
	}
	return s.value.Serialize(writer, v)
}

type invalidSerializer struct{}

func (invalidSerializer) Serialize(writer *Writer, v interface{}) (err error) {
	_, err = writer.Stream.Write([]byte{TagNull})
	return err
}

type boolSerializer struct{}

func (boolSerializer) Serialize(writer *Writer, v interface{}) (err error) {
	var tag byte
	if v.(bool) {
		tag = TagTrue
	} else {
		tag = TagFalse
	}
	_, err = writer.Stream.Write([]byte{tag})
	return err
}

type intSerializer struct{}

func (intSerializer) Serializer(writer *Writer, v interface{}) (err error) {
	s := writer.Stream
	i := v.(int)
	if (i >= 0) && (i <= 9) {
		_, err = s.Write([]byte{byte('0' + i)})
		return err
	}
	if (i >= math.MinInt32) && (i <= math.MaxInt32) {
		_, err = s.Write([]byte{TagInteger})
	} else {
		_, err = s.Write([]byte{TagLong})
	}
	if err == nil {
		if _, err = s.Write(util.GetInt64Bytes(int64(i))); err == nil {
			_, err = s.Write([]byte{TagSemicolon})
		}
	}
	return err
}
<commit_msg>Update intSerializer<commit_after>/**********************************************************\
|                                                          |
|                          hprose                          |
|                                                          |
| Official WebSite: http://www.hprose.com/                 |
|                   http://www.hprose.org/                 |
|                                                          |
\**********************************************************/
/**********************************************************\
 *                                                        *
 * io/serializer.go                                       *
 *                                                        *
 * hprose seriaizer for Go.                               *
 *                                                        *
 * LastModified: Aug 15, 2016                             *
 * Author: Ma Bingyao <andot@hprose.com>                  *
 *                                                        *
\**********************************************************/

package io

import (
	"math"

	"github.com/hprose/hprose-golang/util"
)

// Serializer is a interface for serializing build-in type
type Serializer interface {
	Serialize(writer *Writer, v interface{}) error
}

type refSerializer struct {
	value Serializer
}

func (s refSerializer) Serialize(writer *Writer, v interface{}) error {
	if ok, err := writer.WriteRef(v); ok || err != nil {
		return err
	}
	return s.value.Serialize(writer, v)
}

type invalidSerializer struct{}

func (invalidSerializer) Serialize(writer *Writer, v interface{}) (err error) {
	_, err = writer.Stream.Write([]byte{TagNull})
	return err
}

type boolSerializer struct{}

func (boolSerializer) Serialize(writer *Writer, v interface{}) (err error) {
	var tag byte
	if v.(bool) {
		tag = TagTrue
	} else {
		tag = TagFalse
	}
	_, err = writer.Stream.Write([]byte{tag})
	return err
}

type intSerializer struct{}

func (intSerializer) Serializer(writer *Writer, v interface{}) (err error) {
	s := writer.Stream
	i := v.(int)
	if (i >= 0) && (i <= 9) {
		_, err = s.Write([]byte{byte('0' + i)})
		return err
	}
	if (i >= math.MinInt32) && (i <= math.MaxInt32) {
		_, err = s.Write([]byte{TagInteger})
	} else {
		_, err = s.Write([]byte{TagLong})
	}
	if err != nil {
		return err
	}
	if _, err = s.Write(util.GetInt64Bytes(int64(i))); err != nil {
		return err
	}
	_, err = s.Write([]byte{TagSemicolon})
	return err
}
<|endoftext|>


<commit_before>package event

import (
	"encoding/json"
	"time"

	"github.com/raintank/raintank-apps/task-server/model"
)

type TaskCreated struct {
	Ts      time.Time
	Payload *model.TaskDTO
}

func (a *TaskCreated) Type() string {
	return "task.created"
}

func (a *TaskCreated) Timestamp() time.Time {
	return a.Ts
}

func (a *TaskCreated) Body() ([]byte, error) {
	return json.Marshal(a.Payload)
}

type TaskDeleted struct {
	Ts      time.Time
	Payload *model.TaskDTO
}

func (a *TaskDeleted) Type() string {
	return "task.deleted"
}

func (a *TaskDeleted) Timestamp() time.Time {
	return a.Ts
}

func (a *TaskDeleted) Body() ([]byte, error) {
	return json.Marshal(a.Payload)
}

type TaskUpdated struct {
	Ts      time.Time
	Payload struct {
		Old *model.TaskDTO `json:"old"`
		New *model.TaskDTO `json:"new"`
	}
}

func (a *TaskUpdated) Type() string {
	return "task.updated"
}

func (a *TaskUpdated) Timestamp() time.Time {
	return a.Ts
}

func (a *TaskUpdated) Body() ([]byte, error) {
	return json.Marshal(a.Payload)
}
<commit_msg>Update schema of taskUpdated events<commit_after>package event

import (
	"encoding/json"
	"time"

	"github.com/raintank/raintank-apps/task-server/model"
)

type TaskCreated struct {
	Ts      time.Time
	Payload *model.TaskDTO
}

func (a *TaskCreated) Type() string {
	return "task.created"
}

func (a *TaskCreated) Timestamp() time.Time {
	return a.Ts
}

func (a *TaskCreated) Body() ([]byte, error) {
	return json.Marshal(a.Payload)
}

type TaskDeleted struct {
	Ts      time.Time
	Payload *model.TaskDTO
}

func (a *TaskDeleted) Type() string {
	return "task.deleted"
}

func (a *TaskDeleted) Timestamp() time.Time {
	return a.Ts
}

func (a *TaskDeleted) Body() ([]byte, error) {
	return json.Marshal(a.Payload)
}

type TaskUpdated struct {
	Ts      time.Time
	Payload struct {
		Last    *model.TaskDTO `json:"old"`
		Current *model.TaskDTO `json:"new"`
	}
}

func (a *TaskUpdated) Type() string {
	return "task.updated"
}

func (a *TaskUpdated) Timestamp() time.Time {
	return a.Ts
}

func (a *TaskUpdated) Body() ([]byte, error) {
	return json.Marshal(a.Payload)
}
<|endoftext|>


<commit_before>package phraseapp

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"strconv"
	"strings"

	"os"

	"github.com/bgentry/speakeasy"
)

var Debug bool

func EnableDebug() {
	Debug = true
}

type DefaultParams Action
type Action map[string]map[string]interface{}

type Client struct {
	http.Client
	Credentials *Credentials
}

type Credentials struct {
	Username string `cli:"opt --username -u desc='username used for authentication'"`
	Token    string `cli:"opt --access-token -t desc='access token used for authentication'"`
	TFA      bool   `cli:"opt --tfa desc='use Two-Factor Authentication'"`
	Host     string `cli:"opt --host desc='Host to send Request to'"`
	Debug    bool   `cli:"opt --verbose -v desc='Verbose output'"`
}

func NewClient(credentials Credentials, defaultCredentials *Credentials) (*Client, error) {
	client := &Client{Credentials: &Credentials{}}

	envToken := os.Getenv("PHRASEAPP_ACCESS_TOKEN")

	if credentials.Token != "" && client.Credentials.Token == "" && client.Credentials.Username == "" {
		client.Credentials.Token = credentials.Token
	} else if credentials.Username != "" && client.Credentials.Username == "" {
		client.Credentials.Username = credentials.Username
	} else if envToken != "" && credentials.Token == "" && credentials.Username == "" && client.Credentials.Username == "" {
		client.Credentials.Token = envToken
	}

	if credentials.TFA {
		client.Credentials.TFA = credentials.TFA
	}

	if credentials.Debug == true || ((defaultCredentials != nil) && defaultCredentials.Debug == true) {
		EnableDebug()
	}

	if credentials.Host != "" {
		client.Credentials.Host = credentials.Host
	} else {
		if defaultCredentials != nil && defaultCredentials.Host != "" {
			client.Credentials.Host = defaultCredentials.Host
		}
	}

	if client.Credentials.Host == "" {
		client.Credentials.Host = "https://api.phraseapp.com"
	}

	notSet := client.Credentials.Token == "" && client.Credentials.Username == ""
	if notSet && defaultCredentials != nil && defaultCredentials.Token != "" {
		client.Credentials.Token = defaultCredentials.Token
	}
	if notSet && defaultCredentials != nil && defaultCredentials.Username != "" {
		client.Credentials.Username = defaultCredentials.Username
	}

	return client, nil
}

func (client *Client) authenticate(req *http.Request) error {
	if client.Credentials == nil {
		return fmt.Errorf("no auth handler registered")
	}

	if err := client.Credentials.validate(); err != nil {
		return err
	}

	req.Header.Set("User-Agent", GetUserAgent())
	switch {
	case client.Credentials.Token != "":
		req.Header.Set("Authorization", "token "+client.Credentials.Token)
	case client.Credentials.Username != "":
		pwd, err := speakeasy.Ask("Password: ")
		if err != nil {
			return err
		}
		req.SetBasicAuth(client.Credentials.Username, pwd)

		if client.Credentials.TFA { // TFA only required for username+password based login.
			token, err := speakeasy.Ask("TFA-Token: ")
			if err != nil {
				return err
			}
			req.Header.Set("X-PhraseApp-OTP", token)
		}
	}

	return nil
}

func (ah *Credentials) validate() error {
	switch {
	case ah.Username == "" && ah.Token == "":
		return fmt.Errorf("either username or token must be given")
	default:
		return nil
	}
}

func (client *Client) sendRequestPaginated(method, rawurl, ctype string, r io.Reader, status, page, perPage int) (io.ReadCloser, error) {
	endpointUrl := client.Credentials.Host + rawurl
	u, err := url.Parse(endpointUrl)
	if err != nil {
		return nil, err
	}

	query := u.Query()
	query.Add("page", strconv.Itoa(page))
	query.Add("per_page", strconv.Itoa(perPage))

	u.RawQuery = query.Encode()

	if Debug {
		fmt.Fprintln(os.Stderr, method, u)
		if r != nil {
			bytes, err := ioutil.ReadAll(r)
			if err != nil {
				fmt.Fprintf(os.Stderr, "Error: %s", err.Error())
			}
			str := string(bytes)
			fmt.Fprintln(os.Stderr, str)
			r = strings.NewReader(str)
		}
	}

	req, err := http.NewRequest(method, u.String(), r)
	if err != nil {
		return nil, err
	}

	if ctype != "" {
		req.Header.Add("Content-Type", ctype)
	}

	resp, err := client.send(req, status)
	if err != nil {
		return nil, err
	}

	return resp.Body, nil
}

func (client *Client) sendRequest(method, url, ctype string, r io.Reader, status int) (io.ReadCloser, error) {
	endpointUrl := client.Credentials.Host + url
	if Debug {
		fmt.Fprintln(os.Stderr, method, url)
		if r != nil {
			bytes, err := ioutil.ReadAll(r)
			if err != nil {
				fmt.Fprintf(os.Stderr, "Error: %s", err.Error())
			}
			str := string(bytes)
			fmt.Fprintln(os.Stderr, str)
			r = strings.NewReader(str)
		}
	}
	req, err := http.NewRequest(method, endpointUrl, r)
	if err != nil {
		return nil, err
	}

	if ctype != "" {
		req.Header.Add("Content-Type", ctype)
	}

	resp, err := client.send(req, status)
	if err != nil {
		return nil, err
	}
	return resp.Body, nil
}

func (client *Client) send(req *http.Request, status int) (*http.Response, error) {
	err := client.authenticate(req)
	if err != nil {
		return nil, err
	}

	if Debug {
		b := new(bytes.Buffer)
		err = req.Header.Write(b)
		if err != nil {
			return nil, err
		}

		bytes, err := ioutil.ReadAll(b)
		if err != nil {
			return nil, err
		}
		fmt.Fprintln(os.Stderr, string(bytes))

		r := req.Body
		if r != nil {
			var by []byte
			_, err = r.Read(by)
			fmt.Fprintln(os.Stderr, string(by))
		}
	}
	resp, err := client.Client.Do(req)
	if err != nil {
		return nil, err
	}

	if Debug {
		fmt.Fprintf(os.Stderr, "\nResponse HTTP Status Code: %s\n", resp.Status)
	}

	err = handleResponseStatus(resp, status)
	if err != nil {
		resp.Body.Close()
	}
	return resp, err
}
<commit_msg>client: change constructor to only take one set of credentials<commit_after>package phraseapp

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"strconv"
	"strings"

	"os"

	"github.com/bgentry/speakeasy"
)

var Debug bool

func EnableDebug() {
	Debug = true
}

type DefaultParams Action
type Action map[string]map[string]interface{}

type Client struct {
	http.Client
	Credentials *Credentials
}

type Credentials struct {
	Username string `cli:"opt --username -u desc='username used for authentication'"`
	Token    string `cli:"opt --access-token -t desc='access token used for authentication'"`
	TFA      bool   `cli:"opt --tfa desc='use Two-Factor Authentication'"`
	Host     string `cli:"opt --host desc='Host to send Request to'"`
	Debug    bool   `cli:"opt --verbose -v desc='Verbose output'"`
}

func NewClient(credentials *Credentials) (*Client, error) {
	client := &Client{Credentials: &Credentials{}}

	envToken := os.Getenv("PHRASEAPP_ACCESS_TOKEN")

	if credentials.Token != "" && client.Credentials.Token == "" && client.Credentials.Username == "" {
		client.Credentials.Token = credentials.Token
	} else if credentials.Username != "" && client.Credentials.Username == "" {
		client.Credentials.Username = credentials.Username
	} else if envToken != "" && credentials.Token == "" && credentials.Username == "" && client.Credentials.Username == "" {
		client.Credentials.Token = envToken
	}

	if credentials.TFA {
		client.Credentials.TFA = credentials.TFA
	}

	if credentials.Debug == true {
		EnableDebug()
	}

	if credentials.Host != "" {
		client.Credentials.Host = credentials.Host
	} else {
		client.Credentials.Host = "https://api.phraseapp.com"
	}

	return client, nil
}

func (client *Client) authenticate(req *http.Request) error {
	if client.Credentials == nil {
		return fmt.Errorf("no auth handler registered")
	}

	if err := client.Credentials.validate(); err != nil {
		return err
	}

	req.Header.Set("User-Agent", GetUserAgent())
	switch {
	case client.Credentials.Token != "":
		req.Header.Set("Authorization", "token "+client.Credentials.Token)
	case client.Credentials.Username != "":
		pwd, err := speakeasy.Ask("Password: ")
		if err != nil {
			return err
		}
		req.SetBasicAuth(client.Credentials.Username, pwd)

		if client.Credentials.TFA { // TFA only required for username+password based login.
			token, err := speakeasy.Ask("TFA-Token: ")
			if err != nil {
				return err
			}
			req.Header.Set("X-PhraseApp-OTP", token)
		}
	}

	return nil
}

func (ah *Credentials) validate() error {
	switch {
	case ah.Username == "" && ah.Token == "":
		return fmt.Errorf("either username or token must be given")
	default:
		return nil
	}
}

func (client *Client) sendRequestPaginated(method, rawurl, ctype string, r io.Reader, status, page, perPage int) (io.ReadCloser, error) {
	endpointUrl := client.Credentials.Host + rawurl
	u, err := url.Parse(endpointUrl)
	if err != nil {
		return nil, err
	}

	query := u.Query()
	query.Add("page", strconv.Itoa(page))
	query.Add("per_page", strconv.Itoa(perPage))

	u.RawQuery = query.Encode()

	if Debug {
		fmt.Fprintln(os.Stderr, method, u)
		if r != nil {
			bytes, err := ioutil.ReadAll(r)
			if err != nil {
				fmt.Fprintf(os.Stderr, "Error: %s", err.Error())
			}
			str := string(bytes)
			fmt.Fprintln(os.Stderr, str)
			r = strings.NewReader(str)
		}
	}

	req, err := http.NewRequest(method, u.String(), r)
	if err != nil {
		return nil, err
	}

	if ctype != "" {
		req.Header.Add("Content-Type", ctype)
	}

	resp, err := client.send(req, status)
	if err != nil {
		return nil, err
	}

	return resp.Body, nil
}

func (client *Client) sendRequest(method, url, ctype string, r io.Reader, status int) (io.ReadCloser, error) {
	endpointUrl := client.Credentials.Host + url
	if Debug {
		fmt.Fprintln(os.Stderr, method, url)
		if r != nil {
			bytes, err := ioutil.ReadAll(r)
			if err != nil {
				fmt.Fprintf(os.Stderr, "Error: %s", err.Error())
			}
			str := string(bytes)
			fmt.Fprintln(os.Stderr, str)
			r = strings.NewReader(str)
		}
	}
	req, err := http.NewRequest(method, endpointUrl, r)
	if err != nil {
		return nil, err
	}

	if ctype != "" {
		req.Header.Add("Content-Type", ctype)
	}

	resp, err := client.send(req, status)
	if err != nil {
		return nil, err
	}
	return resp.Body, nil
}

func (client *Client) send(req *http.Request, status int) (*http.Response, error) {
	err := client.authenticate(req)
	if err != nil {
		return nil, err
	}

	if Debug {
		b := new(bytes.Buffer)
		err = req.Header.Write(b)
		if err != nil {
			return nil, err
		}

		bytes, err := ioutil.ReadAll(b)
		if err != nil {
			return nil, err
		}
		fmt.Fprintln(os.Stderr, string(bytes))

		r := req.Body
		if r != nil {
			var by []byte
			_, err = r.Read(by)
			fmt.Fprintln(os.Stderr, string(by))
		}
	}
	resp, err := client.Client.Do(req)
	if err != nil {
		return nil, err
	}

	if Debug {
		fmt.Fprintf(os.Stderr, "\nResponse HTTP Status Code: %s\n", resp.Status)
	}

	err = handleResponseStatus(resp, status)
	if err != nil {
		resp.Body.Close()
	}
	return resp, err
}
<|endoftext|>


<commit_before>// ----------------------------------------------------------------------------
//
//     ***     AUTO GENERATED CODE    ***    AUTO GENERATED CODE     ***
//
// ----------------------------------------------------------------------------
//
//     This file is automatically generated by Magic Modules and manual
//     changes will be clobbered when the file is regenerated.
//
//     Please read more about how to change this file in
//     .github/CONTRIBUTING.md.
//
// ----------------------------------------------------------------------------

package google

import (
	"reflect"

	"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
)

func GetAccessContextManagerServicePerimeterCaiObject(d TerraformResourceData, config *Config) (Asset, error) {
	name, err := assetName(d, config, "//accesscontextmanager.googleapis.com/{{name}}")
	if err != nil {
		return Asset{}, err
	}
	if obj, err := GetAccessContextManagerServicePerimeterApiObject(d, config); err == nil {
		return Asset{
			Name: name,
			Type: "accesscontextmanager.googleapis.com/ServicePerimeter",
			Resource: &AssetResource{
				Version:              "v1",
				DiscoveryDocumentURI: "https://www.googleapis.com/discovery/v1/apis/accesscontextmanager/v1/rest",
				DiscoveryName:        "ServicePerimeter",
				Data:                 obj,
			},
		}, nil
	} else {
		return Asset{}, err
	}
}

func GetAccessContextManagerServicePerimeterApiObject(d TerraformResourceData, config *Config) (map[string]interface{}, error) {
	obj := make(map[string]interface{})
	titleProp, err := expandAccessContextManagerServicePerimeterTitle(d.Get("title"), d, config)
	if err != nil {
		return nil, err
	} else if v, ok := d.GetOkExists("title"); !isEmptyValue(reflect.ValueOf(titleProp)) && (ok || !reflect.DeepEqual(v, titleProp)) {
		obj["title"] = titleProp
	}
	descriptionProp, err := expandAccessContextManagerServicePerimeterDescription(d.Get("description"), d, config)
	if err != nil {
		return nil, err
	} else if v, ok := d.GetOkExists("description"); !isEmptyValue(reflect.ValueOf(descriptionProp)) && (ok || !reflect.DeepEqual(v, descriptionProp)) {
		obj["description"] = descriptionProp
	}
	perimeterTypeProp, err := expandAccessContextManagerServicePerimeterPerimeterType(d.Get("perimeter_type"), d, config)
	if err != nil {
		return nil, err
	} else if v, ok := d.GetOkExists("perimeter_type"); !isEmptyValue(reflect.ValueOf(perimeterTypeProp)) && (ok || !reflect.DeepEqual(v, perimeterTypeProp)) {
		obj["perimeterType"] = perimeterTypeProp
	}
	statusProp, err := expandAccessContextManagerServicePerimeterStatus(d.Get("status"), d, config)
	if err != nil {
		return nil, err
	} else if v, ok := d.GetOkExists("status"); !isEmptyValue(reflect.ValueOf(statusProp)) && (ok || !reflect.DeepEqual(v, statusProp)) {
		obj["status"] = statusProp
	}
	parentProp, err := expandAccessContextManagerServicePerimeterParent(d.Get("parent"), d, config)
	if err != nil {
		return nil, err
	} else if v, ok := d.GetOkExists("parent"); !isEmptyValue(reflect.ValueOf(parentProp)) && (ok || !reflect.DeepEqual(v, parentProp)) {
		obj["parent"] = parentProp
	}
	nameProp, err := expandAccessContextManagerServicePerimeterName(d.Get("name"), d, config)
	if err != nil {
		return nil, err
	} else if v, ok := d.GetOkExists("name"); !isEmptyValue(reflect.ValueOf(nameProp)) && (ok || !reflect.DeepEqual(v, nameProp)) {
		obj["name"] = nameProp
	}

	return resourceAccessContextManagerServicePerimeterEncoder(d, config, obj)
}

func resourceAccessContextManagerServicePerimeterEncoder(d TerraformResourceData, meta interface{}, obj map[string]interface{}) (map[string]interface{}, error) {
	delete(obj, "parent")
	return obj, nil
}

func expandAccessContextManagerServicePerimeterTitle(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandAccessContextManagerServicePerimeterDescription(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandAccessContextManagerServicePerimeterPerimeterType(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandAccessContextManagerServicePerimeterStatus(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	l := v.([]interface{})
	if len(l) == 0 || l[0] == nil {
		return nil, nil
	}
	raw := l[0]
	original := raw.(map[string]interface{})
	transformed := make(map[string]interface{})

	transformedResources, err := expandAccessContextManagerServicePerimeterStatusResources(original["resources"], d, config)
	if err != nil {
		return nil, err
	} else if val := reflect.ValueOf(transformedResources); val.IsValid() && !isEmptyValue(val) {
		transformed["resources"] = transformedResources
	}

	transformedAccessLevels, err := expandAccessContextManagerServicePerimeterStatusAccessLevels(original["access_levels"], d, config)
	if err != nil {
		return nil, err
	} else if val := reflect.ValueOf(transformedAccessLevels); val.IsValid() && !isEmptyValue(val) {
		transformed["accessLevels"] = transformedAccessLevels
	}

	transformedRestrictedServices, err := expandAccessContextManagerServicePerimeterStatusRestrictedServices(original["restricted_services"], d, config)
	if err != nil {
		return nil, err
	} else if val := reflect.ValueOf(transformedRestrictedServices); val.IsValid() && !isEmptyValue(val) {
		transformed["restrictedServices"] = transformedRestrictedServices
	}

	transformedVPCAccessibleServices, err := expandAccessContextManagerServicePerimeterStatusVPCAccessibleServices(original["vpc_accessible_services"], d, config)
	if err != nil {
		return nil, err
	} else if val := reflect.ValueOf(transformedVPCAccessibleServices); val.IsValid() && !isEmptyValue(val) {
		transformed["vpcAccessibleServices"] = transformedVPCAccessibleServices
	}

	return transformed, nil
}

func expandAccessContextManagerServicePerimeterStatusResources(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandAccessContextManagerServicePerimeterStatusAccessLevels(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandAccessContextManagerServicePerimeterStatusRestrictedServices(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	v = v.(*schema.Set).List()
	return v, nil
}

func expandAccessContextManagerServicePerimeterStatusVPCAccessibleServices(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	l := v.([]interface{})
	if len(l) == 0 || l[0] == nil {
		return nil, nil
	}
	raw := l[0]
	original := raw.(map[string]interface{})
	transformed := make(map[string]interface{})

	transformedEnableRestriction, err := expandAccessContextManagerServicePerimeterStatusVPCAccessibleServicesEnableRestriction(original["enable_restriction"], d, config)
	if err != nil {
		return nil, err
	} else if val := reflect.ValueOf(transformedEnableRestriction); val.IsValid() && !isEmptyValue(val) {
		transformed["enableRestriction"] = transformedEnableRestriction
	}

	transformedAllowedServices, err := expandAccessContextManagerServicePerimeterStatusVPCAccessibleServicesAllowedServices(original["allowed_services"], d, config)
	if err != nil {
		return nil, err
	} else if val := reflect.ValueOf(transformedAllowedServices); val.IsValid() && !isEmptyValue(val) {
		transformed["allowedServices"] = transformedAllowedServices
	}

	return transformed, nil
}

func expandAccessContextManagerServicePerimeterStatusVPCAccessibleServicesEnableRestriction(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandAccessContextManagerServicePerimeterStatusVPCAccessibleServicesAllowedServices(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	v = v.(*schema.Set).List()
	return v, nil
}

func expandAccessContextManagerServicePerimeterParent(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandAccessContextManagerServicePerimeterName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}
<commit_msg>VPC SC dry-run mode (#3353) (#413)<commit_after>// ----------------------------------------------------------------------------
//
//     ***     AUTO GENERATED CODE    ***    AUTO GENERATED CODE     ***
//
// ----------------------------------------------------------------------------
//
//     This file is automatically generated by Magic Modules and manual
//     changes will be clobbered when the file is regenerated.
//
//     Please read more about how to change this file in
//     .github/CONTRIBUTING.md.
//
// ----------------------------------------------------------------------------

package google

import (
	"reflect"

	"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
)

func GetAccessContextManagerServicePerimeterCaiObject(d TerraformResourceData, config *Config) (Asset, error) {
	name, err := assetName(d, config, "//accesscontextmanager.googleapis.com/{{name}}")
	if err != nil {
		return Asset{}, err
	}
	if obj, err := GetAccessContextManagerServicePerimeterApiObject(d, config); err == nil {
		return Asset{
			Name: name,
			Type: "accesscontextmanager.googleapis.com/ServicePerimeter",
			Resource: &AssetResource{
				Version:              "v1",
				DiscoveryDocumentURI: "https://www.googleapis.com/discovery/v1/apis/accesscontextmanager/v1/rest",
				DiscoveryName:        "ServicePerimeter",
				Data:                 obj,
			},
		}, nil
	} else {
		return Asset{}, err
	}
}

func GetAccessContextManagerServicePerimeterApiObject(d TerraformResourceData, config *Config) (map[string]interface{}, error) {
	obj := make(map[string]interface{})
	titleProp, err := expandAccessContextManagerServicePerimeterTitle(d.Get("title"), d, config)
	if err != nil {
		return nil, err
	} else if v, ok := d.GetOkExists("title"); !isEmptyValue(reflect.ValueOf(titleProp)) && (ok || !reflect.DeepEqual(v, titleProp)) {
		obj["title"] = titleProp
	}
	descriptionProp, err := expandAccessContextManagerServicePerimeterDescription(d.Get("description"), d, config)
	if err != nil {
		return nil, err
	} else if v, ok := d.GetOkExists("description"); !isEmptyValue(reflect.ValueOf(descriptionProp)) && (ok || !reflect.DeepEqual(v, descriptionProp)) {
		obj["description"] = descriptionProp
	}
	perimeterTypeProp, err := expandAccessContextManagerServicePerimeterPerimeterType(d.Get("perimeter_type"), d, config)
	if err != nil {
		return nil, err
	} else if v, ok := d.GetOkExists("perimeter_type"); !isEmptyValue(reflect.ValueOf(perimeterTypeProp)) && (ok || !reflect.DeepEqual(v, perimeterTypeProp)) {
		obj["perimeterType"] = perimeterTypeProp
	}
	statusProp, err := expandAccessContextManagerServicePerimeterStatus(d.Get("status"), d, config)
	if err != nil {
		return nil, err
	} else if v, ok := d.GetOkExists("status"); !isEmptyValue(reflect.ValueOf(statusProp)) && (ok || !reflect.DeepEqual(v, statusProp)) {
		obj["status"] = statusProp
	}
	specProp, err := expandAccessContextManagerServicePerimeterSpec(d.Get("spec"), d, config)
	if err != nil {
		return nil, err
	} else if v, ok := d.GetOkExists("spec"); !isEmptyValue(reflect.ValueOf(specProp)) && (ok || !reflect.DeepEqual(v, specProp)) {
		obj["spec"] = specProp
	}
	useExplicitDryRunSpecProp, err := expandAccessContextManagerServicePerimeterUseExplicitDryRunSpec(d.Get("use_explicit_dry_run_spec"), d, config)
	if err != nil {
		return nil, err
	} else if v, ok := d.GetOkExists("use_explicit_dry_run_spec"); !isEmptyValue(reflect.ValueOf(useExplicitDryRunSpecProp)) && (ok || !reflect.DeepEqual(v, useExplicitDryRunSpecProp)) {
		obj["useExplicitDryRunSpec"] = useExplicitDryRunSpecProp
	}
	parentProp, err := expandAccessContextManagerServicePerimeterParent(d.Get("parent"), d, config)
	if err != nil {
		return nil, err
	} else if v, ok := d.GetOkExists("parent"); !isEmptyValue(reflect.ValueOf(parentProp)) && (ok || !reflect.DeepEqual(v, parentProp)) {
		obj["parent"] = parentProp
	}
	nameProp, err := expandAccessContextManagerServicePerimeterName(d.Get("name"), d, config)
	if err != nil {
		return nil, err
	} else if v, ok := d.GetOkExists("name"); !isEmptyValue(reflect.ValueOf(nameProp)) && (ok || !reflect.DeepEqual(v, nameProp)) {
		obj["name"] = nameProp
	}

	return resourceAccessContextManagerServicePerimeterEncoder(d, config, obj)
}

func resourceAccessContextManagerServicePerimeterEncoder(d TerraformResourceData, meta interface{}, obj map[string]interface{}) (map[string]interface{}, error) {
	delete(obj, "parent")
	return obj, nil
}

func expandAccessContextManagerServicePerimeterTitle(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandAccessContextManagerServicePerimeterDescription(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandAccessContextManagerServicePerimeterPerimeterType(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandAccessContextManagerServicePerimeterStatus(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	l := v.([]interface{})
	if len(l) == 0 || l[0] == nil {
		return nil, nil
	}
	raw := l[0]
	original := raw.(map[string]interface{})
	transformed := make(map[string]interface{})

	transformedResources, err := expandAccessContextManagerServicePerimeterStatusResources(original["resources"], d, config)
	if err != nil {
		return nil, err
	} else if val := reflect.ValueOf(transformedResources); val.IsValid() && !isEmptyValue(val) {
		transformed["resources"] = transformedResources
	}

	transformedAccessLevels, err := expandAccessContextManagerServicePerimeterStatusAccessLevels(original["access_levels"], d, config)
	if err != nil {
		return nil, err
	} else if val := reflect.ValueOf(transformedAccessLevels); val.IsValid() && !isEmptyValue(val) {
		transformed["accessLevels"] = transformedAccessLevels
	}

	transformedRestrictedServices, err := expandAccessContextManagerServicePerimeterStatusRestrictedServices(original["restricted_services"], d, config)
	if err != nil {
		return nil, err
	} else if val := reflect.ValueOf(transformedRestrictedServices); val.IsValid() && !isEmptyValue(val) {
		transformed["restrictedServices"] = transformedRestrictedServices
	}

	transformedVPCAccessibleServices, err := expandAccessContextManagerServicePerimeterStatusVPCAccessibleServices(original["vpc_accessible_services"], d, config)
	if err != nil {
		return nil, err
	} else if val := reflect.ValueOf(transformedVPCAccessibleServices); val.IsValid() && !isEmptyValue(val) {
		transformed["vpcAccessibleServices"] = transformedVPCAccessibleServices
	}

	return transformed, nil
}

func expandAccessContextManagerServicePerimeterStatusResources(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandAccessContextManagerServicePerimeterStatusAccessLevels(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandAccessContextManagerServicePerimeterStatusRestrictedServices(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	v = v.(*schema.Set).List()
	return v, nil
}

func expandAccessContextManagerServicePerimeterStatusVPCAccessibleServices(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	l := v.([]interface{})
	if len(l) == 0 || l[0] == nil {
		return nil, nil
	}
	raw := l[0]
	original := raw.(map[string]interface{})
	transformed := make(map[string]interface{})

	transformedEnableRestriction, err := expandAccessContextManagerServicePerimeterStatusVPCAccessibleServicesEnableRestriction(original["enable_restriction"], d, config)
	if err != nil {
		return nil, err
	} else if val := reflect.ValueOf(transformedEnableRestriction); val.IsValid() && !isEmptyValue(val) {
		transformed["enableRestriction"] = transformedEnableRestriction
	}

	transformedAllowedServices, err := expandAccessContextManagerServicePerimeterStatusVPCAccessibleServicesAllowedServices(original["allowed_services"], d, config)
	if err != nil {
		return nil, err
	} else if val := reflect.ValueOf(transformedAllowedServices); val.IsValid() && !isEmptyValue(val) {
		transformed["allowedServices"] = transformedAllowedServices
	}

	return transformed, nil
}

func expandAccessContextManagerServicePerimeterStatusVPCAccessibleServicesEnableRestriction(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandAccessContextManagerServicePerimeterStatusVPCAccessibleServicesAllowedServices(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	v = v.(*schema.Set).List()
	return v, nil
}

func expandAccessContextManagerServicePerimeterSpec(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	l := v.([]interface{})
	if len(l) == 0 || l[0] == nil {
		return nil, nil
	}
	raw := l[0]
	original := raw.(map[string]interface{})
	transformed := make(map[string]interface{})

	transformedResources, err := expandAccessContextManagerServicePerimeterSpecResources(original["resources"], d, config)
	if err != nil {
		return nil, err
	} else if val := reflect.ValueOf(transformedResources); val.IsValid() && !isEmptyValue(val) {
		transformed["resources"] = transformedResources
	}

	transformedAccessLevels, err := expandAccessContextManagerServicePerimeterSpecAccessLevels(original["access_levels"], d, config)
	if err != nil {
		return nil, err
	} else if val := reflect.ValueOf(transformedAccessLevels); val.IsValid() && !isEmptyValue(val) {
		transformed["accessLevels"] = transformedAccessLevels
	}

	transformedRestrictedServices, err := expandAccessContextManagerServicePerimeterSpecRestrictedServices(original["restricted_services"], d, config)
	if err != nil {
		return nil, err
	} else if val := reflect.ValueOf(transformedRestrictedServices); val.IsValid() && !isEmptyValue(val) {
		transformed["restrictedServices"] = transformedRestrictedServices
	}

	transformedVPCAccessibleServices, err := expandAccessContextManagerServicePerimeterSpecVPCAccessibleServices(original["vpc_accessible_services"], d, config)
	if err != nil {
		return nil, err
	} else if val := reflect.ValueOf(transformedVPCAccessibleServices); val.IsValid() && !isEmptyValue(val) {
		transformed["vpcAccessibleServices"] = transformedVPCAccessibleServices
	}

	return transformed, nil
}

func expandAccessContextManagerServicePerimeterSpecResources(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandAccessContextManagerServicePerimeterSpecAccessLevels(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandAccessContextManagerServicePerimeterSpecRestrictedServices(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandAccessContextManagerServicePerimeterSpecVPCAccessibleServices(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	l := v.([]interface{})
	if len(l) == 0 || l[0] == nil {
		return nil, nil
	}
	raw := l[0]
	original := raw.(map[string]interface{})
	transformed := make(map[string]interface{})

	transformedEnableRestriction, err := expandAccessContextManagerServicePerimeterSpecVPCAccessibleServicesEnableRestriction(original["enable_restriction"], d, config)
	if err != nil {
		return nil, err
	} else if val := reflect.ValueOf(transformedEnableRestriction); val.IsValid() && !isEmptyValue(val) {
		transformed["enableRestriction"] = transformedEnableRestriction
	}

	transformedAllowedServices, err := expandAccessContextManagerServicePerimeterSpecVPCAccessibleServicesAllowedServices(original["allowed_services"], d, config)
	if err != nil {
		return nil, err
	} else if val := reflect.ValueOf(transformedAllowedServices); val.IsValid() && !isEmptyValue(val) {
		transformed["allowedServices"] = transformedAllowedServices
	}

	return transformed, nil
}

func expandAccessContextManagerServicePerimeterSpecVPCAccessibleServicesEnableRestriction(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandAccessContextManagerServicePerimeterSpecVPCAccessibleServicesAllowedServices(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandAccessContextManagerServicePerimeterUseExplicitDryRunSpec(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandAccessContextManagerServicePerimeterParent(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandAccessContextManagerServicePerimeterName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}
<|endoftext|>


<commit_before>/*
 * Copyright 2015 Xuyuan Pang <xuyuanp # gmail dot com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package hador

import (
	"fmt"
	"regexp"
	"strings"
)

func genSegments(path string) []string {
	if path == "/" {
		path = ""
	}
	return strings.Split(path, "/")[1:]
}

var regSegmentRegexp = regexp.MustCompile(`\(\?P<.+>.+\)`)

// Leaf struct
type Leaf struct {
	*FilterChain
	Parent  *Node
	path    string
	Handler Handler
	Method  string
}

// NewLeaf creates new Leaf instance
func NewLeaf(method string, handler Handler) *Leaf {
	l := &Leaf{
		Method:  method,
		Handler: handler,
	}
	l.FilterChain = NewFilterChain(l.Handler)
	return l
}

func (l *Leaf) Path() string {
	return l.path
}

type dispatcher struct {
	node *Node
}

func (d *dispatcher) Serve(ctx *Context) {
	n := d.node
	segments := ctx.Request.segments
	// path matches
	if len(segments) == n.Depth {
		// 404 not found
		if len(n.Leaves) == 0 {
			ctx.NotFound()
			return
		}
		// method matches
		if l, ok := n.Leaves[ctx.Request.Method]; ok {
			l.Serve(ctx)
			return
		}
		// ANY matches
		if l, ok := n.Leaves["ANY"]; ok {
			l.Serve(ctx)
			return
		}
		// 405 method not allowed
		methods := make([]string, len(n.Leaves))
		i := 0
		for m := range n.Leaves {
			methods[i] = m
			i++
		}
		ctx.MethodNotAllowed(methods)
		return
	}
	// find next node
	segment := segments[n.Depth]
	var next *Node
	if ne, ok := n.rawChildren[segment]; ok {
		next = ne
	} else {
		for _, ne := range n.regChildren {
			if key, value, ok := ne.MatchRegexp(segment); ok && key != "" {
				ctx.Params[key] = value
				next = ne
				break
			}
		}
	}
	if next != nil {
		next.Serve(ctx)
		return
	}
	// 404 not found
	ctx.NotFound()
}

// Node struct
type Node struct {
	*FilterChain
	Parent        *Node
	Depth         int
	Segment       string
	regexpSegment *regexp.Regexp
	rawChildren   map[string]*Node
	regChildren   []*Node
	Leaves        map[string]*Leaf
}

// NewNode creates new Node instance.
func NewNode(segment string, depth int) *Node {
	var reg *regexp.Regexp
	if segment != "" && regSegmentRegexp.MatchString(segment) {
		reg = regexp.MustCompile(segment)
	}
	n := &Node{
		Segment:       segment,
		Depth:         depth,
		regexpSegment: reg,
		rawChildren:   make(map[string]*Node),
		regChildren:   make([]*Node, 0),
		Leaves:        make(map[string]*Leaf),
	}
	n.FilterChain = NewFilterChain(&dispatcher{node: n})
	return n
}

// Options adds route by call AddRoute
func (n *Node) Options(pattern string, handler Handler) Beforer {
	return n.AddRoute("OPTIONS", pattern, handler)
}

// Get adds route by call AddRoute
func (n *Node) Get(pattern string, handler Handler) Beforer {
	return n.AddRoute("GET", pattern, handler)
}

// Head adds route by call AddRoute
func (n *Node) Head(pattern string, handler Handler) Beforer {
	return n.AddRoute("HEAD", pattern, handler)
}

// Post adds route by call AddRoute
func (n *Node) Post(pattern string, handler Handler) Beforer {
	return n.AddRoute("POST", pattern, handler)
}

// Put adds route by call AddRoute
func (n *Node) Put(pattern string, handler Handler) Beforer {
	return n.AddRoute("PUT", pattern, handler)
}

// Delete adds route by call AddRoute
func (n *Node) Delete(pattern string, handler Handler) Beforer {
	return n.AddRoute("DELETE", pattern, handler)
}

// Trace adds route by call AddRoute
func (n *Node) Trace(pattern string, handler Handler) Beforer {
	return n.AddRoute("TRACE", pattern, handler)
}

// Connect adds route by call AddRoute
func (n *Node) Connect(pattern string, handler Handler) Beforer {
	return n.AddRoute("CONNECT", pattern, handler)
}

// Patch adds route by call AddRoute
func (n *Node) Patch(pattern string, handler Handler) Beforer {
	return n.AddRoute("PATCH", pattern, handler)
}

// Any adds route by call AddRoute
func (n *Node) Any(pattern string, handler Handler) Beforer {
	return n.AddRoute("ANY", pattern, handler)
}

// Group adds group routes
func (n *Node) Group(pattern string, f func(Router)) Beforer {
	segments := genSegments(pattern)
	r, _, _ := n.add(segments, "", nil)
	f(r)
	return r
}

// AddRoute adds a new route with method, pattern and handler
func (n *Node) AddRoute(method, pattern string, handler Handler) Beforer {
	segments := genSegments(pattern)
	if _, l, ok := n.add(segments, method, handler); ok {
		return l
	}
	panic(fmt.Errorf("pattern: %s has been registered", pattern))
}

func (n *Node) add(segments []string, method string, handler Handler) (*Node, *Leaf, bool) {
	if len(segments) == 0 {
		if method != "" && handler != nil {
			if _, ok := n.Leaves[method]; ok {
				return n, nil, false
			}
			l := NewLeaf(method, handler)
			l.Parent = n
			l.path = n.Path()
			n.Leaves[method] = l
			return n, l, true
		}
		return n, nil, true
	}
	segment := segments[0]
	var next *Node
	if !regSegmentRegexp.MatchString(segment) {
		if ne, ok := n.rawChildren[segment]; ok {
			next = ne
		} else {
			next = NewNode(segment, n.Depth+1)
			n.rawChildren[segment] = next
		}
	} else {
		found := false
		for _, next = range n.regChildren {
			if next.Segment == segment {
				found = true
				break
			}
		}
		if !found {
			next = NewNode(segment, n.Depth+1)
			n.regChildren = append(n.regChildren, next)
		}
	}
	next.Parent = n
	return next.add(segments[1:], method, handler)
}

// MatchRegexp checks if the segment match regexp in node
func (n *Node) MatchRegexp(segment string) (string, string, bool) {
	if n.regexpSegment != nil {
		result := n.regexpSegment.FindStringSubmatch(segment)
		if len(result) > 1 && result[0] == segment {
			value := result[1]
			key := n.regexpSegment.SubexpNames()[1]
			return key, value, true
		}
	}
	return "", "", false
}

// Path return the full path from root to the node
func (n *Node) Path() string {
	if n.Parent == nil {
		return "/"
	}
	ppath := n.Parent.Path()
	if ppath == "/" {
		ppath = ""
	}
	return ppath + "/" + n.Segment
}
<commit_msg>Changed comments<commit_after>/*
 * Copyright 2015 Xuyuan Pang <xuyuanp # gmail dot com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package hador

import (
	"fmt"
	"regexp"
	"strings"
)

func genSegments(path string) []string {
	if path == "/" {
		path = ""
	}
	return strings.Split(path, "/")[1:]
}

var regSegmentRegexp = regexp.MustCompile(`\(\?P<.+>.+\)`)

// Leaf struct
type Leaf struct {
	*FilterChain
	Parent  *Node
	path    string
	Handler Handler
	Method  string
}

// NewLeaf creates new Leaf instance
func NewLeaf(method string, handler Handler) *Leaf {
	l := &Leaf{
		Method:  method,
		Handler: handler,
	}
	l.FilterChain = NewFilterChain(l.Handler)
	return l
}

// Path returns the full path from root to the parent node
func (l *Leaf) Path() string {
	return l.path
}

type dispatcher struct {
	node *Node
}

func (d *dispatcher) Serve(ctx *Context) {
	n := d.node
	segments := ctx.Request.segments
	// path matches
	if len(segments) == n.Depth {
		// 404 not found
		if len(n.Leaves) == 0 {
			ctx.NotFound()
			return
		}
		// method matches
		if l, ok := n.Leaves[ctx.Request.Method]; ok {
			l.Serve(ctx)
			return
		}
		// ANY matches
		if l, ok := n.Leaves["ANY"]; ok {
			l.Serve(ctx)
			return
		}
		// 405 method not allowed
		methods := make([]string, len(n.Leaves))
		i := 0
		for m := range n.Leaves {
			methods[i] = m
			i++
		}
		ctx.MethodNotAllowed(methods)
		return
	}
	// find next node
	segment := segments[n.Depth]
	var next *Node
	if ne, ok := n.rawChildren[segment]; ok {
		next = ne
	} else {
		for _, ne := range n.regChildren {
			if key, value, ok := ne.MatchRegexp(segment); ok && key != "" {
				ctx.Params[key] = value
				next = ne
				break
			}
		}
	}
	if next != nil {
		next.Serve(ctx)
		return
	}
	// 404 not found
	ctx.NotFound()
}

// Node struct
type Node struct {
	*FilterChain
	Parent        *Node
	Depth         int
	Segment       string
	regexpSegment *regexp.Regexp
	rawChildren   map[string]*Node
	regChildren   []*Node
	Leaves        map[string]*Leaf
}

// NewNode creates new Node instance.
func NewNode(segment string, depth int) *Node {
	var reg *regexp.Regexp
	if segment != "" && regSegmentRegexp.MatchString(segment) {
		reg = regexp.MustCompile(segment)
	}
	n := &Node{
		Segment:       segment,
		Depth:         depth,
		regexpSegment: reg,
		rawChildren:   make(map[string]*Node),
		regChildren:   make([]*Node, 0),
		Leaves:        make(map[string]*Leaf),
	}
	n.FilterChain = NewFilterChain(&dispatcher{node: n})
	return n
}

// Options adds route by call AddRoute
func (n *Node) Options(pattern string, handler Handler) Beforer {
	return n.AddRoute("OPTIONS", pattern, handler)
}

// Get adds route by call AddRoute
func (n *Node) Get(pattern string, handler Handler) Beforer {
	return n.AddRoute("GET", pattern, handler)
}

// Head adds route by call AddRoute
func (n *Node) Head(pattern string, handler Handler) Beforer {
	return n.AddRoute("HEAD", pattern, handler)
}

// Post adds route by call AddRoute
func (n *Node) Post(pattern string, handler Handler) Beforer {
	return n.AddRoute("POST", pattern, handler)
}

// Put adds route by call AddRoute
func (n *Node) Put(pattern string, handler Handler) Beforer {
	return n.AddRoute("PUT", pattern, handler)
}

// Delete adds route by call AddRoute
func (n *Node) Delete(pattern string, handler Handler) Beforer {
	return n.AddRoute("DELETE", pattern, handler)
}

// Trace adds route by call AddRoute
func (n *Node) Trace(pattern string, handler Handler) Beforer {
	return n.AddRoute("TRACE", pattern, handler)
}

// Connect adds route by call AddRoute
func (n *Node) Connect(pattern string, handler Handler) Beforer {
	return n.AddRoute("CONNECT", pattern, handler)
}

// Patch adds route by call AddRoute
func (n *Node) Patch(pattern string, handler Handler) Beforer {
	return n.AddRoute("PATCH", pattern, handler)
}

// Any adds route by call AddRoute
func (n *Node) Any(pattern string, handler Handler) Beforer {
	return n.AddRoute("ANY", pattern, handler)
}

// Group adds group routes
func (n *Node) Group(pattern string, f func(Router)) Beforer {
	segments := genSegments(pattern)
	r, _, _ := n.add(segments, "", nil)
	f(r)
	return r
}

// AddRoute adds a new route with method, pattern and handler
func (n *Node) AddRoute(method, pattern string, handler Handler) Beforer {
	segments := genSegments(pattern)
	if _, l, ok := n.add(segments, method, handler); ok {
		return l
	}
	panic(fmt.Errorf("pattern: %s has been registered", pattern))
}

func (n *Node) add(segments []string, method string, handler Handler) (*Node, *Leaf, bool) {
	if len(segments) == 0 {
		if method != "" && handler != nil {
			if _, ok := n.Leaves[method]; ok {
				return n, nil, false
			}
			l := NewLeaf(method, handler)
			l.Parent = n
			l.path = n.Path()
			n.Leaves[method] = l
			return n, l, true
		}
		return n, nil, true
	}
	segment := segments[0]
	var next *Node
	if !regSegmentRegexp.MatchString(segment) {
		if ne, ok := n.rawChildren[segment]; ok {
			next = ne
		} else {
			next = NewNode(segment, n.Depth+1)
			n.rawChildren[segment] = next
		}
	} else {
		found := false
		for _, next = range n.regChildren {
			if next.Segment == segment {
				found = true
				break
			}
		}
		if !found {
			next = NewNode(segment, n.Depth+1)
			n.regChildren = append(n.regChildren, next)
		}
	}
	next.Parent = n
	return next.add(segments[1:], method, handler)
}

// MatchRegexp checks if the segment match regexp in node
func (n *Node) MatchRegexp(segment string) (string, string, bool) {
	if n.regexpSegment != nil {
		result := n.regexpSegment.FindStringSubmatch(segment)
		if len(result) > 1 && result[0] == segment {
			value := result[1]
			key := n.regexpSegment.SubexpNames()[1]
			return key, value, true
		}
	}
	return "", "", false
}

// Path returns the full path from root to the node
func (n *Node) Path() string {
	if n.Parent == nil {
		return "/"
	}
	ppath := n.Parent.Path()
	if ppath == "/" {
		ppath = ""
	}
	return ppath + "/" + n.Segment
}
<|endoftext|>


<commit_before>package cbfsclient

import (
	"encoding/json"
	"fmt"
	"io"
	"math/rand"
	"net/http"
	"net/url"
	"time"

	"github.com/dustin/go-saturate"
)

type FetchCallback func(oid string, r io.Reader) error

type blobInfo struct {
	Nodes map[string]time.Time
}

func (c Client) GetBlobInfos(oids ...string) (map[string]blobInfo, error) {
	u := c.URLFor("/.cbfs/blob/info/")
	form := url.Values{"blob": oids}
	res, err := http.PostForm(u, form)
	if err != nil {
		return nil, err
	}
	defer res.Body.Close()
	if res.StatusCode != 200 {
		return nil, fmt.Errorf("HTTP error fetching blob info: %v",
			res.Status)
	}

	d := json.NewDecoder(res.Body)
	rv := map[string]blobInfo{}
	err = d.Decode(&rv)
	return rv, err
}

type fetchWork struct {
	oid string
	bi  blobInfo
}

type brokenReader struct{ err error }

func (b brokenReader) Read([]byte) (int, error) {
	return 0, b.err
}

type fetchWorker struct {
	n  StorageNode
	cb FetchCallback
}

func (fw fetchWorker) Work(i interface{}) error {
	oid := i.(string)
	res, err := http.Get(fw.n.BlobURL(oid))
	if err != nil {
		return err
	}
	defer res.Body.Close()
	if res.StatusCode != 200 {
		return fmt.Errorf("HTTP error: %v", res.Status)
	}
	return fw.cb(oid, res.Body)
}

// Fetch many blobs in bulk.
func (c *Client) Blobs(totalConcurrency, destinationConcurrency int,
	cb FetchCallback, oids ...string) error {

	nodeMap, err := c.Nodes()
	if err != nil {
		return err
	}

	dests := make([]string, 0, len(nodeMap))
	for n := range nodeMap {
		dests = append(dests, n)
	}

	infos, err := c.GetBlobInfos(oids...)
	if err != nil {
		return err
	}

	workch := make(chan saturator.WorkInput)
	go func() {
		// Feed the blob (fanout) workers.
		for oid, info := range infos {
			nodes := []string{}
			for n := range info.Nodes {
				nodes = append(nodes, n)
			}
			workch <- saturator.WorkInput{Input: oid, Dests: nodes}
		}

		// Let everything know we're done.
		close(workch)
	}()

	s := saturator.New(dests, func(n string) saturator.Worker {
		return &fetchWorker{nodeMap[n], cb}
	},
		&saturator.Config{
			DestConcurrency:  destinationConcurrency,
			TotalConcurrency: totalConcurrency,
			Retries:          3,
		})

	return s.Saturate(workch)
}

// Grab a file.
//
// This ensures the request is coming directly from a node that
// already has the blob vs. proxying.
func (c Client) Get(path string) (io.ReadCloser, error) {
	req, err := http.NewRequest("GET", c.URLFor(path), nil)
	if err != nil {
		return nil, err
	}
	req.Header.Set("X-CBFS-LocalOnly", "true")

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		return nil, err
	}

	switch res.StatusCode {
	case 200:
		return res.Body, nil
	case 300:
		defer res.Body.Close()
		res, err = http.Get(res.Header.Get("Location"))
		if err != nil {
			return nil, err
		}
		return res.Body, nil
	default:
		defer res.Body.Close()
		return nil, fmt.Errorf("HTTP Error: %v", res.Status)
	}
}

// File info
type FileHandle struct {
	c      Client
	oid    string
	length int64
	header http.Header
	nodes  map[string]time.Time
}

// The nodes containing the files and the last time it was scrubed.
func (f *FileHandle) Nodes() map[string]time.Time {
	return f.nodes
}

// The headers from the file request.
func (f *FileHandle) Header() http.Header {
	return f.header
}

// Length of this file
func (f *FileHandle) Length() int64 {
	return f.length
}

// Implement io.ReaderAt
func (f *FileHandle) ReadAt(p []byte, off int64) (n int, err error) {
	end := int64(len(p)) + off
	if end > f.length {
		return 0, fmt.Errorf("Would seek past EOF")
	}

	nodes, err := f.c.Nodes()
	if err != nil {
		return 0, err
	}

	nodelist := []StorageNode{}
	for k := range nodes {
		if n, ok := nodes[k]; ok {
			nodelist = append(nodelist, n)
		}
	}

	u := nodelist[rand.Intn(len(nodelist))].BlobURL(f.oid)

	req, err := http.NewRequest("GET", u, nil)
	if err != nil {
		return 0, err
	}
	req.Header.Set("Range", fmt.Sprintf("bytes=%v-%v", off, end))
	res, err := http.DefaultClient.Do(req)
	if err != nil {
		return 0, err
	}
	defer res.Body.Close()
	if res.StatusCode != 206 {
		return 0, fmt.Errorf("Unexpected http response: %v", res.Status)
	}

	return io.ReadFull(res.Body, p)
}

// Get a reference to the file at the given path.
func (c Client) OpenFile(path string) (*FileHandle, error) {
	res, err := http.Head(c.URLFor(path))
	if err != nil {
		return nil, err
	}
	res.Body.Close()
	if res.StatusCode != 200 {
		return nil, fmt.Errorf("HTTP error: %v", res.Status)
	}

	h := res.Header.Get("etag")
	if h == "" {
		return nil, fmt.Errorf("No etag in response headers")
	}

	h = h[1 : len(h)-1]

	infos, err := c.GetBlobInfos(h)
	if err != nil {
		return nil, err
	}

	return &FileHandle{c, h, res.ContentLength, res.Header, infos[h].Nodes}, nil
}
<commit_msg>Documented GetBlobInfos/exposed return type<commit_after>package cbfsclient

import (
	"encoding/json"
	"fmt"
	"io"
	"math/rand"
	"net/http"
	"net/url"
	"time"

	"github.com/dustin/go-saturate"
)

type FetchCallback func(oid string, r io.Reader) error

// Blob info as returned from GetBlobInfos
type BlobInfo struct {
	// Map of node name -> last time the object was validated
	Nodes map[string]time.Time
}

// Find out what nodes contain the given blobs.
func (c Client) GetBlobInfos(oids ...string) (map[string]BlobInfo, error) {
	u := c.URLFor("/.cbfs/blob/info/")
	form := url.Values{"blob": oids}
	res, err := http.PostForm(u, form)
	if err != nil {
		return nil, err
	}
	defer res.Body.Close()
	if res.StatusCode != 200 {
		return nil, fmt.Errorf("HTTP error fetching blob info: %v",
			res.Status)
	}

	d := json.NewDecoder(res.Body)
	rv := map[string]BlobInfo{}
	err = d.Decode(&rv)
	return rv, err
}

type fetchWork struct {
	oid string
	bi  BlobInfo
}

type brokenReader struct{ err error }

func (b brokenReader) Read([]byte) (int, error) {
	return 0, b.err
}

type fetchWorker struct {
	n  StorageNode
	cb FetchCallback
}

func (fw fetchWorker) Work(i interface{}) error {
	oid := i.(string)
	res, err := http.Get(fw.n.BlobURL(oid))
	if err != nil {
		return err
	}
	defer res.Body.Close()
	if res.StatusCode != 200 {
		return fmt.Errorf("HTTP error: %v", res.Status)
	}
	return fw.cb(oid, res.Body)
}

// Fetch many blobs in bulk.
func (c *Client) Blobs(totalConcurrency, destinationConcurrency int,
	cb FetchCallback, oids ...string) error {

	nodeMap, err := c.Nodes()
	if err != nil {
		return err
	}

	dests := make([]string, 0, len(nodeMap))
	for n := range nodeMap {
		dests = append(dests, n)
	}

	infos, err := c.GetBlobInfos(oids...)
	if err != nil {
		return err
	}

	workch := make(chan saturator.WorkInput)
	go func() {
		// Feed the blob (fanout) workers.
		for oid, info := range infos {
			nodes := []string{}
			for n := range info.Nodes {
				nodes = append(nodes, n)
			}
			workch <- saturator.WorkInput{Input: oid, Dests: nodes}
		}

		// Let everything know we're done.
		close(workch)
	}()

	s := saturator.New(dests, func(n string) saturator.Worker {
		return &fetchWorker{nodeMap[n], cb}
	},
		&saturator.Config{
			DestConcurrency:  destinationConcurrency,
			TotalConcurrency: totalConcurrency,
			Retries:          3,
		})

	return s.Saturate(workch)
}

// Grab a file.
//
// This ensures the request is coming directly from a node that
// already has the blob vs. proxying.
func (c Client) Get(path string) (io.ReadCloser, error) {
	req, err := http.NewRequest("GET", c.URLFor(path), nil)
	if err != nil {
		return nil, err
	}
	req.Header.Set("X-CBFS-LocalOnly", "true")

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		return nil, err
	}

	switch res.StatusCode {
	case 200:
		return res.Body, nil
	case 300:
		defer res.Body.Close()
		res, err = http.Get(res.Header.Get("Location"))
		if err != nil {
			return nil, err
		}
		return res.Body, nil
	default:
		defer res.Body.Close()
		return nil, fmt.Errorf("HTTP Error: %v", res.Status)
	}
}

// File info
type FileHandle struct {
	c      Client
	oid    string
	length int64
	header http.Header
	nodes  map[string]time.Time
}

// The nodes containing the files and the last time it was scrubed.
func (f *FileHandle) Nodes() map[string]time.Time {
	return f.nodes
}

// The headers from the file request.
func (f *FileHandle) Header() http.Header {
	return f.header
}

// Length of this file
func (f *FileHandle) Length() int64 {
	return f.length
}

// Implement io.ReaderAt
func (f *FileHandle) ReadAt(p []byte, off int64) (n int, err error) {
	end := int64(len(p)) + off
	if end > f.length {
		return 0, fmt.Errorf("Would seek past EOF")
	}

	nodes, err := f.c.Nodes()
	if err != nil {
		return 0, err
	}

	nodelist := []StorageNode{}
	for k := range nodes {
		if n, ok := nodes[k]; ok {
			nodelist = append(nodelist, n)
		}
	}

	u := nodelist[rand.Intn(len(nodelist))].BlobURL(f.oid)

	req, err := http.NewRequest("GET", u, nil)
	if err != nil {
		return 0, err
	}
	req.Header.Set("Range", fmt.Sprintf("bytes=%v-%v", off, end))
	res, err := http.DefaultClient.Do(req)
	if err != nil {
		return 0, err
	}
	defer res.Body.Close()
	if res.StatusCode != 206 {
		return 0, fmt.Errorf("Unexpected http response: %v", res.Status)
	}

	return io.ReadFull(res.Body, p)
}

// Get a reference to the file at the given path.
func (c Client) OpenFile(path string) (*FileHandle, error) {
	res, err := http.Head(c.URLFor(path))
	if err != nil {
		return nil, err
	}
	res.Body.Close()
	if res.StatusCode != 200 {
		return nil, fmt.Errorf("HTTP error: %v", res.Status)
	}

	h := res.Header.Get("etag")
	if h == "" {
		return nil, fmt.Errorf("No etag in response headers")
	}

	h = h[1 : len(h)-1]

	infos, err := c.GetBlobInfos(h)
	if err != nil {
		return nil, err
	}

	return &FileHandle{c, h, res.ContentLength, res.Header, infos[h].Nodes}, nil
}
<|endoftext|>


<commit_before>// Copyright 2016 The etcd Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package concurrency

import (
	"fmt"
	"sync"

	v3 "github.com/coreos/etcd/clientv3"
	pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
	"golang.org/x/net/context"
)

// Mutex implements the sync Locker interface with etcd
type Mutex struct {
	s *Session

	pfx   string
	myKey string
	myRev int64
	hdr   *pb.ResponseHeader
}

func NewMutex(s *Session, pfx string) *Mutex {
	return &Mutex{s, pfx + "/", "", -1, nil}
}

// Lock locks the mutex with a cancelable context. If the context is canceled
// while trying to acquire the lock, the mutex tries to clean its stale lock entry.
func (m *Mutex) Lock(ctx context.Context) error {
	s := m.s
	client := m.s.Client()

	m.myKey = fmt.Sprintf("%s%x", m.pfx, s.Lease())
	cmp := v3.Compare(v3.CreateRevision(m.myKey), "=", 0)
	// put self in lock waiters via myKey; oldest waiter holds lock
	put := v3.OpPut(m.myKey, "", v3.WithLease(s.Lease()))
	// reuse key in case this session already holds the lock
	get := v3.OpGet(m.myKey)
	resp, err := client.Txn(ctx).If(cmp).Then(put).Else(get).Commit()
	if err != nil {
		return err
	}
	m.myRev = resp.Header.Revision
	if !resp.Succeeded {
		m.myRev = resp.Responses[0].GetResponseRange().Kvs[0].CreateRevision
	}

	// wait for deletion revisions prior to myKey
	hdr, werr := waitDeletes(ctx, client, m.pfx, m.myRev-1)
	// release lock key if cancelled
	select {
	case <-ctx.Done():
		m.Unlock(client.Ctx())
	default:
		m.hdr = hdr
	}
	return werr
}

func (m *Mutex) Unlock(ctx context.Context) error {
	client := m.s.Client()
	if _, err := client.Delete(ctx, m.myKey); err != nil {
		return err
	}
	m.myKey = "\x00"
	m.myRev = -1
	return nil
}

func (m *Mutex) IsOwner() v3.Cmp {
	return v3.Compare(v3.CreateRevision(m.myKey), "=", m.myRev)
}

func (m *Mutex) Key() string { return m.myKey }

// Header is the response header received from etcd on acquiring the lock.
func (m *Mutex) Header() *pb.ResponseHeader { return m.hdr }

type lockerMutex struct{ *Mutex }

func (lm *lockerMutex) Lock() {
	client := lm.s.Client()
	if err := lm.Mutex.Lock(client.Ctx()); err != nil {
		panic(err)
	}
}
func (lm *lockerMutex) Unlock() {
	client := lm.s.Client()
	if err := lm.Mutex.Unlock(client.Ctx()); err != nil {
		panic(err)
	}
}

// NewLocker creates a sync.Locker backed by an etcd mutex.
func NewLocker(s *Session, pfx string) sync.Locker {
	return &lockerMutex{NewMutex(s, pfx)}
}
<commit_msg>concurrency: fetch current lock holder when creating waitlist key<commit_after>// Copyright 2016 The etcd Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package concurrency

import (
	"fmt"
	"sync"

	v3 "github.com/coreos/etcd/clientv3"
	pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
	"golang.org/x/net/context"
)

// Mutex implements the sync Locker interface with etcd
type Mutex struct {
	s *Session

	pfx   string
	myKey string
	myRev int64
	hdr   *pb.ResponseHeader
}

func NewMutex(s *Session, pfx string) *Mutex {
	return &Mutex{s, pfx + "/", "", -1, nil}
}

// Lock locks the mutex with a cancelable context. If the context is canceled
// while trying to acquire the lock, the mutex tries to clean its stale lock entry.
func (m *Mutex) Lock(ctx context.Context) error {
	s := m.s
	client := m.s.Client()

	m.myKey = fmt.Sprintf("%s%x", m.pfx, s.Lease())
	cmp := v3.Compare(v3.CreateRevision(m.myKey), "=", 0)
	// put self in lock waiters via myKey; oldest waiter holds lock
	put := v3.OpPut(m.myKey, "", v3.WithLease(s.Lease()))
	// reuse key in case this session already holds the lock
	get := v3.OpGet(m.myKey)
	// fetch current holder to complete uncontended path with only one RPC
	getOwner := v3.OpGet(m.pfx, v3.WithFirstCreate()...)
	resp, err := client.Txn(ctx).If(cmp).Then(put, getOwner).Else(get, getOwner).Commit()
	if err != nil {
		return err
	}
	m.myRev = resp.Header.Revision
	if !resp.Succeeded {
		m.myRev = resp.Responses[0].GetResponseRange().Kvs[0].CreateRevision
	}
	// if no key on prefix / the minimum rev is key, already hold the lock
	ownerKey := resp.Responses[1].GetResponseRange().Kvs
	if len(ownerKey) == 0 || ownerKey[0].CreateRevision == m.myRev {
		m.hdr = resp.Header
		return nil
	}

	// wait for deletion revisions prior to myKey
	hdr, werr := waitDeletes(ctx, client, m.pfx, m.myRev-1)
	// release lock key if cancelled
	select {
	case <-ctx.Done():
		m.Unlock(client.Ctx())
	default:
		m.hdr = hdr
	}
	return werr
}

func (m *Mutex) Unlock(ctx context.Context) error {
	client := m.s.Client()
	if _, err := client.Delete(ctx, m.myKey); err != nil {
		return err
	}
	m.myKey = "\x00"
	m.myRev = -1
	return nil
}

func (m *Mutex) IsOwner() v3.Cmp {
	return v3.Compare(v3.CreateRevision(m.myKey), "=", m.myRev)
}

func (m *Mutex) Key() string { return m.myKey }

// Header is the response header received from etcd on acquiring the lock.
func (m *Mutex) Header() *pb.ResponseHeader { return m.hdr }

type lockerMutex struct{ *Mutex }

func (lm *lockerMutex) Lock() {
	client := lm.s.Client()
	if err := lm.Mutex.Lock(client.Ctx()); err != nil {
		panic(err)
	}
}
func (lm *lockerMutex) Unlock() {
	client := lm.s.Client()
	if err := lm.Mutex.Unlock(client.Ctx()); err != nil {
		panic(err)
	}
}

// NewLocker creates a sync.Locker backed by an etcd mutex.
func NewLocker(s *Session, pfx string) sync.Locker {
	return &lockerMutex{NewMutex(s, pfx)}
}
<|endoftext|>


<commit_before>package mpb

import (
	"reflect"
	"testing"
)

func TestFillBar(t *testing.T) {
	s := newTestState(80, 60)
	tests := []struct {
		termWidth int
		barWidth  int
		want      []byte
	}{
		{
			termWidth: 1,
			barWidth:  60,
			want:      []byte{},
		},
		{
			termWidth: 2,
			barWidth:  60,
			want:      []byte("[]"),
		},
		{
			termWidth: 4,
			barWidth:  60,
			want:      []byte("[=>]"),
		},
		{
			termWidth: 6,
			barWidth:  60,
			want:      []byte("[==>-]"),
		},
		{
			termWidth: 8,
			barWidth:  60,
			want:      []byte("[====>-]"),
		},
		{
			termWidth: 80,
			barWidth:  60,
			want:      []byte("[===========================================>--------------]"),
		},
		{
			termWidth: 80,
			barWidth:  62,
			want:      []byte("[============================================>---------------]"),
		},
	}

	for _, test := range tests {
		s.width = test.barWidth
		got := draw(s, test.termWidth)
		if !reflect.DeepEqual(test.want, got) {
			t.Errorf("Want: %q, Got: %q\n", test.want, got)
		}
	}
}

func newTestState(total, current int64) *state {
	return &state{
		format:         barFmtRunes{'[', '=', '>', '-', ']'},
		total:          total,
		current:        current,
		trimLeftSpace:  true,
		trimRightSpace: true,
	}
}
<commit_msg>test update<commit_after>package mpb

import (
	"reflect"
	"testing"
)

func TestFillBar(t *testing.T) {
	tests := []struct {
		termWidth int
		barWidth  int
		total     int64
		current   int64
		barRefill *refill
		want      []byte
	}{
		{
			termWidth: 1,
			barWidth:  100,
			want:      []byte{},
		},
		{
			termWidth: 2,
			barWidth:  100,
			total:     100,
			current:   20,
			want:      []byte("[]"),
		},
		{
			termWidth: 20,
			barWidth:  100,
			total:     100,
			current:   20,
			want:      []byte("[==>---------------]"),
		},
		{
			termWidth: 50,
			barWidth:  100,
			total:     100,
			current:   20,
			want:      []byte("[========>---------------------------------------]"),
		},
		{
			termWidth: 100,
			barWidth:  100,
			total:     100,
			current:   40,
			want:      []byte("[======================================>-----------------------------------------------------------]"),
		},
		{
			termWidth: 100,
			barWidth:  100,
			total:     100,
			current:   40,
			barRefill: &refill{'+', 32},
			want:      []byte("[+++++++++++++++++++++++++++++++=======>-----------------------------------------------------------]"),
		},
		{
			termWidth: 100,
			barWidth:  100,
			total:     100,
			current:   99,
			want:      []byte("[=================================================================================================>]"),
		},
		{
			termWidth: 100,
			barWidth:  100,
			total:     100,
			current:   100,
			want:      []byte("[==================================================================================================]"),
		},
	}

	for _, test := range tests {
		s := newTestState()
		s.width = test.barWidth
		s.total = test.total
		s.current = test.current
		if test.barRefill != nil {
			s.refill = test.barRefill
		}
		got := draw(s, test.termWidth)
		if !reflect.DeepEqual(test.want, got) {
			t.Errorf("Want: %q, Got: %q\n", test.want, got)
		}
	}
}

func newTestState() *state {
	return &state{
		format:         barFmtRunes{'[', '=', '>', '-', ']'},
		trimLeftSpace:  true,
		trimRightSpace: true,
	}
}
<|endoftext|>