<commit_before>// Package tail implements tailing a log file.
//
// tail provides a channel on which log lines will be sent as string messages.
// one line in the log file is one message on the channel
package tail

import (
	"bufio"
	"encoding/json"
	"errors"
	"fmt"
	"math/rand"
	"os"
	"path/filepath"
	"strings"
	"sync"
	"time"

	"github.com/Sirupsen/logrus"
	"golang.org/x/sys/unix"

	"github.com/hpcloud/tail"
)

type RotateStyle int

const (
	// foo.log gets rotated to foo.log.1, new entries go to foo.log
	RotateStyleSyslog RotateStyle = iota
	// foo.log.OLDSTAMP gets closed, new entries go to foo.log.NEWSTAMP
	// NOT YET IMPLEMENTED
	RotateStyleTimestamp
)

type TailOptions struct {
	ReadFrom  string `long:"read_from" description:"Location in the file from which to start reading. Values: beginning, end, last. Last picks up where it left off, if the file has not been rotated, otherwise beginning." default:"last"`
	Stop      bool   `long:"stop" description:"Stop reading the file after reaching the end rather than continuing to tail."`
	StateFile string `long:"statefile" description:"File in which to store the last read position. Defaults to a file with the same path as the log file and the suffix .leash.state. If tailing multiple files, default is forced."`
}

// Statefile mechanics when ReadFrom is 'last'
// missing statefile => ReadFrom = end
// empty statefile => ReadFrom = end
// permission denied => WARN and ReadFrom = end
// invalid location (aka logfile's been rotated) => ReadFrom = beginning

type Config struct {
	// Path to the log file to tail
	Paths []string
	// Type of log rotation we expect on this file
	Type RotateStyle
	// Tail specific options
	Options TailOptions
}

// State is what's stored in a statefile
type State struct {
	INode  uint64 // the inode
	Offset int64
}

// GetSampledEntries wraps GetEntries and returns a channel that provides
// sampled entries
func GetSampledEntries(conf Config, sampleRate int) (chan string, error) {
	lines, err := GetEntries(conf)
	if err != nil {
		return nil, err
	}
	if sampleRate == 1 {
		return lines, nil
	}
	sampledLines := make(chan string)
	go func() {
		defer close(sampledLines)
		for line := range lines {
			if shouldSample(sampleRate) {
				sampledLines <- line
			} else {
				logrus.WithFields(logrus.Fields{
					"line": line,
				}).Debug("Sampler says skip this line")
			}
		}
	}()
	return sampledLines, nil
}

// shouldSample returns true if the line should be preserved
// false if it should be skipped
// if sampleRate is 5,
// on average one out of every 5 calls should return true
func shouldSample(sampleRate int) bool {
	if rand.Intn(sampleRate) == 0 {
		return true
	}
	return false
}

// GetEntries opens the log file, reading from the end. It sends one line
// at a time down the returned channel
func GetEntries(conf Config) (chan string, error) {
	if conf.Type != RotateStyleSyslog {
		return nil, errors.New("Only Syslog style rotation currently supported")
	}
	lines := make(chan string)
	var wg sync.WaitGroup
	defer func() {
		go func() {
			wg.Wait()
			close(lines)
		}()
	}()
	// handle reading from STDIN
	if conf.Paths[0] == "-" {
		return lines, tailStdIn(lines, &wg)
	}
	for _, filePath := range conf.Paths {
		if err := tailMultipleFiles(conf, filePath, lines, &wg); err != nil {
			return nil, err
		}
	}
	// close lines when all processors are done

	return lines, nil
}

func tailMultipleFiles(conf Config, filePath string, lines chan string, wg *sync.WaitGroup) error {
	files, err := filepath.Glob(filePath)
	if err != nil {
		return err
	}
	for _, file := range files {
		var realStateFile string
		if conf.Options.StateFile == "" {
			// force statefile to match globbed file
			baseName := strings.TrimSuffix(file, ".log")
			realStateFile = baseName + ".leash.state"
		}
		if err := tailSingleFile(conf, file, realStateFile, lines, wg); err != nil {
			return err
		}
	}
	return nil
}

func tailSingleFile(conf Config, file string, stateFile string, lines chan string, wg *sync.WaitGroup) error {
	// TODO report some metric to indicate whether we're keeping up with the
	// front of the file, of if it's being written faster than we can send
	// events

	// tail a real file
	var loc *tail.SeekInfo // 0 value means start at beginning
	var reOpen, follow bool = true, true
	switch conf.Options.ReadFrom {
	case "start", "beginning":
		// 0 value for tail.SeekInfo means start at beginning
	case "end":
		loc = &tail.SeekInfo{
			Offset: 0,
			Whence: 2,
		}
	case "last":
		loc = getStartLocation(stateFile, file)
	default:
		errMsg := fmt.Sprintf("unknown option to --read_from: %s",
			conf.Options.ReadFrom)
		return errors.New(errMsg)
	}
	if conf.Options.Stop {
		reOpen = false
		follow = false
	}
	tailConf := tail.Config{
		Location:  loc,
		ReOpen:    reOpen, // keep reading on rotation, aka tail -F
		MustExist: true,   // fail if log file doesn't exist
		Follow:    follow, // don't stop at EOF, aka tail -f
		Logger:    logrus.New(),
	}
	logrus.WithFields(logrus.Fields{
		"tailConf":  tailConf,
		"conf":      conf,
		"statefile": stateFile,
		"location":  loc,
	}).Debug("about to call tail.TailFile")
	t, err := tail.TailFile(file, tailConf)
	logrus.WithFields(logrus.Fields{"tail": t}).Debug("finished call to TailFile")
	if err != nil {
		return err
	}
	// TODO this only updates once/sec. On clean shutdown, make sure we write
	// one last time after stopping reading traffic.
	go updateStateFile(t, stateFile, file)
	wg.Add(1)
	go func() {
		for line := range t.Lines {
			if line.Err != nil {
				// skip errored lines
				continue
			}
			lines <- line.Text
		}
		wg.Done()
	}()
	return nil
}

// tailStdIn is a special case to tail STDIN without any of the
// fancy stuff that the tail module provides
func tailStdIn(lines chan string, wg *sync.WaitGroup) error {
	input := bufio.NewReader(os.Stdin)
	wg.Add(1)
	go func() {
		defer wg.Done()
		for {
			line, partialLine, err := input.ReadLine()
			if err != nil {
				logrus.Debug("stdin is closed")
				// bail when STDIN closes
				return
			}
			var parts []string
			parts = append(parts, string(line))
			for partialLine {
				line, partialLine, _ = input.ReadLine()
				parts = append(parts, string(line))
			}
			lines <- strings.Join(parts, "")
		}
	}()
	return nil
}

// getStartLocation reads the state file and creates an appropriate start
// location.  See details at the top of this file on how the loc is chosen.
func getStartLocation(stateFile string, logfile string) *tail.SeekInfo {
	beginning := &tail.SeekInfo{}
	end := &tail.SeekInfo{0, 2}
	fh, err := os.Open(stateFile)
	if err != nil {
		logrus.WithFields(logrus.Fields{
			"starting at": "end", "error": err,
		}).Debug("getStartLocation failed to open the statefile")
		return end
	}
	defer fh.Close()
	// read the contents of the state file (JSON)
	content := make([]byte, 1024)
	bytesRead, err := fh.Read(content)
	if err != nil {
		logrus.WithFields(logrus.Fields{
			"starting at": "end", "error": err,
		}).Debug("getStartLocation failed to read the statefile contents")
		return end
	}
	content = content[:bytesRead]
	// decode the contents of the statefile
	state := State{}
	if err := json.Unmarshal(content, &state); err != nil {
		logrus.WithFields(logrus.Fields{
			"starting at": "end", "error": err,
		}).Debug("getStartLocation failed to json decode the statefile")
		return end
	}
	// get the details of the existing log file
	logStat := unix.Stat_t{}
	if err := unix.Stat(logfile, &logStat); err != nil {
		logrus.WithFields(logrus.Fields{
			"starting at": "end", "error": err,
		}).Debug("getStartLocation failed to get unix.stat() on the logfile")
		return end
	}
	// compare inode numbers of the last-seen and existing log files
	if state.INode != logStat.Ino {
		logrus.WithFields(logrus.Fields{
			"starting at": "beginning", "error": err,
		}).Debug("getStartLocation found a different inode number for the logfile")
		// file's been rotated
		return beginning
	}
	logrus.WithFields(logrus.Fields{
		"starting at": state.Offset,
	}).Debug("getStartLocation seeking to offset in logfile")
	// we're good; start reading from the remembered state
	return &tail.SeekInfo{
		Offset: state.Offset,
		Whence: 0,
	}
}

// updateStateFile updates the state file once per second with the current
// values for the logfile's inode number and offset
func updateStateFile(t *tail.Tail, stateFile string, file string) {
	statefh, err := os.OpenFile(stateFile, os.O_RDWR|os.O_CREATE, 0644)
	if err != nil {
		logrus.WithFields(logrus.Fields{
			"logfile":   file,
			"statefile": stateFile,
		}).Warn("Failed to open statefile for writing. File location will not be saved.")
		return
	}
	ticker := time.NewTicker(time.Second)
	state := State{}
	for _ = range ticker.C {
		logStat := unix.Stat_t{}
		unix.Stat(file, &logStat)
		currentPos, err := t.Tell()
		if err != nil {
			continue
		}
		state.INode = logStat.Ino
		state.Offset = currentPos
		out, err := json.Marshal(state)
		if err != nil {
			continue
		}
		statefh.Truncate(0)
		out = append(out, '\n')
		statefh.WriteAt(out, 0)
		statefh.Sync()
	}
}
<commit_msg>adding poll option to see if that fixes the tailing bug<commit_after>// Package tail implements tailing a log file.
//
// tail provides a channel on which log lines will be sent as string messages.
// one line in the log file is one message on the channel
package tail

import (
	"bufio"
	"encoding/json"
	"errors"
	"fmt"
	"math/rand"
	"os"
	"path/filepath"
	"strings"
	"sync"
	"time"

	"github.com/Sirupsen/logrus"
	"golang.org/x/sys/unix"

	"github.com/hpcloud/tail"
)

type RotateStyle int

const (
	// foo.log gets rotated to foo.log.1, new entries go to foo.log
	RotateStyleSyslog RotateStyle = iota
	// foo.log.OLDSTAMP gets closed, new entries go to foo.log.NEWSTAMP
	// NOT YET IMPLEMENTED
	RotateStyleTimestamp
)

type TailOptions struct {
	ReadFrom  string `long:"read_from" description:"Location in the file from which to start reading. Values: beginning, end, last. Last picks up where it left off, if the file has not been rotated, otherwise beginning." default:"last"`
	Stop      bool   `long:"stop" description:"Stop reading the file after reaching the end rather than continuing to tail."`
	Poll      bool   `long:"poll" description:"use poll instead of inotify to tail files"`
	StateFile string `long:"statefile" description:"File in which to store the last read position. Defaults to a file with the same path as the log file and the suffix .leash.state. If tailing multiple files, default is forced."`
}

// Statefile mechanics when ReadFrom is 'last'
// missing statefile => ReadFrom = end
// empty statefile => ReadFrom = end
// permission denied => WARN and ReadFrom = end
// invalid location (aka logfile's been rotated) => ReadFrom = beginning

type Config struct {
	// Path to the log file to tail
	Paths []string
	// Type of log rotation we expect on this file
	Type RotateStyle
	// Tail specific options
	Options TailOptions
}

// State is what's stored in a statefile
type State struct {
	INode  uint64 // the inode
	Offset int64
}

// GetSampledEntries wraps GetEntries and returns a channel that provides
// sampled entries
func GetSampledEntries(conf Config, sampleRate int) (chan string, error) {
	lines, err := GetEntries(conf)
	if err != nil {
		return nil, err
	}
	if sampleRate == 1 {
		return lines, nil
	}
	sampledLines := make(chan string)
	go func() {
		defer close(sampledLines)
		for line := range lines {
			if shouldSample(sampleRate) {
				sampledLines <- line
			} else {
				logrus.WithFields(logrus.Fields{
					"line": line,
				}).Debug("Sampler says skip this line")
			}
		}
	}()
	return sampledLines, nil
}

// shouldSample returns true if the line should be preserved
// false if it should be skipped
// if sampleRate is 5,
// on average one out of every 5 calls should return true
func shouldSample(sampleRate int) bool {
	if rand.Intn(sampleRate) == 0 {
		return true
	}
	return false
}

// GetEntries opens the log file, reading from the end. It sends one line
// at a time down the returned channel
func GetEntries(conf Config) (chan string, error) {
	if conf.Type != RotateStyleSyslog {
		return nil, errors.New("Only Syslog style rotation currently supported")
	}
	lines := make(chan string)
	var wg sync.WaitGroup
	defer func() {
		go func() {
			wg.Wait()
			close(lines)
		}()
	}()
	// handle reading from STDIN
	if conf.Paths[0] == "-" {
		return lines, tailStdIn(lines, &wg)
	}
	for _, filePath := range conf.Paths {
		if err := tailMultipleFiles(conf, filePath, lines, &wg); err != nil {
			return nil, err
		}
	}
	// close lines when all processors are done

	return lines, nil
}

func tailMultipleFiles(conf Config, filePath string, lines chan string, wg *sync.WaitGroup) error {
	files, err := filepath.Glob(filePath)
	if err != nil {
		return err
	}
	for _, file := range files {
		var realStateFile string
		if conf.Options.StateFile == "" {
			// force statefile to match globbed file
			baseName := strings.TrimSuffix(file, ".log")
			realStateFile = baseName + ".leash.state"
		}
		if err := tailSingleFile(conf, file, realStateFile, lines, wg); err != nil {
			return err
		}
	}
	return nil
}

func tailSingleFile(conf Config, file string, stateFile string, lines chan string, wg *sync.WaitGroup) error {
	// TODO report some metric to indicate whether we're keeping up with the
	// front of the file, of if it's being written faster than we can send
	// events

	// tail a real file
	var loc *tail.SeekInfo // 0 value means start at beginning
	var reOpen, follow bool = true, true
	switch conf.Options.ReadFrom {
	case "start", "beginning":
		// 0 value for tail.SeekInfo means start at beginning
	case "end":
		loc = &tail.SeekInfo{
			Offset: 0,
			Whence: 2,
		}
	case "last":
		loc = getStartLocation(stateFile, file)
	default:
		errMsg := fmt.Sprintf("unknown option to --read_from: %s",
			conf.Options.ReadFrom)
		return errors.New(errMsg)
	}
	if conf.Options.Stop {
		reOpen = false
		follow = false
	}
	tailConf := tail.Config{
		Location:  loc,
		ReOpen:    reOpen, // keep reading on rotation, aka tail -F
		MustExist: true,   // fail if log file doesn't exist
		Follow:    follow, // don't stop at EOF, aka tail -f
		Logger:    logrus.New(),
		Poll:      conf.Options.Poll, // use poll instead of inotify
	}
	logrus.WithFields(logrus.Fields{
		"tailConf":  tailConf,
		"conf":      conf,
		"statefile": stateFile,
		"location":  loc,
	}).Debug("about to call tail.TailFile")
	t, err := tail.TailFile(file, tailConf)
	logrus.WithFields(logrus.Fields{"tail": t}).Debug("finished call to TailFile")
	if err != nil {
		return err
	}
	// TODO this only updates once/sec. On clean shutdown, make sure we write
	// one last time after stopping reading traffic.
	go updateStateFile(t, stateFile, file)
	wg.Add(1)
	go func() {
		for line := range t.Lines {
			if line.Err != nil {
				// skip errored lines
				continue
			}
			lines <- line.Text
		}
		wg.Done()
	}()
	return nil
}

// tailStdIn is a special case to tail STDIN without any of the
// fancy stuff that the tail module provides
func tailStdIn(lines chan string, wg *sync.WaitGroup) error {
	input := bufio.NewReader(os.Stdin)
	wg.Add(1)
	go func() {
		defer wg.Done()
		for {
			line, partialLine, err := input.ReadLine()
			if err != nil {
				logrus.Debug("stdin is closed")
				// bail when STDIN closes
				return
			}
			var parts []string
			parts = append(parts, string(line))
			for partialLine {
				line, partialLine, _ = input.ReadLine()
				parts = append(parts, string(line))
			}
			lines <- strings.Join(parts, "")
		}
	}()
	return nil
}

// getStartLocation reads the state file and creates an appropriate start
// location.  See details at the top of this file on how the loc is chosen.
func getStartLocation(stateFile string, logfile string) *tail.SeekInfo {
	beginning := &tail.SeekInfo{}
	end := &tail.SeekInfo{0, 2}
	fh, err := os.Open(stateFile)
	if err != nil {
		logrus.WithFields(logrus.Fields{
			"starting at": "end", "error": err,
		}).Debug("getStartLocation failed to open the statefile")
		return end
	}
	defer fh.Close()
	// read the contents of the state file (JSON)
	content := make([]byte, 1024)
	bytesRead, err := fh.Read(content)
	if err != nil {
		logrus.WithFields(logrus.Fields{
			"starting at": "end", "error": err,
		}).Debug("getStartLocation failed to read the statefile contents")
		return end
	}
	content = content[:bytesRead]
	// decode the contents of the statefile
	state := State{}
	if err := json.Unmarshal(content, &state); err != nil {
		logrus.WithFields(logrus.Fields{
			"starting at": "end", "error": err,
		}).Debug("getStartLocation failed to json decode the statefile")
		return end
	}
	// get the details of the existing log file
	logStat := unix.Stat_t{}
	if err := unix.Stat(logfile, &logStat); err != nil {
		logrus.WithFields(logrus.Fields{
			"starting at": "end", "error": err,
		}).Debug("getStartLocation failed to get unix.stat() on the logfile")
		return end
	}
	// compare inode numbers of the last-seen and existing log files
	if state.INode != logStat.Ino {
		logrus.WithFields(logrus.Fields{
			"starting at": "beginning", "error": err,
		}).Debug("getStartLocation found a different inode number for the logfile")
		// file's been rotated
		return beginning
	}
	logrus.WithFields(logrus.Fields{
		"starting at": state.Offset,
	}).Debug("getStartLocation seeking to offset in logfile")
	// we're good; start reading from the remembered state
	return &tail.SeekInfo{
		Offset: state.Offset,
		Whence: 0,
	}
}

// updateStateFile updates the state file once per second with the current
// values for the logfile's inode number and offset
func updateStateFile(t *tail.Tail, stateFile string, file string) {
	statefh, err := os.OpenFile(stateFile, os.O_RDWR|os.O_CREATE, 0644)
	if err != nil {
		logrus.WithFields(logrus.Fields{
			"logfile":   file,
			"statefile": stateFile,
		}).Warn("Failed to open statefile for writing. File location will not be saved.")
		return
	}
	ticker := time.NewTicker(time.Second)
	state := State{}
	for _ = range ticker.C {
		logStat := unix.Stat_t{}
		unix.Stat(file, &logStat)
		currentPos, err := t.Tell()
		if err != nil {
			continue
		}
		state.INode = logStat.Ino
		state.Offset = currentPos
		out, err := json.Marshal(state)
		if err != nil {
			continue
		}
		statefh.Truncate(0)
		out = append(out, '\n')
		statefh.WriteAt(out, 0)
		statefh.Sync()
	}
}
<|endoftext|>


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

package main

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

var cmdClean = &Command{
	UsageLine: "clean [-i] [-r] [-n] [-x] [packages]",
	Short:     "remove object files",
	Long: `
Clean removes object files from package source directories.
The go command builds most objects in a temporary directory,
so go clean is mainly concerned with object files left by other
tools or by manual invocations of go build.

Specifically, clean removes the following files from each of the
source directories corresponding to the import paths:

	_obj/            old object directory, left from Makefiles
	_test/           old test directory, left from Makefiles
	_testmain.go     old gotest file, left from Makefiles
	test.out         old test log, left from Makefiles
	build.out        old test log, left from Makefiles
	*.[568ao]        object files, left from Makefiles

	DIR(.exe)        from go build
	DIR.test(.exe)   from go test -c
	MAINFILE(.exe)   from go build MAINFILE.go
	*.so             from SWIG

In the list, DIR represents the final path element of the
directory, and MAINFILE is the base name of any Go source
file in the directory that is not included when building
the package.

The -i flag causes clean to remove the corresponding installed
archive or binary (what 'go install' would create).

The -n flag causes clean to print the remove commands it would execute,
but not run them.

The -r flag causes clean to be applied recursively to all the
dependencies of the packages named by the import paths.

The -x flag causes clean to print remove commands as it executes them.

For more about specifying packages, see 'go help packages'.
	`,
}

var cleanI bool // clean -i flag
var cleanN bool // clean -n flag
var cleanR bool // clean -r flag
var cleanX bool // clean -x flag

func init() {
	// break init cycle
	cmdClean.Run = runClean

	cmdClean.Flag.BoolVar(&cleanI, "i", false, "")
	cmdClean.Flag.BoolVar(&cleanN, "n", false, "")
	cmdClean.Flag.BoolVar(&cleanR, "r", false, "")
	cmdClean.Flag.BoolVar(&cleanX, "x", false, "")
}

func runClean(cmd *Command, args []string) {
	for _, pkg := range packagesAndErrors(args) {
		clean(pkg)
	}
}

var cleaned = map[*Package]bool{}

// TODO: These are dregs left by Makefile-based builds.
// Eventually, can stop deleting these.
var cleanDir = map[string]bool{
	"_test": true,
	"_obj":  true,
}

var cleanFile = map[string]bool{
	"_testmain.go": true,
	"test.out":     true,
	"build.out":    true,
	"a.out":        true,
}

var cleanExt = map[string]bool{
	".5":  true,
	".6":  true,
	".8":  true,
	".a":  true,
	".o":  true,
	".so": true,
}

func clean(p *Package) {
	if cleaned[p] {
		return
	}
	if p.Dir == "" {
		errorf("can't load package: %v", p.Error)
		return
	}
	dirs, err := ioutil.ReadDir(p.Dir)
	if err != nil {
		errorf("go clean %s: %v", p.Dir, err)
		return
	}

	var b builder
	b.print = fmt.Print

	packageFile := map[string]bool{}
	if p.Name != "main" {
		// Record which files are not in package main.
		// The others are.
		keep := func(list []string) {
			for _, f := range list {
				packageFile[f] = true
			}
		}
		keep(p.GoFiles)
		keep(p.CgoFiles)
		keep(p.TestGoFiles)
		keep(p.XTestGoFiles)
	}

	_, elem := filepath.Split(p.Dir)
	allRemove := []string{
		elem,
		elem + ".exe",
		elem + ".test",
		elem + ".test.exe",
	}
	for _, dir := range dirs {
		name := dir.Name()
		if packageFile[name] {
			continue
		}
		if !dir.IsDir() && strings.HasSuffix(name, ".go") {
			base := name[:len(name)-len(".go")]
			allRemove = append(allRemove, base, base+".exe")
		}
	}
	if cleanN || cleanX {
		b.showcmd(p.Dir, "rm -f %s", strings.Join(allRemove, " "))
	}

	toRemove := map[string]bool{}
	for _, name := range allRemove {
		toRemove[name] = true
	}
	for _, dir := range dirs {
		name := dir.Name()
		if dir.IsDir() {
			// TODO: Remove once Makefiles are forgotten.
			if cleanDir[name] {
				if cleanN || cleanX {
					b.showcmd(p.Dir, "rm -r %s", name)
					if cleanN {
						continue
					}
				}
				os.RemoveAll(filepath.Join(p.Dir, name))
			}
			continue
		}

		if cleanN {
			continue
		}

		if cleanFile[name] || cleanExt[filepath.Ext(name)] || toRemove[name] {
			os.Remove(filepath.Join(p.Dir, name))
		}
	}

	if cleanI && p.target != "" {
		if cleanN || cleanX {
			b.showcmd("", "rm -f %s", p.target)
		}
		if !cleanN {
			os.Remove(p.target)
		}
	}

	if cleanI && p.usesSwig() {
		for _, f := range stringList(p.SwigFiles, p.SwigCXXFiles) {
			dir := p.swigDir(&buildContext)
			soname := p.swigSoname(f)
			target := filepath.Join(dir, soname)
			if cleanN || cleanX {
				b.showcmd("", "rm -f %s", target)
			}
			if !cleanN {
				os.Remove(target)
			}
		}
	}

	if cleanR {
		for _, p1 := range p.imports {
			clean(p1)
		}
	}
}
<commit_msg>cmd/go: don't ignore error when 'go clean'         Fixes issue 4208.<commit_after>// Copyright 2012 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

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

var cmdClean = &Command{
	UsageLine: "clean [-i] [-r] [-n] [-x] [packages]",
	Short:     "remove object files",
	Long: `
Clean removes object files from package source directories.
The go command builds most objects in a temporary directory,
so go clean is mainly concerned with object files left by other
tools or by manual invocations of go build.

Specifically, clean removes the following files from each of the
source directories corresponding to the import paths:

	_obj/            old object directory, left from Makefiles
	_test/           old test directory, left from Makefiles
	_testmain.go     old gotest file, left from Makefiles
	test.out         old test log, left from Makefiles
	build.out        old test log, left from Makefiles
	*.[568ao]        object files, left from Makefiles

	DIR(.exe)        from go build
	DIR.test(.exe)   from go test -c
	MAINFILE(.exe)   from go build MAINFILE.go
	*.so             from SWIG

In the list, DIR represents the final path element of the
directory, and MAINFILE is the base name of any Go source
file in the directory that is not included when building
the package.

The -i flag causes clean to remove the corresponding installed
archive or binary (what 'go install' would create).

The -n flag causes clean to print the remove commands it would execute,
but not run them.

The -r flag causes clean to be applied recursively to all the
dependencies of the packages named by the import paths.

The -x flag causes clean to print remove commands as it executes them.

For more about specifying packages, see 'go help packages'.
	`,
}

var cleanI bool // clean -i flag
var cleanN bool // clean -n flag
var cleanR bool // clean -r flag
var cleanX bool // clean -x flag

func init() {
	// break init cycle
	cmdClean.Run = runClean

	cmdClean.Flag.BoolVar(&cleanI, "i", false, "")
	cmdClean.Flag.BoolVar(&cleanN, "n", false, "")
	cmdClean.Flag.BoolVar(&cleanR, "r", false, "")
	cmdClean.Flag.BoolVar(&cleanX, "x", false, "")
}

func runClean(cmd *Command, args []string) {
	for _, pkg := range packagesAndErrors(args) {
		clean(pkg)
	}
}

var cleaned = map[*Package]bool{}

// TODO: These are dregs left by Makefile-based builds.
// Eventually, can stop deleting these.
var cleanDir = map[string]bool{
	"_test": true,
	"_obj":  true,
}

var cleanFile = map[string]bool{
	"_testmain.go": true,
	"test.out":     true,
	"build.out":    true,
	"a.out":        true,
}

var cleanExt = map[string]bool{
	".5":  true,
	".6":  true,
	".8":  true,
	".a":  true,
	".o":  true,
	".so": true,
}

func clean(p *Package) {
	if cleaned[p] {
		return
	}
	if p.Dir == "" {
		errorf("can't load package: %v", p.Error)
		return
	}
	dirs, err := ioutil.ReadDir(p.Dir)
	if err != nil {
		errorf("go clean %s: %v", p.Dir, err)
		return
	}

	var b builder
	b.print = fmt.Print

	packageFile := map[string]bool{}
	if p.Name != "main" {
		// Record which files are not in package main.
		// The others are.
		keep := func(list []string) {
			for _, f := range list {
				packageFile[f] = true
			}
		}
		keep(p.GoFiles)
		keep(p.CgoFiles)
		keep(p.TestGoFiles)
		keep(p.XTestGoFiles)
	}

	_, elem := filepath.Split(p.Dir)
	allRemove := []string{
		elem,
		elem + ".exe",
		elem + ".test",
		elem + ".test.exe",
	}
	for _, dir := range dirs {
		name := dir.Name()
		if packageFile[name] {
			continue
		}
		if !dir.IsDir() && strings.HasSuffix(name, ".go") {
			base := name[:len(name)-len(".go")]
			allRemove = append(allRemove, base, base+".exe")
		}
	}
	if cleanN || cleanX {
		b.showcmd(p.Dir, "rm -f %s", strings.Join(allRemove, " "))
	}

	toRemove := map[string]bool{}
	for _, name := range allRemove {
		toRemove[name] = true
	}
	for _, dir := range dirs {
		name := dir.Name()
		if dir.IsDir() {
			// TODO: Remove once Makefiles are forgotten.
			if cleanDir[name] {
				if cleanN || cleanX {
					b.showcmd(p.Dir, "rm -r %s", name)
					if cleanN {
						continue
					}
				}
				if err := os.RemoveAll(filepath.Join(p.Dir, name)); err != nil {
					errorf("go clean: %v", err)
				}
			}
			continue
		}

		if cleanN {
			continue
		}

		if cleanFile[name] || cleanExt[filepath.Ext(name)] || toRemove[name] {
			removeFile(filepath.Join(p.Dir, name))
		}
	}

	if cleanI && p.target != "" {
		if cleanN || cleanX {
			b.showcmd("", "rm -f %s", p.target)
		}
		if !cleanN {
			removeFile(p.target)
		}
	}

	if cleanI && p.usesSwig() {
		for _, f := range stringList(p.SwigFiles, p.SwigCXXFiles) {
			dir := p.swigDir(&buildContext)
			soname := p.swigSoname(f)
			target := filepath.Join(dir, soname)
			if cleanN || cleanX {
				b.showcmd("", "rm -f %s", target)
			}
			if !cleanN {
				removeFile(target)
			}
		}
	}

	if cleanR {
		for _, p1 := range p.imports {
			clean(p1)
		}
	}
}

// removeFile tries to remove file f, if error other than file doesn't exist
// occurs, it will report the error.
func removeFile(f string) {
	if err := os.Remove(f); err != nil && !os.IsNotExist(err) {
		errorf("go clean: %v", err)
	}
}
<|endoftext|>


<commit_before>// Package implementing methods: flickr.photosets.*
package photosets

import (
	"strconv"

	"github.com/masci/flickr.go/flickr"
)

type Photoset struct {
	Id                string `xml:"id,attr"`
	Primary           string `xml:"primary,attr"`
	Secret            string `xml:"secret,attr"`
	Server            string `xml:"server,attr"`
	Farm              string `xml:"farm,attr"`
	Photos            int    `xml:"photos,attr"`
	Videos            int    `xml:"videos,attr"`
	NeedsInterstitial bool   `xml:"needs_interstitial,attr"`
	VisCanSeeSet      bool   `xml:"visibility_can_see_set,attr"`
	CountViews        int    `xml:"count_views,attr"`
	CountComments     int    `xml:"count_comments,attr"`
	CanComment        bool   `xml:"can_comment,attr"`
	DateCreate        int    `xml:"date_create,attr"`
	DateUpdate        int    `xml:"date_update,attr"`
	Title             string `xml:"title"`
	Description       string `xml:"description"`
	Url               string `xml:"url,attr"`
}

type Photo struct {
	Id    string `xml:"id,attr"`
	Title string `xml:"title,attr"`
}

type PhotosetsListResponse struct {
	flickr.BasicResponse
	Photosets struct {
		Page    int        `xml:"page,attr"`
		Pages   int        `xml:"pages,attr"`
		Perpage int        `xml:"perpage,attr"`
		Total   int        `xml:"total,attr"`
		Items   []Photoset `xml:"photoset"`
	} `xml:"photosets"`
}

type PhotosetResponse struct {
	flickr.BasicResponse
	Set Photoset `xml:"photoset"`
}

type PhotosListResponse struct {
	flickr.BasicResponse
	Photoset struct {
		Page    int     `xml:"page,attr"`
		Pages   int     `xml:"pages,attr"`
		Perpage int     `xml:"perpage,attr"`
		Total   int     `xml:"total,attr"`
		Photos  []Photo `xml:"photo"`
	} `xml:"photoset"`
}

// Return all the photosets belonging to the caller user
// This call must be authenticated to get both public and private sets
func GetOwnList(client *flickr.FlickrClient) (*PhotosetsListResponse, error) {
	client.Init()
	client.Args.Set("method", "flickr.photosets.getList")

	client.ApiSign()

	response := &PhotosetsListResponse{}
	err := flickr.DoGet(client, response)
	return response, err
}

// Return the public sets belonging to the user with userId
// This method does not require authentication.
func GetList(client *flickr.FlickrClient, userId string) (*PhotosetsListResponse, error) {
	client.Init()
	client.Args.Set("method", "flickr.photosets.getList")
	client.Args.Set("user_id", userId)

	response := &PhotosetsListResponse{}
	err := flickr.DoGet(client, response)
	return response, err
}

// Add a photo to a photoset
// This method requires authentication with 'write' permission.
func AddPhoto(client *flickr.FlickrClient, photosetId, photoId string) (*flickr.BasicResponse, error) {
	client.Init()
	client.HTTPVerb = "POST"
	client.SetOAuthDefaults()
	client.Args.Set("method", "flickr.photosets.addPhoto")
	client.Args.Set("photoset_id", photosetId)
	client.Args.Set("photo_id", photoId)

	client.OAuthSign()

	response := &flickr.BasicResponse{}
	err := flickr.DoPost(client, response)
	return response, err
}

// Create a photoset specifying its primary photo
// This method requires authentication with 'write' permission.
func Create(client *flickr.FlickrClient, title, description, primaryPhotoId string) (*PhotosetResponse, error) {
	client.Init()
	client.HTTPVerb = "POST"
	client.SetOAuthDefaults()
	client.Args.Set("method", "flickr.photosets.create")
	client.Args.Set("title", title)
	client.Args.Set("description", description)
	client.Args.Set("primary_photo_id", primaryPhotoId)

	client.OAuthSign()

	response := &PhotosetResponse{}
	err := flickr.DoPost(client, response)
	return response, err
}

// Delete a photoset
// This method requires authentication with 'write' permission.
func Delete(client *flickr.FlickrClient, photosetId string) (*flickr.BasicResponse, error) {
	client.Init()
	client.HTTPVerb = "POST"
	client.SetOAuthDefaults()
	client.Args.Set("method", "flickr.photosets.delete")
	client.Args.Set("photoset_id", photosetId)

	client.OAuthSign()

	response := &flickr.BasicResponse{}
	err := flickr.DoPost(client, response)
	return response, err
}

// Remove a photo from a photoset
// This method requires authentication with 'write' permission.
func RemovePhoto(client *flickr.FlickrClient, photosetId, photoId string) (*flickr.BasicResponse, error) {
	client.Init()
	client.HTTPVerb = "POST"
	client.SetOAuthDefaults()
	client.Args.Set("method", "flickr.photosets.removePhoto")
	client.Args.Set("photoset_id", photosetId)
	client.Args.Set("photo_id", photoId)

	client.OAuthSign()

	response := &flickr.BasicResponse{}
	err := flickr.DoPost(client, response)
	return response, err
}

// Get the photos in a set
// This method does not require authentication.
func GetPhotos(client *flickr.FlickrClient, photosetId, userID string, page int) (*PhotosListResponse, error) {
	client.Init()
	client.Args.Set("method", "flickr.photosets.getList")
	client.Args.Set("photoset_id", "photosetId")
	if userID == "" {
		// userID = myuserid TODO
	}
	if page > 1 {
		client.Args.Set("page", strconv.Itoa(page))
	}
	client.Args.Set("user_id", "userID")
}
<commit_msg>temporary fixing build<commit_after>// Package implementing methods: flickr.photosets.*
package photosets

import (
	"strconv"

	"github.com/masci/flickr.go/flickr"
)

type Photoset struct {
	Id                string `xml:"id,attr"`
	Primary           string `xml:"primary,attr"`
	Secret            string `xml:"secret,attr"`
	Server            string `xml:"server,attr"`
	Farm              string `xml:"farm,attr"`
	Photos            int    `xml:"photos,attr"`
	Videos            int    `xml:"videos,attr"`
	NeedsInterstitial bool   `xml:"needs_interstitial,attr"`
	VisCanSeeSet      bool   `xml:"visibility_can_see_set,attr"`
	CountViews        int    `xml:"count_views,attr"`
	CountComments     int    `xml:"count_comments,attr"`
	CanComment        bool   `xml:"can_comment,attr"`
	DateCreate        int    `xml:"date_create,attr"`
	DateUpdate        int    `xml:"date_update,attr"`
	Title             string `xml:"title"`
	Description       string `xml:"description"`
	Url               string `xml:"url,attr"`
}

type Photo struct {
	Id    string `xml:"id,attr"`
	Title string `xml:"title,attr"`
}

type PhotosetsListResponse struct {
	flickr.BasicResponse
	Photosets struct {
		Page    int        `xml:"page,attr"`
		Pages   int        `xml:"pages,attr"`
		Perpage int        `xml:"perpage,attr"`
		Total   int        `xml:"total,attr"`
		Items   []Photoset `xml:"photoset"`
	} `xml:"photosets"`
}

type PhotosetResponse struct {
	flickr.BasicResponse
	Set Photoset `xml:"photoset"`
}

type PhotosListResponse struct {
	flickr.BasicResponse
	Photoset struct {
		Page    int     `xml:"page,attr"`
		Pages   int     `xml:"pages,attr"`
		Perpage int     `xml:"perpage,attr"`
		Total   int     `xml:"total,attr"`
		Photos  []Photo `xml:"photo"`
	} `xml:"photoset"`
}

// Return all the photosets belonging to the caller user
// This call must be authenticated to get both public and private sets
func GetOwnList(client *flickr.FlickrClient) (*PhotosetsListResponse, error) {
	client.Init()
	client.Args.Set("method", "flickr.photosets.getList")

	client.ApiSign()

	response := &PhotosetsListResponse{}
	err := flickr.DoGet(client, response)
	return response, err
}

// Return the public sets belonging to the user with userId
// This method does not require authentication.
func GetList(client *flickr.FlickrClient, userId string) (*PhotosetsListResponse, error) {
	client.Init()
	client.Args.Set("method", "flickr.photosets.getList")
	client.Args.Set("user_id", userId)

	response := &PhotosetsListResponse{}
	err := flickr.DoGet(client, response)
	return response, err
}

// Add a photo to a photoset
// This method requires authentication with 'write' permission.
func AddPhoto(client *flickr.FlickrClient, photosetId, photoId string) (*flickr.BasicResponse, error) {
	client.Init()
	client.HTTPVerb = "POST"
	client.SetOAuthDefaults()
	client.Args.Set("method", "flickr.photosets.addPhoto")
	client.Args.Set("photoset_id", photosetId)
	client.Args.Set("photo_id", photoId)

	client.OAuthSign()

	response := &flickr.BasicResponse{}
	err := flickr.DoPost(client, response)
	return response, err
}

// Create a photoset specifying its primary photo
// This method requires authentication with 'write' permission.
func Create(client *flickr.FlickrClient, title, description, primaryPhotoId string) (*PhotosetResponse, error) {
	client.Init()
	client.HTTPVerb = "POST"
	client.SetOAuthDefaults()
	client.Args.Set("method", "flickr.photosets.create")
	client.Args.Set("title", title)
	client.Args.Set("description", description)
	client.Args.Set("primary_photo_id", primaryPhotoId)

	client.OAuthSign()

	response := &PhotosetResponse{}
	err := flickr.DoPost(client, response)
	return response, err
}

// Delete a photoset
// This method requires authentication with 'write' permission.
func Delete(client *flickr.FlickrClient, photosetId string) (*flickr.BasicResponse, error) {
	client.Init()
	client.HTTPVerb = "POST"
	client.SetOAuthDefaults()
	client.Args.Set("method", "flickr.photosets.delete")
	client.Args.Set("photoset_id", photosetId)

	client.OAuthSign()

	response := &flickr.BasicResponse{}
	err := flickr.DoPost(client, response)
	return response, err
}

// Remove a photo from a photoset
// This method requires authentication with 'write' permission.
func RemovePhoto(client *flickr.FlickrClient, photosetId, photoId string) (*flickr.BasicResponse, error) {
	client.Init()
	client.HTTPVerb = "POST"
	client.SetOAuthDefaults()
	client.Args.Set("method", "flickr.photosets.removePhoto")
	client.Args.Set("photoset_id", photosetId)
	client.Args.Set("photo_id", photoId)

	client.OAuthSign()

	response := &flickr.BasicResponse{}
	err := flickr.DoPost(client, response)
	return response, err
}

// Get the photos in a set
// This method does not require authentication.
func GetPhotos(client *flickr.FlickrClient, photosetId, userID string, page int) (*PhotosListResponse, error) {
	client.Init()
	client.Args.Set("method", "flickr.photosets.getList")
	client.Args.Set("photoset_id", "photosetId")
	// this argument is optional but increases query performances
	if userID == "" {
		// userID = myuserid TODO
	}
	// if not provided, flickr defaults this argument to 1
	if page > 1 {
		client.Args.Set("page", strconv.Itoa(page))
	}
	client.Args.Set("user_id", "userID")

	return nil, nil
}
<|endoftext|>


<commit_before>package awsdns

import (
	"bytes"
	"crypto/hmac"
	"crypto/sha256"
	"encoding/base64"
	"encoding/xml"
	"fmt"
	auth "github.com/scorelab/gocloud-v2/auth"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"reflect"
	"strings"
	"time"
)

func multimap(p map[string]string) url.Values {
	q := make(url.Values, len(p))
	for k, v := range p {
		q[k] = []string{v}
	}
	return q
}

func CleanZoneID(ID string) string {
	if strings.HasPrefix(ID, "/hostedzone/") {
		ID = strings.TrimPrefix(ID, "/hostedzone/")
	}
	return ID
}

func (awsdns *Awsdns) PrepareSignatureV4query(method, path string, req, resp interface{}, response map[string]interface{}) error {
	params := make(map[string]string)
	endpoint, err := url.Parse("https://route53.amazonaws.com")
	if err != nil {
		return err
	}
	endpoint.Path = path
	sign(endpoint.Path, params)
	fmt.Println("params : ", params)

	if queryArgs, ok := req.(url.Values); ok {
		endpoint.RawQuery = queryArgs.Encode()
		req = nil
	}

	var body io.ReadWriter
	if req != nil {
		bodyBuf := bytes.NewBuffer(nil)
		enc := xml.NewEncoder(bodyBuf)
		start := xml.StartElement{
			Name: xml.Name{
				Space: "",
				Local: reflect.Indirect(reflect.ValueOf(req)).Type().Name(),
			},
			Attr: []xml.Attr{{xml.Name{"", "xmlns"}, "https://route53.amazonaws.com/doc/2013-04-01/"}},
		}
		if err := enc.EncodeElement(req, start); err != nil {
			return err
		}

		replace := "<ResourceRecords><ResourceRecord></ResourceRecord></ResourceRecords>"
		if strings.Contains(bodyBuf.String(), replace) {
			var newBuf bytes.Buffer
			newBuf.WriteString(strings.Replace(bodyBuf.String(), replace, "", -1))
			bodyBuf = &newBuf
		}

		if reflect.Indirect(reflect.ValueOf(req)).Type().Name() == "ChangeResourceRecordSetsRequest" {
			for _, change := range req.(ChangeResourceRecordSetsRequest).Changes {
				if change.Record.AliasTarget != nil {
					replace := change.Record.Type + "</Type><TTL>0</TTL>"
					var newBuf bytes.Buffer
					newBuf.WriteString(strings.Replace(bodyBuf.String(), replace, change.Record.Type+"</Type>", -1))
					bodyBuf = &newBuf
				}
			}
		}

		body = bodyBuf
	}

	hReq, err := http.NewRequest(method, endpoint.String(), body)
	if err != nil {
		return err
	}
	for k, v := range params {
		hReq.Header.Set(k, v)
	}
	client := new(http.Client)

	re, err := client.Do(hReq)
	if err != nil {
		return err
	}
	defer re.Body.Close()

	bodystring, _ := ioutil.ReadAll(re.Body)

	response["status"] = re.StatusCode
	response["body"] = string(bodystring)

	switch re.StatusCode {
	case 200:
	case 201:
	default:
		var body bytes.Buffer
		io.Copy(&body, re.Body)
		return fmt.Errorf("Request failed, got status code: %d. Response: %s",
			re.StatusCode, body.Bytes())
	}

	decoder := xml.NewDecoder(re.Body)
	return decoder.Decode(resp)
}

var b64 = base64.StdEncoding

func sign(path string, params map[string]string) {

	AccessKey := auth.Config.AWSAccessKeyID

	SecretKey := auth.Config.AWSSecretKey

	date := time.Now().In(time.UTC).Format(time.RFC1123)

	params["Date"] = date

	fmt.Println("SecretKey:", SecretKey)

	hash := hmac.New(sha256.New, []byte(SecretKey))

	hash.Write([]byte(date))

	signature := make([]byte, b64.EncodedLen(hash.Size()))

	b64.Encode(signature, hash.Sum(nil))

	fmt.Println("AccessKey:", AccessKey)

	header := fmt.Sprintf("AWS3-HTTPS AWSAccessKeyId=%s,Algorithm=HmacSHA256,Signature=%s", AccessKey, signature)

	params["X-Amzn-Authorization"] = string(header)

}
<commit_msg>gofmt<commit_after>package awsdns

import (
	"bytes"
	"crypto/hmac"
	"crypto/sha256"
	"encoding/base64"
	"encoding/xml"
	"fmt"
	auth "github.com/scorelab/gocloud-v2/auth"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"reflect"
	"strings"
	"time"
)

//multimap create map for parameters.
func multimap(p map[string]string) url.Values {
	q := make(url.Values, len(p))
	for k, v := range p {
		q[k] = []string{v}
	}
	return q
}

//CleanZoneID cleans zone ID.
func CleanZoneID(ID string) string {
	if strings.HasPrefix(ID, "/hostedzone/") {
		ID = strings.TrimPrefix(ID, "/hostedzone/")
	}
	return ID
}

//PrepareSignatureV4query prepare signatue for awsdns.
func (awsdns *Awsdns) PrepareSignatureV4query(method, path string, req, resp interface{}, response map[string]interface{}) error {
	params := make(map[string]string)
	endpoint, err := url.Parse("https://route53.amazonaws.com")
	if err != nil {
		return err
	}
	endpoint.Path = path
	sign(endpoint.Path, params)

	if queryArgs, ok := req.(url.Values); ok {
		endpoint.RawQuery = queryArgs.Encode()
		req = nil
	}

	var body io.ReadWriter
	if req != nil {
		bodyBuf := bytes.NewBuffer(nil)
		enc := xml.NewEncoder(bodyBuf)
		start := xml.StartElement{
			Name: xml.Name{
				Space: "",
				Local: reflect.Indirect(reflect.ValueOf(req)).Type().Name(),
			},
			Attr: []xml.Attr{{xml.Name{"", "xmlns"}, "https://route53.amazonaws.com/doc/2013-04-01/"}},
		}
		if err := enc.EncodeElement(req, start); err != nil {
			return err
		}

		replace := "<ResourceRecords><ResourceRecord></ResourceRecord></ResourceRecords>"
		if strings.Contains(bodyBuf.String(), replace) {
			var newBuf bytes.Buffer
			newBuf.WriteString(strings.Replace(bodyBuf.String(), replace, "", -1))
			bodyBuf = &newBuf
		}

		if reflect.Indirect(reflect.ValueOf(req)).Type().Name() == "ChangeResourceRecordSetsRequest" {
			for _, change := range req.(ChangeResourceRecordSetsRequest).Changes {
				if change.Record.AliasTarget != nil {
					replace := change.Record.Type + "</Type><TTL>0</TTL>"
					var newBuf bytes.Buffer
					newBuf.WriteString(strings.Replace(bodyBuf.String(), replace, change.Record.Type+"</Type>", -1))
					bodyBuf = &newBuf
				}
			}
		}

		body = bodyBuf
	}

	hReq, err := http.NewRequest(method, endpoint.String(), body)
	if err != nil {
		return err
	}
	for k, v := range params {
		hReq.Header.Set(k, v)
	}
	client := new(http.Client)

	re, err := client.Do(hReq)
	if err != nil {
		return err
	}
	defer re.Body.Close()

	bodystring, _ := ioutil.ReadAll(re.Body)

	response["status"] = re.StatusCode
	response["body"] = string(bodystring)

	switch re.StatusCode {
	case 200:
	case 201:
	default:
		var body bytes.Buffer
		io.Copy(&body, re.Body)
		return fmt.Errorf("Request failed, got status code: %d. Response: %s",
			re.StatusCode, body.Bytes())
	}

	decoder := xml.NewDecoder(re.Body)
	return decoder.Decode(resp)
}

//b64 represents base64.StdEncoding.
var b64 = base64.StdEncoding

// sign signs aws request.
func sign(path string, params map[string]string) {

	AccessKey := auth.Config.AWSAccessKeyID

	SecretKey := auth.Config.AWSSecretKey

	date := time.Now().In(time.UTC).Format(time.RFC1123)

	params["Date"] = date

	hash := hmac.New(sha256.New, []byte(SecretKey))

	hash.Write([]byte(date))

	signature := make([]byte, b64.EncodedLen(hash.Size()))

	b64.Encode(signature, hash.Sum(nil))

	header := fmt.Sprintf("AWS3-HTTPS AWSAccessKeyId=%s,Algorithm=HmacSHA256,Signature=%s", AccessKey, signature)

	params["X-Amzn-Authorization"] = string(header)

}
<|endoftext|>


<commit_before>package dmgo

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"time"
)

type gbsPlayer struct {
	cpuState
	Hdr              gbsHeader
	PlayCallInterval float64
	LastPlayCall     time.Time
	CurrentSong      byte
	CurrentSongStart time.Time
	Paused           bool
	PauseStartTime   time.Time
	DbgTerminal      dbgTerminal
	DbgScreen        [160 * 144 * 4]byte
}

func (gp *gbsPlayer) GetCartRAM() []byte { return nil }
func (gp *gbsPlayer) SetCartRAM(ram []byte) error {
	return fmt.Errorf("saves not implemented for GBSs")
}
func (gp *gbsPlayer) MakeSnapshot() []byte { return nil }
func (gp *gbsPlayer) LoadSnapshot(snapBytes []byte) (Emulator, error) {
	return nil, fmt.Errorf("snapshots not implemented for GBSs")
}

type gbsHeader struct {
	Magic           [3]byte
	Version         byte
	NumSongs        byte
	StartSong       byte
	LoadAddr        uint16
	InitAddr        uint16
	PlayAddr        uint16
	StackPtr        uint16
	TimerModulo     byte
	TimerControl    byte
	TitleString     [32]byte
	AuthorString    [32]byte
	CopyrightString [32]byte
}

func parseGbs(gbs []byte) (gbsHeader, []byte, error) {
	hdr := gbsHeader{}
	if err := readStructLE(gbs, &hdr); err != nil {
		return gbsHeader{}, nil, fmt.Errorf("gbs player error\n%s", err.Error())
	}
	if hdr.Version != 1 {
		return gbsHeader{}, nil, fmt.Errorf("gbs player error\nunsupported gbs version: %v", hdr.Version)
	}
	data := gbs[0x70:]
	return hdr, data, nil
}

func readStructLE(structBytes []byte, iface interface{}) error {
	return binary.Read(bytes.NewReader(structBytes), binary.LittleEndian, iface)
}

// NewGbsPlayer creates an gbsPlayer session
func NewGbsPlayer(gbs []byte) Emulator {

	var hdr gbsHeader
	var data []byte
	var err error
	hdr, data, err = parseGbs(gbs)
	if err != nil {
		return NewErrEmu(fmt.Sprintf("gbs player error\n%s", err.Error()))
	}

	cart := append(make([]byte, hdr.LoadAddr), data...)
	paddingNeeded := len(cart) % 16 * 1024
	if paddingNeeded != 0 {
		cart = append(cart, make([]byte, paddingNeeded)...)
	}

	gp := gbsPlayer{
		cpuState: cpuState{
			Mem: mem{
				mbc:                   &gbsMBC{},
				cart:                  cart,
				CartRAM:               make([]byte, 8192),
				InternalRAMBankNumber: 1,
			},
		},
		Hdr: hdr,
	}
	gp.DbgTerminal = dbgTerminal{w: 160, h: 144, screen: gp.DbgScreen[:]}

	fmt.Println("uses timer:", gp.usesTimer())

	timerMod := float64(gp.Hdr.TimerModulo)

	if gp.Hdr.TimerControl&0x80 > 0 {
		// correct all timers for our dmg timer speeds
		timerMod /= 2
		fmt.Println("GBC Speed Requested")
	}

	if gp.usesTimer() {
		counterRate := []float64{4096, 262144, 65536, 16384}[gp.Hdr.TimerControl&0x03]
		gp.PlayCallInterval = 1.0 / (counterRate / (256 - timerMod))
	} else {
		gp.PlayCallInterval = 1.0 / 59.7
	}

	gp.init()

	gp.patchRsts()

	gp.initTune(gp.Hdr.StartSong - 1)

	gp.updateScreen()

	return &gp
}

func (gp *gbsPlayer) usesTimer() bool {
	return gp.Hdr.TimerControl&0x04 == 0x04
}

func (gp *gbsPlayer) patchRsts() {
	addrs := []uint16{0x00, 0x08, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38}
	for _, addr := range addrs {
		newAddr := gp.Hdr.LoadAddr + addr
		patch := []byte{0xcd, byte(newAddr), byte(newAddr >> 8)}
		copy(gp.Mem.cart[addr:addr+3], patch)
	}
}

func (gp *gbsPlayer) initTune(songNum byte) {

	gp.F = 0
	gp.B, gp.C = 0, 0
	gp.D, gp.E = 0, 0
	gp.H, gp.L = 0, 0

	for i := uint16(0xa000); i < 0xfe00; i++ {
		gp.write(i, 0)
	}

	for i := uint16(0xff80); i < 0xffff; i++ {
		gp.write(i, 0)
	}

	gp.initIORegs()

	gp.APU.Sounds[0].RestartRequested = false
	gp.APU.Sounds[1].RestartRequested = false
	gp.APU.Sounds[2].RestartRequested = false
	gp.APU.Sounds[3].RestartRequested = false

	gp.A = songNum

	// force a call to INIT
	gp.SP = gp.Hdr.StackPtr
	gp.pushOp16(0, 0, 0x0130)
	gp.PC = gp.Hdr.InitAddr
	for gp.PC != 0x0130 {
		gp.step()
	}

	gp.CurrentSong = songNum
	gp.CurrentSongStart = time.Now()
}

func (gp *gbsPlayer) updateScreen() {

	gp.DbgTerminal.clearScreen()

	gp.DbgTerminal.setPos(0, 1)
	gp.DbgTerminal.writeString("GBS Player\n")
	gp.DbgTerminal.newline()
	gp.DbgTerminal.writeString(string(gp.Hdr.TitleString[:]) + "\n")
	gp.DbgTerminal.writeString(string(gp.Hdr.AuthorString[:]) + "\n")
	gp.DbgTerminal.writeString(string(gp.Hdr.CopyrightString[:]) + "\n")

	gp.DbgTerminal.newline()

	gp.DbgTerminal.writeString(fmt.Sprintf("Track %02d/%02d\n", gp.CurrentSong+1, gp.Hdr.NumSongs))

	nowTime := int(time.Now().Sub(gp.CurrentSongStart).Seconds())
	nowTimeStr := fmt.Sprintf("%02d:%02d", nowTime/60, nowTime%60)

	gp.DbgTerminal.writeString(fmt.Sprintf("%s", nowTimeStr))

	if gp.Paused {
		gp.DbgTerminal.writeString(" *PAUSED*\n")
	} else {
		gp.DbgTerminal.newline()
	}

	gp.LCD.FlipRequested = true
}

func (gp *gbsPlayer) prevSong() {
	if gp.CurrentSong > 0 {
		gp.CurrentSong--
		gp.initTune(gp.CurrentSong)
		gp.updateScreen()
	}
}
func (gp *gbsPlayer) nextSong() {
	if gp.CurrentSong < gp.Hdr.NumSongs-1 {
		gp.CurrentSong++
		gp.initTune(gp.CurrentSong)
		gp.updateScreen()
	}
}
func (gp *gbsPlayer) togglePause() {
	gp.Paused = !gp.Paused
	if gp.Paused {
		gp.PauseStartTime = time.Now()
	} else {
		gp.CurrentSongStart = gp.CurrentSongStart.Add(time.Now().Sub(gp.PauseStartTime))
	}
	gp.updateScreen()
}

var lastInput time.Time

func (gp *gbsPlayer) UpdateInput(input Input) {
	now := time.Now()
	if now.Sub(lastInput).Seconds() > 0.20 {
		if input.Joypad.Left {
			gp.prevSong()
			lastInput = now
		}
		if input.Joypad.Right {
			gp.nextSong()
			lastInput = now
		}
		if input.Joypad.Start {
			gp.togglePause()
			lastInput = now
		}
	}
}

var lastScreenUpdate time.Time

func (gp *gbsPlayer) Step() {
	if !gp.Paused {

		now := time.Now()
		if now.Sub(lastScreenUpdate) >= 100*time.Millisecond {
			lastScreenUpdate = now
			gp.updateScreen()
		}

		if gp.PC == 0x0130 {
			if now.Sub(gp.LastPlayCall).Seconds() > gp.PlayCallInterval {
				gp.LastPlayCall = now
				gp.SP = gp.Hdr.StackPtr
				gp.pushOp16(0, 0, 0x0130)
				gp.PC = gp.Hdr.PlayAddr
			}
		}

		if gp.PC != 0x0130 {
			gp.step()
		} else {
			gp.runCycles(4)
		}
	}
}

func (gp *gbsPlayer) ReadSoundBuffer(toFill []byte) []byte {
	buf := gp.APU.buffer.read(toFill)
	return buf
}

func (gp *gbsPlayer) Framebuffer() []byte {
	return gp.DbgScreen[:]
}
<commit_msg>Slight presentation improvement for gbs files<commit_after>package dmgo

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"strings"
	"time"
)

type gbsPlayer struct {
	cpuState
	Hdr              gbsHeader
	PlayCallInterval float64
	LastPlayCall     time.Time
	CurrentSong      byte
	CurrentSongStart time.Time
	Paused           bool
	PauseStartTime   time.Time
	DbgTerminal      dbgTerminal
	DbgScreen        [160 * 144 * 4]byte
}

func (gp *gbsPlayer) GetCartRAM() []byte { return nil }
func (gp *gbsPlayer) SetCartRAM(ram []byte) error {
	return fmt.Errorf("saves not implemented for GBSs")
}
func (gp *gbsPlayer) MakeSnapshot() []byte { return nil }
func (gp *gbsPlayer) LoadSnapshot(snapBytes []byte) (Emulator, error) {
	return nil, fmt.Errorf("snapshots not implemented for GBSs")
}

type gbsHeader struct {
	Magic           [3]byte
	Version         byte
	NumSongs        byte
	StartSong       byte
	LoadAddr        uint16
	InitAddr        uint16
	PlayAddr        uint16
	StackPtr        uint16
	TimerModulo     byte
	TimerControl    byte
	TitleString     [32]byte
	AuthorString    [32]byte
	CopyrightString [32]byte
}

func parseGbs(gbs []byte) (gbsHeader, []byte, error) {
	hdr := gbsHeader{}
	if err := readStructLE(gbs, &hdr); err != nil {
		return gbsHeader{}, nil, fmt.Errorf("gbs player error\n%s", err.Error())
	}
	if hdr.Version != 1 {
		return gbsHeader{}, nil, fmt.Errorf("gbs player error\nunsupported gbs version: %v", hdr.Version)
	}
	data := gbs[0x70:]
	return hdr, data, nil
}

func readStructLE(structBytes []byte, iface interface{}) error {
	return binary.Read(bytes.NewReader(structBytes), binary.LittleEndian, iface)
}

// NewGbsPlayer creates an gbsPlayer session
func NewGbsPlayer(gbs []byte) Emulator {

	var hdr gbsHeader
	var data []byte
	var err error
	hdr, data, err = parseGbs(gbs)
	if err != nil {
		return NewErrEmu(fmt.Sprintf("gbs player error\n%s", err.Error()))
	}

	cart := append(make([]byte, hdr.LoadAddr), data...)
	paddingNeeded := len(cart) % 16 * 1024
	if paddingNeeded != 0 {
		cart = append(cart, make([]byte, paddingNeeded)...)
	}

	gp := gbsPlayer{
		cpuState: cpuState{
			Mem: mem{
				mbc:                   &gbsMBC{},
				cart:                  cart,
				CartRAM:               make([]byte, 8192),
				InternalRAMBankNumber: 1,
			},
		},
		Hdr: hdr,
	}
	gp.DbgTerminal = dbgTerminal{w: 160, h: 144, screen: gp.DbgScreen[:]}

	fmt.Println("uses timer:", gp.usesTimer())

	timerMod := float64(gp.Hdr.TimerModulo)

	if gp.Hdr.TimerControl&0x80 > 0 {
		// correct all timers for our dmg timer speeds
		timerMod /= 2
		fmt.Println("GBC Speed Requested")
	}

	if gp.usesTimer() {
		counterRate := []float64{4096, 262144, 65536, 16384}[gp.Hdr.TimerControl&0x03]
		gp.PlayCallInterval = 1.0 / (counterRate / (256 - timerMod))
	} else {
		gp.PlayCallInterval = 1.0 / 59.7
	}

	gp.init()

	gp.patchRsts()

	gp.initTune(gp.Hdr.StartSong - 1)

	gp.updateScreen()

	return &gp
}

func (gp *gbsPlayer) usesTimer() bool {
	return gp.Hdr.TimerControl&0x04 == 0x04
}

func (gp *gbsPlayer) patchRsts() {
	addrs := []uint16{0x00, 0x08, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38}
	for _, addr := range addrs {
		newAddr := gp.Hdr.LoadAddr + addr
		patch := []byte{0xcd, byte(newAddr), byte(newAddr >> 8)}
		copy(gp.Mem.cart[addr:addr+3], patch)
	}
}

func (gp *gbsPlayer) initTune(songNum byte) {

	gp.F = 0
	gp.B, gp.C = 0, 0
	gp.D, gp.E = 0, 0
	gp.H, gp.L = 0, 0

	for i := uint16(0xa000); i < 0xfe00; i++ {
		gp.write(i, 0)
	}

	for i := uint16(0xff80); i < 0xffff; i++ {
		gp.write(i, 0)
	}

	gp.initIORegs()

	gp.APU.Sounds[0].RestartRequested = false
	gp.APU.Sounds[1].RestartRequested = false
	gp.APU.Sounds[2].RestartRequested = false
	gp.APU.Sounds[3].RestartRequested = false

	gp.A = songNum

	// force a call to INIT
	gp.SP = gp.Hdr.StackPtr
	gp.pushOp16(0, 0, 0x0130)
	gp.PC = gp.Hdr.InitAddr
	for gp.PC != 0x0130 {
		gp.step()
	}

	gp.CurrentSong = songNum
	gp.CurrentSongStart = time.Now()
}

func (gp *gbsPlayer) updateScreen() {

	gp.DbgTerminal.clearScreen()

	gp.DbgTerminal.setPos(0, 1)

	gp.DbgTerminal.writeString("GBS Player\n\n")
	gp.DbgTerminal.writeString(string(gp.Hdr.TitleString[:]) + "\n")
	gp.DbgTerminal.writeString(string(gp.Hdr.AuthorString[:]) + "\n")

	copyStr := string(gp.Hdr.CopyrightString[:])
	copyParts := strings.SplitN(copyStr, " ", 2)
	if len(copyParts) > 1 {
		// almost always improves presentation
		gp.DbgTerminal.writeString(copyParts[0] + "\n")
		gp.DbgTerminal.writeString(copyParts[1] + "\n")
	} else {
		gp.DbgTerminal.writeString(copyStr + "\n")
	}

	gp.DbgTerminal.newline()

	gp.DbgTerminal.writeString(fmt.Sprintf("Track %02d/%02d\n", gp.CurrentSong+1, gp.Hdr.NumSongs))

	nowTime := int(time.Now().Sub(gp.CurrentSongStart).Seconds())
	nowTimeStr := fmt.Sprintf("%02d:%02d", nowTime/60, nowTime%60)

	gp.DbgTerminal.writeString(fmt.Sprintf("%s", nowTimeStr))

	if gp.Paused {
		gp.DbgTerminal.writeString(" *PAUSED*\n")
	} else {
		gp.DbgTerminal.newline()
	}

	gp.LCD.FlipRequested = true
}

func (gp *gbsPlayer) prevSong() {
	if gp.CurrentSong > 0 {
		gp.CurrentSong--
		gp.initTune(gp.CurrentSong)
		gp.updateScreen()
	}
}
func (gp *gbsPlayer) nextSong() {
	if gp.CurrentSong < gp.Hdr.NumSongs-1 {
		gp.CurrentSong++
		gp.initTune(gp.CurrentSong)
		gp.updateScreen()
	}
}
func (gp *gbsPlayer) togglePause() {
	gp.Paused = !gp.Paused
	if gp.Paused {
		gp.PauseStartTime = time.Now()
	} else {
		gp.CurrentSongStart = gp.CurrentSongStart.Add(time.Now().Sub(gp.PauseStartTime))
	}
	gp.updateScreen()
}

var lastInput time.Time

func (gp *gbsPlayer) UpdateInput(input Input) {
	now := time.Now()
	if now.Sub(lastInput).Seconds() > 0.20 {
		if input.Joypad.Left {
			gp.prevSong()
			lastInput = now
		}
		if input.Joypad.Right {
			gp.nextSong()
			lastInput = now
		}
		if input.Joypad.Start {
			gp.togglePause()
			lastInput = now
		}
	}
}

var lastScreenUpdate time.Time

func (gp *gbsPlayer) Step() {
	if !gp.Paused {

		now := time.Now()
		if now.Sub(lastScreenUpdate) >= 100*time.Millisecond {
			lastScreenUpdate = now
			gp.updateScreen()
		}

		if gp.PC == 0x0130 {
			if now.Sub(gp.LastPlayCall).Seconds() > gp.PlayCallInterval {
				gp.LastPlayCall = now
				gp.SP = gp.Hdr.StackPtr
				gp.pushOp16(0, 0, 0x0130)
				gp.PC = gp.Hdr.PlayAddr
			}
		}

		if gp.PC != 0x0130 {
			gp.step()
		} else {
			gp.runCycles(4)
		}
	}
}

func (gp *gbsPlayer) ReadSoundBuffer(toFill []byte) []byte {
	buf := gp.APU.buffer.read(toFill)
	return buf
}

func (gp *gbsPlayer) Framebuffer() []byte {
	return gp.DbgScreen[:]
}
<|endoftext|>


<commit_before>package main

import "fmt"

import "path/filepath"
import "log"

import (
	"os"
	"os/exec"
)
import "strings"

type marker struct {
	name string
	path string
	link *volume
}

type volume struct {
	dir  string
	mark *marker
}

type container struct {
	name    string
	id      string
	stopped bool
	volumes []volume
}

func mustcmd(acmd string) string {
	fmt.Println(acmd)
	out, err := cmd(acmd)
	if err != nil {
		log.Fatal(fmt.Sprintf("out='%s', err='%s'", out, err))
	}
	return string(out)
}

func cmd(cmd string) (string, error) {
	out, err := exec.Command("sh", "-c", cmd).Output()
	return strings.TrimSpace(string(out)), err
}

func readVolumes() {
	out := mustcmd("sudo ls -1 /mnt/sda1/var/lib/docker/vfs/dir")
	vollines := strings.Split(out, "\n")
	fmt.Println(vollines)
	for _, volline := range vollines {
		dir := volline
		fdir := fmt.Sprintf("/mnt/sda1/var/lib/docker/vfs/dir/", dir)
		dirlink, err := cmd(fdir)
		fmt.Printf("---\ndir: '%s'\ndlk: '%s'\nerr='%v'", dir, dirlink, err)
		if err != nil {
			finfo, err := os.Stat(fdir)
			if err != nil {
				fmt.Printf("Invalid dir detected: '%s' (%s)\n", dir, err)
			}
			if finfo.IsDir() {
				fmt.Printf("dir detected: '%s'\n", dir)
			} else {
				fmt.Printf("Invalid dir (file) detected: '%s'\n", dir)
			}
			// mustcmd(fmt.Sprintf("sudo rm /mnt/sda1/var/lib/docker/vfs/dir/%s", dir))
		}
	}
}

// docker run --rm -i -t -v `pwd`:`pwd` -w `pwd` --entrypoint="/bin/bash" go -c 'go build gcl.go'
func main() {
	readVolumes()
	os.Exit(0)
	out := mustcmd("docker ps -qa --no-trunc")
	containers := strings.Split(out, "\n")
	containers = containers[:len(containers)-1]
	for _, id := range containers {
		fmt.Printf("container id: %s\n", id)
		out = mustcmd(fmt.Sprintf("docker inspect -f '{{ .Name }}' %s", id))
		name := strings.TrimSpace(out)[1:]
		fmt.Printf("  name: '%s'\n", name)
		out = mustcmd(fmt.Sprintf("docker inspect -f '{{ range $key, $value := .Volumes }}{{ $key }},{{ $value }}##~#{{ end }}' %s", name))
		volumes := strings.Split(out, "##~#")
		volumes = volumes[:len(volumes)-1]
		fmt.Printf("    volumes: '%v': %d\n", volumes, len(volumes))
		for i, volume := range volumes {
			vols := strings.Split(volume, ",")
			path := vols[0]
			vfs := vols[1]
			fmt.Printf("      volume %d: '%v'=>'%v'\n", i, path, vfs)
			if strings.Contains(vfs, "/var/lib/docker/vfs/dir/") {
				vfs2, _ := cmd(fmt.Sprintf("sudo readlink %s 2> /dev/null", vfs))
				vfs2 = strings.TrimSpace(vfs2)
				fmt.Printf("      vfs2 '%s' from sudo readlink %s\n", vfs2, vfs)
				link := "." + name + "###" + strings.Replace(path, "/", ",#,", -1)
				fmt.Printf("      link '%s'\n", link)
				ls, _ := cmd(fmt.Sprintf("sudo readlink /var/lib/docker/vfs/dir/%s 2> /dev/null", link))
				ls = strings.TrimSpace(ls)
				fmt.Printf("      ls link '%s'\n", ls)
				dir := filepath.Base(vfs)
				if vfs2 != "" {
					dir = filepath.Base(vfs2)
				}
				if ls == "" {
					fmt.Printf("      ln '%s' to '%s'\n", link, dir)
					mustcmd(fmt.Sprintf("sudo ln -s %s /var/lib/docker/vfs/dir/%s", dir, link))
				}
				if ls != dir && ls != "" {
					apathdir := fmt.Sprintf("/var/lib/docker/vfs/dir/%s", dir)
					mustcmd(fmt.Sprintf("sudo rm -Rf %s", apathdir))
					acmd := fmt.Sprintf("sudo ln -s %s %s", ls, apathdir)
					fmt.Printf("      must redirect '%s' to '%s'\n%s\n", dir, ls, acmd)
					mustcmd(acmd)
				}
			}
		}
	}
}
<commit_msg>gcl.go: read volumes<commit_after>package main

import (
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
)

type mpath string
type vdir string

var mpathre = regexp.MustCompile(`^\.(.*)$`)
var vdirre = regexp.MustCompile(`^[a-f0-9]{64}$`)

func newmpath(mp string) mpath {
	res := mpathre.FindAllStringSubmatch(mp, -1)
	mres := mpath("")
	if res != nil && len(res) == 1 && len(res[0]) == 2 {
		mres = mpath(res[0][1])
	}
	return mres
}

func newvdir(vd string) vdir {
	res := vdirre.FindString(vd)
	vres := vdir("")
	if res != "" && res == vd {
		vres = vdir(vd)
	}
	return vres
}

type marker struct {
	path mpath
	dir  vdir
}

var markers = []*marker{}

type volume struct {
	dir  vdir
	mark *marker
}

var volumes = []*volume{}

func (v *volume) String() string {
	return "vol '" + string(v.dir) + "'"
}

type container struct {
	name    string
	id      string
	stopped bool
	volumes []volume
}

func mustcmd(acmd string) string {
	out, err := cmd(acmd)
	if err != nil {
		log.Fatal(fmt.Sprintf("out='%s', err='%s'", out, err))
	}
	return string(out)
}

func cmd(cmd string) (string, error) {
	fmt.Println(cmd)
	out, err := exec.Command("sh", "-c", cmd).Output()
	return strings.TrimSpace(string(out)), err
}

func readVolumes() {
	out := mustcmd("sudo ls -a1F /mnt/sda1/var/lib/docker/vfs/dir")
	vollines := strings.Split(out, "\n")
	fmt.Println(vollines)
	for _, volline := range vollines {
		dir := volline
		if dir == "./" || dir == "../" {
			continue
		}
		if strings.HasSuffix(dir, "@") {
			dir = dir[:len(dir)-1]
			fdir := fmt.Sprintf("/mnt/sda1/var/lib/docker/vfs/dir/%s", dir)
			mp := newmpath(dir)
			if mp == "" {
				fmt.Printf("Invalid marker detected: '%s'\n", dir)
				mustcmd("sudo rm " + fdir)
			} else {
				dirlink, err := cmd("sudo readlink " + fdir)
				fmt.Printf("---\ndir: '%s'\ndlk: '%s'\nerr='%v'\n", dir, dirlink, err)
				if err != nil {
					fmt.Printf("Invalid marker (no readlink) detected: '%s'\n", dir)
					mustcmd("sudo rm " + fdir)
				} else {
					_, err := cmd("sudo ls /mnt/sda1/var/lib/docker/vfs/dir/" + dirlink)
					if err != nil {
						fmt.Printf("Invalid marker (readlink no ls) detected: '%s'\n", dir)
						mustcmd("sudo rm " + fdir)
					} else {
						vd := newvdir(dirlink)
						if vd == "" {
							fmt.Printf("Invalid marker (readlink no vdir) detected: '%s'\n", dir)
							mustcmd("sudo rm " + fdir)
						} else {
							markers = append(markers, &marker{mp, vd})
						}
					}
				}
			}
		} else if strings.HasSuffix(dir, "/") {

			dir = dir[:len(dir)-1]
			fdir := fmt.Sprintf("/mnt/sda1/var/lib/docker/vfs/dir/%s", dir)
			vd := newvdir(dir)
			if vd == "" {
				fmt.Printf("Invalid volume folder detected: '%s'\n", dir)
				mustcmd("sudo rm " + fdir)
			} else {
				volumes = append(volumes, &volume{vd, nil})
			}
		} else {
			fdir := fmt.Sprintf("/mnt/sda1/var/lib/docker/vfs/dir/%s", dir)
			fmt.Printf("Invalid file detected: '%s'\n", dir)
			mustcmd("sudo rm " + fdir)
		}
	}
	fmt.Printf("volumes: %v\nmarkers: %v\n", volumes, markers)
}

// docker run --rm -i -t -v `pwd`:`pwd` -w `pwd` --entrypoint="/bin/bash" go -c 'go build gcl.go'
func main() {
	readVolumes()
	os.Exit(0)
	out := mustcmd("docker ps -qa --no-trunc")
	containers := strings.Split(out, "\n")
	containers = containers[:len(containers)-1]
	for _, id := range containers {
		fmt.Printf("container id: %s\n", id)
		out = mustcmd(fmt.Sprintf("docker inspect -f '{{ .Name }}' %s", id))
		name := strings.TrimSpace(out)[1:]
		fmt.Printf("  name: '%s'\n", name)
		out = mustcmd(fmt.Sprintf("docker inspect -f '{{ range $key, $value := .Volumes }}{{ $key }},{{ $value }}##~#{{ end }}' %s", name))
		volumes := strings.Split(out, "##~#")
		volumes = volumes[:len(volumes)-1]
		fmt.Printf("    volumes: '%v': %d\n", volumes, len(volumes))
		for i, volume := range volumes {
			vols := strings.Split(volume, ",")
			path := vols[0]
			vfs := vols[1]
			fmt.Printf("      volume %d: '%v'=>'%v'\n", i, path, vfs)
			if strings.Contains(vfs, "/var/lib/docker/vfs/dir/") {
				vfs2, _ := cmd(fmt.Sprintf("sudo readlink %s 2> /dev/null", vfs))
				vfs2 = strings.TrimSpace(vfs2)
				fmt.Printf("      vfs2 '%s' from sudo readlink %s\n", vfs2, vfs)
				link := "." + name + "###" + strings.Replace(path, "/", ",#,", -1)
				fmt.Printf("      link '%s'\n", link)
				ls, _ := cmd(fmt.Sprintf("sudo readlink /var/lib/docker/vfs/dir/%s 2> /dev/null", link))
				ls = strings.TrimSpace(ls)
				fmt.Printf("      ls link '%s'\n", ls)
				dir := filepath.Base(vfs)
				if vfs2 != "" {
					dir = filepath.Base(vfs2)
				}
				if ls == "" {
					fmt.Printf("      ln '%s' to '%s'\n", link, dir)
					mustcmd(fmt.Sprintf("sudo ln -s %s /var/lib/docker/vfs/dir/%s", dir, link))
				}
				if ls != dir && ls != "" {
					apathdir := fmt.Sprintf("/var/lib/docker/vfs/dir/%s", dir)
					mustcmd(fmt.Sprintf("sudo rm -Rf %s", apathdir))
					acmd := fmt.Sprintf("sudo ln -s %s %s", ls, apathdir)
					fmt.Printf("      must redirect '%s' to '%s'\n%s\n", dir, ls, acmd)
					mustcmd(acmd)
				}
			}
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"os/exec"
	"regexp"
)

type Matcher struct {
	re *regexp.Regexp
}

func NewMatcher(expr string) (m *Matcher, err error) {
	m = &Matcher{}
	m.re, err = regexp.Compile(expr)
	if err != nil {
		return nil, err
	}
	return m, nil
}

func (m *Matcher) MatchString(s string) bool {
	return m.re.MatchString(s)
}

type Processor struct {
	cmd *exec.Cmd
}

func NewProcessor(name string, arg ...string) (p *Processor, err error) {
	if _, err = exec.LookPath(name); err != nil {
		return nil, err
	}
	p = &Processor{}
	p.cmd = exec.Command(name, arg...)
	return p, nil
}

func (p *Processor) Process(a []string) error {
	in, err := p.cmd.StdinPipe()
	if err != nil {
		return err
	}
	defer in.Close()

	out, err := p.cmd.StdoutPipe()
	if err != nil {
		return err
	}
	defer out.Close()

	if err = p.cmd.Start(); err != nil {
		return err
	}
	for _, s := range a {
		fmt.Fprintln(in, s)
	}
	if err = in.Close(); err != nil {
		return err
	}

	b := bufio.NewScanner(out)
	for i := 0; i < len(a) && b.Scan(); i++ {
		a[i] = b.Text()
	}
	return b.Err()
}

type Option struct {
	IsHelp  bool
	Pattern string
	Command string
	Arg     []string
	Files   []string
}

func ParseOption(args []string) (opt *Option, err error) {
	opt = &Option{}
	f := flag.NewFlagSet("gdo", flag.ContinueOnError)
	f.SetOutput(ioutil.Discard)

	f.BoolVar(&opt.IsHelp, "h", false, "")
	f.BoolVar(&opt.IsHelp, "help", false, "")
	if err = f.Parse(args); err != nil {
		return nil, err
	}
	switch f.NArg() {
	case 0:
		return nil, fmt.Errorf("no specify PATTERN and COMMAND")
	case 1:
		return nil, fmt.Errorf("no specify COMMAND")
	}
	opt.Pattern = f.Arg(0)
	opt.Command = f.Arg(1)

	var finishArg bool
	for _, arg := range f.Args()[2:] {
		switch {
		case finishArg:
			opt.Files = append(opt.Files, arg)
		case arg == "--":
			finishArg = true
		default:
			opt.Arg = append(opt.Arg, arg)
		}
	}
	return opt, nil
}

type Lines struct {
	matcher        *Matcher
	processor      *Processor
	lines          []string
	matchedLines   []string
	matchedIndexes map[int]bool
}

func NewLines(opt *Option) (l *Lines, err error) {
	if opt == nil {
		opt = &Option{}
	}
	m, err := NewMatcher(opt.Pattern)
	if err != nil {
		return nil, err
	}
	p, err := NewProcessor(opt.Command, opt.Arg...)
	if err != nil {
		return nil, err
	}
	return &Lines{
		matcher:        m,
		processor:      p,
		matchedIndexes: make(map[int]bool),
	}, nil
}

func (l *Lines) LoadLines(r io.Reader, m *Matcher) error {
	b := bufio.NewScanner(r)
	for i := 0; b.Scan(); i++ {
		line := b.Text()
		if m.MatchString(line) {
			l.matchedLines = append(l.matchedLines, line)
			l.matchedIndexes[i] = true
		}
		l.lines = append(l.lines, line)
	}
	return b.Err()
}

func (l *Lines) Flush(out io.Writer, p *Processor) error {
	if err := p.Process(l.matchedLines); err != nil {
		return err
	}
	mi := 0
	for li := 0; li < len(l.lines); li++ {
		if l.matchedIndexes[li] {
			fmt.Fprintln(out, l.matchedLines[mi])
			mi++
		} else {
			fmt.Fprintln(out, l.lines[li])
		}
	}
	return nil
}
<commit_msg>Remove args of Lines.LoadLines<commit_after>package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"os/exec"
	"regexp"
)

type Matcher struct {
	re *regexp.Regexp
}

func NewMatcher(expr string) (m *Matcher, err error) {
	m = &Matcher{}
	m.re, err = regexp.Compile(expr)
	if err != nil {
		return nil, err
	}
	return m, nil
}

func (m *Matcher) MatchString(s string) bool {
	return m.re.MatchString(s)
}

type Processor struct {
	cmd *exec.Cmd
}

func NewProcessor(name string, arg ...string) (p *Processor, err error) {
	if _, err = exec.LookPath(name); err != nil {
		return nil, err
	}
	p = &Processor{}
	p.cmd = exec.Command(name, arg...)
	return p, nil
}

func (p *Processor) Process(a []string) error {
	in, err := p.cmd.StdinPipe()
	if err != nil {
		return err
	}
	defer in.Close()

	out, err := p.cmd.StdoutPipe()
	if err != nil {
		return err
	}
	defer out.Close()

	if err = p.cmd.Start(); err != nil {
		return err
	}
	for _, s := range a {
		fmt.Fprintln(in, s)
	}
	if err = in.Close(); err != nil {
		return err
	}

	b := bufio.NewScanner(out)
	for i := 0; i < len(a) && b.Scan(); i++ {
		a[i] = b.Text()
	}
	return b.Err()
}

type Option struct {
	IsHelp  bool
	Pattern string
	Command string
	Arg     []string
	Files   []string
}

func ParseOption(args []string) (opt *Option, err error) {
	opt = &Option{}
	f := flag.NewFlagSet("gdo", flag.ContinueOnError)
	f.SetOutput(ioutil.Discard)

	f.BoolVar(&opt.IsHelp, "h", false, "")
	f.BoolVar(&opt.IsHelp, "help", false, "")
	if err = f.Parse(args); err != nil {
		return nil, err
	}
	switch f.NArg() {
	case 0:
		return nil, fmt.Errorf("no specify PATTERN and COMMAND")
	case 1:
		return nil, fmt.Errorf("no specify COMMAND")
	}
	opt.Pattern = f.Arg(0)
	opt.Command = f.Arg(1)

	var finishArg bool
	for _, arg := range f.Args()[2:] {
		switch {
		case finishArg:
			opt.Files = append(opt.Files, arg)
		case arg == "--":
			finishArg = true
		default:
			opt.Arg = append(opt.Arg, arg)
		}
	}
	return opt, nil
}

type Lines struct {
	matcher        *Matcher
	processor      *Processor
	lines          []string
	matchedLines   []string
	matchedIndexes map[int]bool
}

func NewLines(opt *Option) (l *Lines, err error) {
	if opt == nil {
		opt = &Option{}
	}
	m, err := NewMatcher(opt.Pattern)
	if err != nil {
		return nil, err
	}
	p, err := NewProcessor(opt.Command, opt.Arg...)
	if err != nil {
		return nil, err
	}
	return &Lines{
		matcher:        m,
		processor:      p,
		matchedIndexes: make(map[int]bool),
	}, nil
}

func (l *Lines) LoadLines(r io.Reader) error {
	b := bufio.NewScanner(r)
	for i := 0; b.Scan(); i++ {
		line := b.Text()
		if l.matcher.MatchString(line) {
			l.matchedLines = append(l.matchedLines, line)
			l.matchedIndexes[i] = true
		}
		l.lines = append(l.lines, line)
	}
	return b.Err()
}

func (l *Lines) Flush(out io.Writer, p *Processor) error {
	if err := p.Process(l.matchedLines); err != nil {
		return err
	}
	mi := 0
	for li := 0; li < len(l.lines); li++ {
		if l.matchedIndexes[li] {
			fmt.Fprintln(out, l.matchedLines[mi])
			mi++
		} else {
			fmt.Fprintln(out, l.lines[li])
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package configuration

import (
	"cf"
	"fileutils"
	"fmt"
	"github.com/stretchr/testify/assert"
	"os"
	"path/filepath"
	"testing"
)

func TestLoadingWithNoConfigFile(t *testing.T) {
	withFakeHome(func() {
		repo := NewConfigurationDiskRepository()
		config, err := repo.Get()
		assert.NoError(t, err)

		assert.Equal(t, config.Target, "")
		assert.Equal(t, config.ApiVersion, "")
		assert.Equal(t, config.AuthorizationEndpoint, "")
		assert.Equal(t, config.AccessToken, "")
	})
}

func TestSavingAndLoading(t *testing.T) {
	withFakeHome(func() {
		repo := NewConfigurationDiskRepository()
		configToSave, err := repo.Get()
		assert.NoError(t, err)

		configToSave.ApiVersion = "3.1.0"
		configToSave.Target = "https://api.target.example.com"
		configToSave.AuthorizationEndpoint = "https://login.target.example.com"
		configToSave.AccessToken = "bearer my_access_token"

		repo.Save()

		singleton = nil
		savedConfig, err := repo.Get()
		assert.NoError(t, err)
		assert.Equal(t, savedConfig, configToSave)
	})
}

func TestSetOrganization(t *testing.T) {
	withFakeHome(func() {
		repo := NewConfigurationDiskRepository()
		config, err := repo.Get()
		assert.NoError(t, err)

		config.OrganizationFields = cf.OrganizationFields{}

		org := cf.OrganizationFields{}
		org.Name = "my-org"
		org.Guid = "my-org-guid"
		err = repo.SetOrganization(org)
		assert.NoError(t, err)

		repo.Save()

		savedConfig, err := repo.Get()
		assert.NoError(t, err)
		assert.Equal(t, savedConfig.OrganizationFields, org)
		assert.Equal(t, savedConfig.SpaceFields, cf.SpaceFields{})
	})
}

func TestSetSpace(t *testing.T) {
	withFakeHome(func() {
		repo := NewConfigurationDiskRepository()
		repo.Get()
		space := cf.SpaceFields{}
		space.Name = "my-space"
		space.Guid = "my-space-guid"

		err := repo.SetSpace(space)
		assert.NoError(t, err)

		repo.Save()

		savedConfig, err := repo.Get()
		assert.NoError(t, err)
		assert.Equal(t, savedConfig.SpaceFields, space)
	})
}

func TestClearTokens(t *testing.T) {
	withFakeHome(func() {
		org := cf.OrganizationFields{}
		org.Name = "my-org"
		space := cf.SpaceFields{}
		space.Name = "my-space"

		repo := NewConfigurationDiskRepository()
		config, err := repo.Get()
		assert.NoError(t, err)

		config.Target = "http://api.example.com"
		config.RefreshToken = "some old refresh token"
		config.AccessToken = "some old access token"
		config.OrganizationFields = org
		config.SpaceFields = space
		repo.Save()

		err = repo.ClearTokens()
		assert.NoError(t, err)

		repo.Save()

		savedConfig, err := repo.Get()
		assert.NoError(t, err)
		assert.Equal(t, savedConfig.Target, "http://api.example.com")
		assert.Empty(t, savedConfig.AccessToken)
		assert.Empty(t, savedConfig.RefreshToken)
		assert.Equal(t, savedConfig.OrganizationFields, org)
		assert.Equal(t, savedConfig.SpaceFields, space)
	})
}

func TestClearSession(t *testing.T) {
	withFakeHome(func() {
		repo := NewConfigurationDiskRepository()
		config, err := repo.Get()
		assert.NoError(t, err)

		config.Target = "http://api.example.com"
		config.RefreshToken = "some old refresh token"
		config.AccessToken = "some old access token"
		org := cf.OrganizationFields{}
		org.Name = "my-org"
		space := cf.SpaceFields{}
		space.Name = "my-space"
		repo.Save()

		err = repo.ClearSession()
		assert.NoError(t, err)

		repo.Save()

		savedConfig, err := repo.Get()
		assert.NoError(t, err)
		assert.Equal(t, savedConfig.Target, "http://api.example.com")
		assert.Empty(t, savedConfig.AccessToken)
		assert.Empty(t, savedConfig.RefreshToken)
		assert.Equal(t, savedConfig.OrganizationFields, cf.OrganizationFields{})
		assert.Equal(t, savedConfig.SpaceFields, cf.SpaceFields{})
	})
}

func TestNewConfigGivesYouCurrentVersionedConfig(t *testing.T) {
	withFakeHome(func() {
		repo := NewConfigurationDiskRepository()
		config, err := repo.Get()
		assert.NoError(t, err)
		assert.Equal(t, config.ConfigVersion, 1)
	})
}

func TestReadingOutdatedConfigReturnsNewConfig(t *testing.T) {
	withConfigFixture(t, "outdated-config", func() {
		repo := NewConfigurationDiskRepository()
		config, err := repo.Get()

		assert.NoError(t, err)
		assert.Equal(t, config.ConfigVersion, 1)
		assert.Equal(t, config.Target, "")
	})
}

func TestReadingVersionNumberFromExistingConfig(t *testing.T) {
	withConfigFixture(t, "versioned-config", func() {
		repo := NewConfigurationDiskRepository()
		config, err := repo.Get()
		assert.NoError(t, err)
		assert.Equal(t, config.ConfigVersion, 9001)
	})
}

func withFakeHome(callback func()) {
	oldHome := os.Getenv("HOME")
	oldHomePath := os.Getenv("HOMEPATH")
	defer func() {
		os.Setenv("HOMEPATH", oldHomePath)
		os.Setenv("HOME", oldHome)
	}()

	defer func() {
		NewConfigurationDiskRepository().Delete()
	}()

	fileutils.TempDir("test-config", func(dir string, err error) {
		os.Setenv("HOME", dir)
		os.Setenv("HOMEPATH", dir)
		callback()
	})
}

func withConfigFixture(t *testing.T, name string, callback func()) {
	oldHome := os.Getenv("HOME")
	oldHomePath := os.Getenv("HOMEPATH")
	defer func() {
		os.Setenv("HOMEPATH", oldHomePath)
		os.Setenv("HOME", oldHome)
	}()

	defer func() {
		singleton = nil
	}()

	cwd, err := os.Getwd()
	assert.NoError(t, err)

	fixturePath := filepath.Join(cwd, fmt.Sprintf("../../fixtures/config/%s", name))
	os.Setenv("HOME", fixturePath)
	os.Setenv("HOMEPATH", fixturePath)
	callback()
}
<commit_msg>Append volume name and relative path for config test on windows<commit_after>package configuration

import (
	"cf"
	"fileutils"
	"fmt"
	"github.com/stretchr/testify/assert"
	"os"
	"path/filepath"
	"testing"
	"strings"
)

func TestLoadingWithNoConfigFile(t *testing.T) {
	withFakeHome(t, func() {
		repo := NewConfigurationDiskRepository()
		config, err := repo.Get()
		assert.NoError(t, err)

		assert.Equal(t, config.Target, "")
		assert.Equal(t, config.ApiVersion, "")
		assert.Equal(t, config.AuthorizationEndpoint, "")
		assert.Equal(t, config.AccessToken, "")
	})
}

func TestSavingAndLoading(t *testing.T) {
	withFakeHome(t, func() {
		repo := NewConfigurationDiskRepository()
		configToSave, err := repo.Get()
		assert.NoError(t, err)

		configToSave.ApiVersion = "3.1.0"
		configToSave.Target = "https://api.target.example.com"
		configToSave.AuthorizationEndpoint = "https://login.target.example.com"
		configToSave.AccessToken = "bearer my_access_token"

		repo.Save()

		singleton = nil
		savedConfig, err := repo.Get()
		assert.NoError(t, err)
		assert.Equal(t, savedConfig, configToSave)
	})
}

func TestSetOrganization(t *testing.T) {
	withFakeHome(t, func() {
		repo := NewConfigurationDiskRepository()
		config, err := repo.Get()
		assert.NoError(t, err)

		config.OrganizationFields = cf.OrganizationFields{}

		org := cf.OrganizationFields{}
		org.Name = "my-org"
		org.Guid = "my-org-guid"
		err = repo.SetOrganization(org)
		assert.NoError(t, err)

		repo.Save()

		savedConfig, err := repo.Get()
		assert.NoError(t, err)
		assert.Equal(t, savedConfig.OrganizationFields, org)
		assert.Equal(t, savedConfig.SpaceFields, cf.SpaceFields{})
	})
}

func TestSetSpace(t *testing.T) {
	withFakeHome(t, func() {
		repo := NewConfigurationDiskRepository()
		repo.Get()
		space := cf.SpaceFields{}
		space.Name = "my-space"
		space.Guid = "my-space-guid"

		err := repo.SetSpace(space)
		assert.NoError(t, err)

		repo.Save()

		savedConfig, err := repo.Get()
		assert.NoError(t, err)
		assert.Equal(t, savedConfig.SpaceFields, space)
	})
}

func TestClearTokens(t *testing.T) {
	withFakeHome(t, func() {
		org := cf.OrganizationFields{}
		org.Name = "my-org"
		space := cf.SpaceFields{}
		space.Name = "my-space"

		repo := NewConfigurationDiskRepository()
		config, err := repo.Get()
		assert.NoError(t, err)

		config.Target = "http://api.example.com"
		config.RefreshToken = "some old refresh token"
		config.AccessToken = "some old access token"
		config.OrganizationFields = org
		config.SpaceFields = space
		repo.Save()

		err = repo.ClearTokens()
		assert.NoError(t, err)

		repo.Save()

		savedConfig, err := repo.Get()
		assert.NoError(t, err)
		assert.Equal(t, savedConfig.Target, "http://api.example.com")
		assert.Empty(t, savedConfig.AccessToken)
		assert.Empty(t, savedConfig.RefreshToken)
		assert.Equal(t, savedConfig.OrganizationFields, org)
		assert.Equal(t, savedConfig.SpaceFields, space)
	})
}

func TestClearSession(t *testing.T) {
	withFakeHome(t, func() {
		repo := NewConfigurationDiskRepository()
		config, err := repo.Get()
		assert.NoError(t, err)

		config.Target = "http://api.example.com"
		config.RefreshToken = "some old refresh token"
		config.AccessToken = "some old access token"
		org := cf.OrganizationFields{}
		org.Name = "my-org"
		space := cf.SpaceFields{}
		space.Name = "my-space"
		repo.Save()

		err = repo.ClearSession()
		assert.NoError(t, err)

		repo.Save()

		savedConfig, err := repo.Get()
		assert.NoError(t, err)
		assert.Equal(t, savedConfig.Target, "http://api.example.com")
		assert.Empty(t, savedConfig.AccessToken)
		assert.Empty(t, savedConfig.RefreshToken)
		assert.Equal(t, savedConfig.OrganizationFields, cf.OrganizationFields{})
		assert.Equal(t, savedConfig.SpaceFields, cf.SpaceFields{})
	})
}

func TestNewConfigGivesYouCurrentVersionedConfig(t *testing.T) {
	withFakeHome(t, func() {
		repo := NewConfigurationDiskRepository()
		config, err := repo.Get()
		assert.NoError(t, err)
		assert.Equal(t, config.ConfigVersion, 1)
	})
}

func TestReadingOutdatedConfigReturnsNewConfig(t *testing.T) {
	withConfigFixture(t, "outdated-config", func() {
		repo := NewConfigurationDiskRepository()
		config, err := repo.Get()

		assert.NoError(t, err)
		assert.Equal(t, config.ConfigVersion, 1)
		assert.Equal(t, config.Target, "")
	})
}

func TestReadingVersionNumberFromExistingConfig(t *testing.T) {
	withConfigFixture(t, "versioned-config", func() {
		repo := NewConfigurationDiskRepository()
		config, err := repo.Get()
		assert.NoError(t, err)
		assert.Equal(t, config.ConfigVersion, 9001)
	})
}

func withFakeHome(t *testing.T, callback func()) {
	oldHome := os.Getenv("HOME")
	oldHomePath := os.Getenv("HOMEPATH")
	oldHomeDrive := os.Getenv("HOMEDRIVE")
	defer func() {
		os.Setenv("HOMEDRIVE", oldHomeDrive)
		os.Setenv("HOMEPATH", oldHomePath)
		os.Setenv("HOME", oldHome)
	}()

	defer func() {
		NewConfigurationDiskRepository().Delete()
	}()

	fileutils.TempDir("test-config", func(dir string, err error) {
		os.Setenv("HOME", dir)

		volumeName := filepath.VolumeName(dir)
		if volumeName != "" {
			relativePath := strings.Replace(dir, volumeName, "", 1)

			os.Setenv("HOMEPATH", relativePath)
			os.Setenv("HOMEDRIVE", volumeName)
		}

		callback()
	})
}

func withConfigFixture(t *testing.T, name string, callback func()) {
	oldHome := os.Getenv("HOME")
	oldHomePath := os.Getenv("HOMEPATH")
	oldHomeDrive := os.Getenv("HOMEDRIVE")
	defer func() {
		os.Setenv("HOMEDRIVE", oldHomeDrive)
		os.Setenv("HOMEPATH", oldHomePath)
		os.Setenv("HOME", oldHome)
	}()

	defer func() {
		singleton = nil
	}()

	cwd, err := os.Getwd()
	assert.NoError(t, err)

	fixturePath := filepath.Join(cwd, fmt.Sprintf("../../fixtures/config/%s", name))
	os.Setenv("HOME", fixturePath)

	volumeName := filepath.VolumeName(fixturePath)
	if volumeName != "" {
		relativePath := strings.Replace(fixturePath, volumeName, "", 1)

		os.Setenv("HOMEPATH", relativePath)
		os.Setenv("HOMEDRIVE", volumeName)
	}

	callback()
}
<|endoftext|>