<commit_before>package environs

import (
	"archive/tar"
	"compress/gzip"
	"fmt"
	"io"
	"io/ioutil"
	"launchpad.net/juju-core/log"
	"launchpad.net/juju-core/state"
	"launchpad.net/juju-core/version"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"strings"
)

// VarDir is the directory where juju data is stored.
// The tools directories are stored inside the "tools" subdirectory
// inside VarDir.
var VarDir = "/var/lib/juju"

var toolPrefix = "tools/juju-"

// ListTools returns all the tools found in the given storage
// that have the given major version.
func ListTools(store StorageReader, majorVersion int) ([]*state.Tools, error) {
	dir := fmt.Sprintf("%s%d.", toolPrefix, majorVersion)
	names, err := store.List(dir)
	if err != nil {
		return nil, err
	}
	var toolsList []*state.Tools
	for _, name := range names {
		if !strings.HasPrefix(name, toolPrefix) || !strings.HasSuffix(name, ".tgz") {
			log.Printf("unexpected tools file found %q", name)
			continue
		}
		vers := name[len(toolPrefix) : len(name)-len(".tgz")]
		var t state.Tools
		t.Binary, err = version.ParseBinary(vers)
		if err != nil {
			log.Printf("failed to parse %q: %v", vers, err)
			continue
		}
		if t.Major != majorVersion {
			log.Printf("tool %q found in wrong directory %q", name, dir)
			continue
		}
		t.URL, err = store.URL(name)
		if err != nil {
			log.Printf("cannot get URL for %q: %v", name, err)
			continue
		}
		toolsList = append(toolsList, &t)
	}
	return toolsList, nil
}

// PutTools builds the current version of the juju tools and uploads them
// to the given storage, and returns a Tools instance describing them.
// If vers is non-nil, a FORCE_VERSION file will be written into the
// tools directory which will override the current version.
// TODO(rog) find binaries from $PATH when not using a development
// version of juju within a $GOPATH.
func PutTools(storage Storage, vers *version.Binary) (*state.Tools, error) {
	// We create the entire archive before asking the environment to
	// start uploading so that we can be sure we have archived
	// correctly.
	f, err := ioutil.TempFile("", "juju-tgz")
	if err != nil {
		return nil, err
	}
	defer f.Close()
	defer os.Remove(f.Name())
	tvers, err := bundleTools(f, vers)
	if err != nil {
		return nil, err
	}
	_, err = f.Seek(0, 0)
	if err != nil {
		return nil, fmt.Errorf("cannot seek to start of tools archive: %v", err)
	}
	fi, err := f.Stat()
	if err != nil {
		return nil, fmt.Errorf("cannot stat newly made tools archive: %v", err)
	}
	p := ToolsStoragePath(tvers)
	log.Printf("environs: putting tools %v", p)
	err = storage.Put(p, f, fi.Size())
	if err != nil {
		return nil, err
	}
	url, err := storage.URL(p)
	if err != nil {
		return nil, err
	}
	return &state.Tools{tvers, url}, nil
}

// archive writes the executable files found in the given directory in
// gzipped tar format to w.  An error is returned if an entry inside dir
// is not a regular executable file.
func archive(w io.Writer, dir string) (err error) {
	entries, err := ioutil.ReadDir(dir)
	if err != nil {
		return err
	}

	gzw := gzip.NewWriter(w)
	defer closeErrorCheck(&err, gzw)

	tarw := tar.NewWriter(gzw)
	defer closeErrorCheck(&err, tarw)

	for _, ent := range entries {
		h := tarHeader(ent)
		// ignore local umask
		if isExecutable(ent) {
			h.Mode = 0755
		} else {
			h.Mode = 0644
		}
		err := tarw.WriteHeader(h)
		if err != nil {
			return err
		}
		if err := copyFile(tarw, filepath.Join(dir, ent.Name())); err != nil {
			return err
		}
	}
	return nil
}

// copyFile writes the contents of the given file to w.
func copyFile(w io.Writer, file string) error {
	f, err := os.Open(file)
	if err != nil {
		return err
	}
	defer f.Close()
	_, err = io.Copy(w, f)
	return err
}

// tarHeader returns a tar file header given the file's stat
// information.
func tarHeader(i os.FileInfo) *tar.Header {
	return &tar.Header{
		Typeflag:   tar.TypeReg,
		Name:       i.Name(),
		Size:       i.Size(),
		Mode:       int64(i.Mode() & 0777),
		ModTime:    i.ModTime(),
		AccessTime: i.ModTime(),
		ChangeTime: i.ModTime(),
		Uname:      "ubuntu",
		Gname:      "ubuntu",
	}
}

// isExecutable returns whether the given info
// represents a regular file executable by (at least) the user.
func isExecutable(i os.FileInfo) bool {
	return i.Mode()&(0100|os.ModeType) == 0100
}

// closeErrorCheck means that we can ensure that
// Close errors do not get lost even when we defer them,
func closeErrorCheck(errp *error, c io.Closer) {
	err := c.Close()
	if *errp == nil {
		*errp = err
	}
}

// BestTools the most recent tools compatible with the
// given specification. It returns nil if nothing appropriate
// was found.
func BestTools(toolsList []*state.Tools, vers version.Binary) *state.Tools {
	var bestTools *state.Tools
	for _, t := range toolsList {
		if t.Major != vers.Major ||
			t.Series != vers.Series ||
			t.Arch != vers.Arch {
			continue
		}
		if bestTools == nil || bestTools.Number.Less(t.Number) {
			bestTools = t
		}
	}
	return bestTools
}

const urlFile = "downloaded-url.txt"

// toolsParentDir returns the tools parent directory.
func toolsParentDir() string {
	return path.Join(VarDir, "tools")
}

// UnpackTools reads a set of juju tools in gzipped tar-archive
// format and unpacks them into the appropriate tools directory.
// If a valid tools directory already exists, UnpackTools returns
// without error.
func UnpackTools(tools *state.Tools, r io.Reader) (err error) {
	zr, err := gzip.NewReader(r)
	if err != nil {
		return err
	}
	defer zr.Close()

	// Make a temporary directory in the tools directory,
	// first ensuring that the tools directory exists.
	err = os.MkdirAll(toolsParentDir(), 0755)
	if err != nil {
		return err
	}
	dir, err := ioutil.TempDir(toolsParentDir(), "unpacking-")
	if err != nil {
		return err
	}
	defer removeAll(dir)

	tr := tar.NewReader(zr)
	for {
		hdr, err := tr.Next()
		if err == io.EOF {
			break
		}
		if err != nil {
			return err
		}
		if strings.ContainsAny(hdr.Name, "/\\") {
			return fmt.Errorf("bad name %q in tools archive", hdr.Name)
		}
		if hdr.Typeflag != tar.TypeReg {
			return fmt.Errorf("bad file type %#c in file %q in tools archive", hdr.Typeflag, hdr.Name)
		}
		name := filepath.Join(dir, hdr.Name)
		if err := writeFile(name, os.FileMode(hdr.Mode&0777), tr); err != nil {
			return fmt.Errorf("tar extract %q failed: %v", name, err)
		}
	}
	err = ioutil.WriteFile(filepath.Join(dir, urlFile), []byte(tools.URL), 0644)
	if err != nil {
		return err
	}

	err = os.Rename(dir, ToolsDir(tools.Binary))
	// If we've failed to rename the directory, it may be because
	// the directory already exists - if ReadTools succeeds, we
	// assume all's ok.
	if err != nil {
		_, err := ReadTools(tools.Binary)
		if err == nil {
			return nil
		}
	}
	return nil
}

func removeAll(dir string) {
	err := os.RemoveAll(dir)
	if err == nil || os.IsNotExist(err) {
		return
	}
	log.Printf("environs: cannot remove %q: %v", dir, err)
}

func writeFile(name string, mode os.FileMode, r io.Reader) error {
	f, err := os.OpenFile(name, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, mode)
	if err != nil {
		return err
	}
	defer f.Close()
	_, err = io.Copy(f, r)
	return err
}

// ReadTools checks that the tools for the given version exist
// and returns a Tools instance describing them.
func ReadTools(vers version.Binary) (*state.Tools, error) {
	dir := ToolsDir(vers)
	urlData, err := ioutil.ReadFile(filepath.Join(dir, urlFile))
	if err != nil {
		return nil, fmt.Errorf("cannot read URL in tools directory: %v", err)
	}
	url := strings.TrimSpace(string(urlData))
	if len(url) == 0 {
		return nil, fmt.Errorf("empty URL in tools directory %q", dir)
	}
	// TODO(rog): do more verification here too, such as checking
	// for the existence of certain files.
	return &state.Tools{
		URL:    url,
		Binary: vers,
	}, nil
}

// ChangeAgentTools atomically replaces the agent-specific symlink
// under the tools directory so it points to the previously unpacked
// version vers. It returns the new tools read.
func ChangeAgentTools(agentName string, vers version.Binary) (*state.Tools, error) {
	tools, err := ReadTools(vers)
	if err != nil {
		return nil, err
	}
	tmpName := AgentToolsDir("tmplink-" + agentName)
	err = os.Symlink(tools.Binary.String(), tmpName)
	if err != nil {
		return nil, fmt.Errorf("cannot create tools symlink: %v", err)
	}
	err = os.Rename(tmpName, AgentToolsDir(agentName))
	if err != nil {
		return nil, fmt.Errorf("cannot update tools symlink: %v", err)
	}
	return tools, nil
}

// ToolsStoragePath returns the slash-separated path that is used to store and
// retrieve the given version of the juju tools in a Storage.
func ToolsStoragePath(vers version.Binary) string {
	return toolPrefix + vers.String() + ".tgz"
}

// ToolsDir returns the slash-separated directory name that is used to
// store binaries for the given version of the juju tools.
func ToolsDir(vers version.Binary) string {
	return path.Join(VarDir, "tools", vers.String())
}

// AgentToolsDir returns the slash-separated directory name that is used
// to store binaries for the tools used by the given agent.
// Conventionally it is a symbolic link to the actual tools directory.
func AgentToolsDir(agentName string) string {
	return path.Join(VarDir, "tools", agentName)
}

// FindTools tries to find a set of tools compatible with the given
// version from the given environment.  If no tools are found and
// there's no other error, a NotFoundError is returned.  If there's
// anything compatible in the environ's Storage, it gets precedence over
// anything in its PublicStorage.
func FindTools(env Environ, vers version.Binary) (*state.Tools, error) {
	toolsList, err := ListTools(env.Storage(), vers.Major)
	if err != nil {
		return nil, err
	}
	tools := BestTools(toolsList, vers)
	if tools != nil {
		return tools, nil
	}
	toolsList, err = ListTools(env.PublicStorage(), vers.Major)
	if err != nil {
		return nil, err
	}
	tools = BestTools(toolsList, vers)
	if tools == nil {
		return nil, &NotFoundError{fmt.Errorf("no compatible tools found")}
	}
	return tools, nil
}

func setenv(env []string, val string) []string {
	prefix := val[0 : strings.Index(val, "=")+1]
	for i, eval := range env {
		if strings.HasPrefix(eval, prefix) {
			env[i] = val
			return env
		}
	}
	return append(env, val)
}

// bundleTools bundles all the current juju tools in gzipped tar
// format to the given writer.
func bundleTools(w io.Writer, vers *version.Binary) (version.Binary, error) {
	dir, err := ioutil.TempDir("", "juju-tools")
	if err != nil {
		return version.Binary{}, err
	}
	defer os.RemoveAll(dir)

	cmd := exec.Command("go", "install", "launchpad.net/juju-core/cmd/...")
	cmd.Env = setenv(os.Environ(), "GOBIN="+dir)
	out, err := cmd.CombinedOutput()
	if err != nil {
		return version.Binary{}, fmt.Errorf("build failed: %v; %s", err, out)
	}
	if vers != nil {
		if err := ioutil.WriteFile(filepath.Join(dir, "FORCE-VERSION"), []byte((*vers).String()), 0666); err != nil {
			return version.Binary{}, err
		}
	}
	cmd = exec.Command(filepath.Join(dir, "jujud"), "version")
	out, err = cmd.CombinedOutput()
	if err != nil {
		return version.Binary{}, fmt.Errorf("cannot get version from %q: %v; %s", cmd.Args[0], err, out)
	}
	tvs := strings.TrimSpace(string(out))
	tvers, err := version.ParseBinary(tvs)
	if err != nil {
		return version.Binary{}, fmt.Errorf("invalid version %q printed by jujud", tvs)
	}
	err = archive(w, dir)
	if err != nil {
		return version.Binary{}, err
	}
	return tvers, err
}

// EmptyStorage holds a StorageReader object that contains nothing.
var EmptyStorage StorageReader = emptyStorage{}

type emptyStorage struct{}

func (s emptyStorage) Get(name string) (io.ReadCloser, error) {
	return nil, &NotFoundError{fmt.Errorf("file %q not found in empty storage", name)}
}

func (s emptyStorage) URL(string) (string, error) {
	return "", fmt.Errorf("empty storage has no URLs")
}

func (s emptyStorage) List(prefix string) ([]string, error) {
	return nil, nil
}
<commit_msg>adjust comment<commit_after>package environs

import (
	"archive/tar"
	"compress/gzip"
	"fmt"
	"io"
	"io/ioutil"
	"launchpad.net/juju-core/log"
	"launchpad.net/juju-core/state"
	"launchpad.net/juju-core/version"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"strings"
)

// VarDir is the directory where juju data is stored.
// The tools directories are stored inside the "tools" subdirectory
// inside VarDir.
var VarDir = "/var/lib/juju"

var toolPrefix = "tools/juju-"

// ListTools returns all the tools found in the given storage
// that have the given major version.
func ListTools(store StorageReader, majorVersion int) ([]*state.Tools, error) {
	dir := fmt.Sprintf("%s%d.", toolPrefix, majorVersion)
	names, err := store.List(dir)
	if err != nil {
		return nil, err
	}
	var toolsList []*state.Tools
	for _, name := range names {
		if !strings.HasPrefix(name, toolPrefix) || !strings.HasSuffix(name, ".tgz") {
			log.Printf("unexpected tools file found %q", name)
			continue
		}
		vers := name[len(toolPrefix) : len(name)-len(".tgz")]
		var t state.Tools
		t.Binary, err = version.ParseBinary(vers)
		if err != nil {
			log.Printf("failed to parse %q: %v", vers, err)
			continue
		}
		if t.Major != majorVersion {
			log.Printf("tool %q found in wrong directory %q", name, dir)
			continue
		}
		t.URL, err = store.URL(name)
		if err != nil {
			log.Printf("cannot get URL for %q: %v", name, err)
			continue
		}
		toolsList = append(toolsList, &t)
	}
	return toolsList, nil
}

// PutTools builds the current version of the juju tools, uploads them
// to the given storage, and returns a Tools instance describing them.
// If vers is non-nil, a FORCE_VERSION file will be written into the
// tools directory which will override the current version.
// TODO(rog) find binaries from $PATH when not using a development
// version of juju within a $GOPATH.
func PutTools(storage Storage, vers *version.Binary) (*state.Tools, error) {
	// We create the entire archive before asking the environment to
	// start uploading so that we can be sure we have archived
	// correctly.
	f, err := ioutil.TempFile("", "juju-tgz")
	if err != nil {
		return nil, err
	}
	defer f.Close()
	defer os.Remove(f.Name())
	tvers, err := bundleTools(f, vers)
	if err != nil {
		return nil, err
	}
	_, err = f.Seek(0, 0)
	if err != nil {
		return nil, fmt.Errorf("cannot seek to start of tools archive: %v", err)
	}
	fi, err := f.Stat()
	if err != nil {
		return nil, fmt.Errorf("cannot stat newly made tools archive: %v", err)
	}
	p := ToolsStoragePath(tvers)
	log.Printf("environs: putting tools %v", p)
	err = storage.Put(p, f, fi.Size())
	if err != nil {
		return nil, err
	}
	url, err := storage.URL(p)
	if err != nil {
		return nil, err
	}
	return &state.Tools{tvers, url}, nil
}

// archive writes the executable files found in the given directory in
// gzipped tar format to w.  An error is returned if an entry inside dir
// is not a regular executable file.
func archive(w io.Writer, dir string) (err error) {
	entries, err := ioutil.ReadDir(dir)
	if err != nil {
		return err
	}

	gzw := gzip.NewWriter(w)
	defer closeErrorCheck(&err, gzw)

	tarw := tar.NewWriter(gzw)
	defer closeErrorCheck(&err, tarw)

	for _, ent := range entries {
		h := tarHeader(ent)
		// ignore local umask
		if isExecutable(ent) {
			h.Mode = 0755
		} else {
			h.Mode = 0644
		}
		err := tarw.WriteHeader(h)
		if err != nil {
			return err
		}
		if err := copyFile(tarw, filepath.Join(dir, ent.Name())); err != nil {
			return err
		}
	}
	return nil
}

// copyFile writes the contents of the given file to w.
func copyFile(w io.Writer, file string) error {
	f, err := os.Open(file)
	if err != nil {
		return err
	}
	defer f.Close()
	_, err = io.Copy(w, f)
	return err
}

// tarHeader returns a tar file header given the file's stat
// information.
func tarHeader(i os.FileInfo) *tar.Header {
	return &tar.Header{
		Typeflag:   tar.TypeReg,
		Name:       i.Name(),
		Size:       i.Size(),
		Mode:       int64(i.Mode() & 0777),
		ModTime:    i.ModTime(),
		AccessTime: i.ModTime(),
		ChangeTime: i.ModTime(),
		Uname:      "ubuntu",
		Gname:      "ubuntu",
	}
}

// isExecutable returns whether the given info
// represents a regular file executable by (at least) the user.
func isExecutable(i os.FileInfo) bool {
	return i.Mode()&(0100|os.ModeType) == 0100
}

// closeErrorCheck means that we can ensure that
// Close errors do not get lost even when we defer them,
func closeErrorCheck(errp *error, c io.Closer) {
	err := c.Close()
	if *errp == nil {
		*errp = err
	}
}

// BestTools the most recent tools compatible with the
// given specification. It returns nil if nothing appropriate
// was found.
func BestTools(toolsList []*state.Tools, vers version.Binary) *state.Tools {
	var bestTools *state.Tools
	for _, t := range toolsList {
		if t.Major != vers.Major ||
			t.Series != vers.Series ||
			t.Arch != vers.Arch {
			continue
		}
		if bestTools == nil || bestTools.Number.Less(t.Number) {
			bestTools = t
		}
	}
	return bestTools
}

const urlFile = "downloaded-url.txt"

// toolsParentDir returns the tools parent directory.
func toolsParentDir() string {
	return path.Join(VarDir, "tools")
}

// UnpackTools reads a set of juju tools in gzipped tar-archive
// format and unpacks them into the appropriate tools directory.
// If a valid tools directory already exists, UnpackTools returns
// without error.
func UnpackTools(tools *state.Tools, r io.Reader) (err error) {
	zr, err := gzip.NewReader(r)
	if err != nil {
		return err
	}
	defer zr.Close()

	// Make a temporary directory in the tools directory,
	// first ensuring that the tools directory exists.
	err = os.MkdirAll(toolsParentDir(), 0755)
	if err != nil {
		return err
	}
	dir, err := ioutil.TempDir(toolsParentDir(), "unpacking-")
	if err != nil {
		return err
	}
	defer removeAll(dir)

	tr := tar.NewReader(zr)
	for {
		hdr, err := tr.Next()
		if err == io.EOF {
			break
		}
		if err != nil {
			return err
		}
		if strings.ContainsAny(hdr.Name, "/\\") {
			return fmt.Errorf("bad name %q in tools archive", hdr.Name)
		}
		if hdr.Typeflag != tar.TypeReg {
			return fmt.Errorf("bad file type %#c in file %q in tools archive", hdr.Typeflag, hdr.Name)
		}
		name := filepath.Join(dir, hdr.Name)
		if err := writeFile(name, os.FileMode(hdr.Mode&0777), tr); err != nil {
			return fmt.Errorf("tar extract %q failed: %v", name, err)
		}
	}
	err = ioutil.WriteFile(filepath.Join(dir, urlFile), []byte(tools.URL), 0644)
	if err != nil {
		return err
	}

	err = os.Rename(dir, ToolsDir(tools.Binary))
	// If we've failed to rename the directory, it may be because
	// the directory already exists - if ReadTools succeeds, we
	// assume all's ok.
	if err != nil {
		_, err := ReadTools(tools.Binary)
		if err == nil {
			return nil
		}
	}
	return nil
}

func removeAll(dir string) {
	err := os.RemoveAll(dir)
	if err == nil || os.IsNotExist(err) {
		return
	}
	log.Printf("environs: cannot remove %q: %v", dir, err)
}

func writeFile(name string, mode os.FileMode, r io.Reader) error {
	f, err := os.OpenFile(name, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, mode)
	if err != nil {
		return err
	}
	defer f.Close()
	_, err = io.Copy(f, r)
	return err
}

// ReadTools checks that the tools for the given version exist
// and returns a Tools instance describing them.
func ReadTools(vers version.Binary) (*state.Tools, error) {
	dir := ToolsDir(vers)
	urlData, err := ioutil.ReadFile(filepath.Join(dir, urlFile))
	if err != nil {
		return nil, fmt.Errorf("cannot read URL in tools directory: %v", err)
	}
	url := strings.TrimSpace(string(urlData))
	if len(url) == 0 {
		return nil, fmt.Errorf("empty URL in tools directory %q", dir)
	}
	// TODO(rog): do more verification here too, such as checking
	// for the existence of certain files.
	return &state.Tools{
		URL:    url,
		Binary: vers,
	}, nil
}

// ChangeAgentTools atomically replaces the agent-specific symlink
// under the tools directory so it points to the previously unpacked
// version vers. It returns the new tools read.
func ChangeAgentTools(agentName string, vers version.Binary) (*state.Tools, error) {
	tools, err := ReadTools(vers)
	if err != nil {
		return nil, err
	}
	tmpName := AgentToolsDir("tmplink-" + agentName)
	err = os.Symlink(tools.Binary.String(), tmpName)
	if err != nil {
		return nil, fmt.Errorf("cannot create tools symlink: %v", err)
	}
	err = os.Rename(tmpName, AgentToolsDir(agentName))
	if err != nil {
		return nil, fmt.Errorf("cannot update tools symlink: %v", err)
	}
	return tools, nil
}

// ToolsStoragePath returns the slash-separated path that is used to store and
// retrieve the given version of the juju tools in a Storage.
func ToolsStoragePath(vers version.Binary) string {
	return toolPrefix + vers.String() + ".tgz"
}

// ToolsDir returns the slash-separated directory name that is used to
// store binaries for the given version of the juju tools.
func ToolsDir(vers version.Binary) string {
	return path.Join(VarDir, "tools", vers.String())
}

// AgentToolsDir returns the slash-separated directory name that is used
// to store binaries for the tools used by the given agent.
// Conventionally it is a symbolic link to the actual tools directory.
func AgentToolsDir(agentName string) string {
	return path.Join(VarDir, "tools", agentName)
}

// FindTools tries to find a set of tools compatible with the given
// version from the given environment.  If no tools are found and
// there's no other error, a NotFoundError is returned.  If there's
// anything compatible in the environ's Storage, it gets precedence over
// anything in its PublicStorage.
func FindTools(env Environ, vers version.Binary) (*state.Tools, error) {
	toolsList, err := ListTools(env.Storage(), vers.Major)
	if err != nil {
		return nil, err
	}
	tools := BestTools(toolsList, vers)
	if tools != nil {
		return tools, nil
	}
	toolsList, err = ListTools(env.PublicStorage(), vers.Major)
	if err != nil {
		return nil, err
	}
	tools = BestTools(toolsList, vers)
	if tools == nil {
		return nil, &NotFoundError{fmt.Errorf("no compatible tools found")}
	}
	return tools, nil
}

func setenv(env []string, val string) []string {
	prefix := val[0 : strings.Index(val, "=")+1]
	for i, eval := range env {
		if strings.HasPrefix(eval, prefix) {
			env[i] = val
			return env
		}
	}
	return append(env, val)
}

// bundleTools bundles all the current juju tools in gzipped tar
// format to the given writer.
func bundleTools(w io.Writer, vers *version.Binary) (version.Binary, error) {
	dir, err := ioutil.TempDir("", "juju-tools")
	if err != nil {
		return version.Binary{}, err
	}
	defer os.RemoveAll(dir)

	cmd := exec.Command("go", "install", "launchpad.net/juju-core/cmd/...")
	cmd.Env = setenv(os.Environ(), "GOBIN="+dir)
	out, err := cmd.CombinedOutput()
	if err != nil {
		return version.Binary{}, fmt.Errorf("build failed: %v; %s", err, out)
	}
	if vers != nil {
		if err := ioutil.WriteFile(filepath.Join(dir, "FORCE-VERSION"), []byte((*vers).String()), 0666); err != nil {
			return version.Binary{}, err
		}
	}
	cmd = exec.Command(filepath.Join(dir, "jujud"), "version")
	out, err = cmd.CombinedOutput()
	if err != nil {
		return version.Binary{}, fmt.Errorf("cannot get version from %q: %v; %s", cmd.Args[0], err, out)
	}
	tvs := strings.TrimSpace(string(out))
	tvers, err := version.ParseBinary(tvs)
	if err != nil {
		return version.Binary{}, fmt.Errorf("invalid version %q printed by jujud", tvs)
	}
	err = archive(w, dir)
	if err != nil {
		return version.Binary{}, err
	}
	return tvers, err
}

// EmptyStorage holds a StorageReader object that contains nothing.
var EmptyStorage StorageReader = emptyStorage{}

type emptyStorage struct{}

func (s emptyStorage) Get(name string) (io.ReadCloser, error) {
	return nil, &NotFoundError{fmt.Errorf("file %q not found in empty storage", name)}
}

func (s emptyStorage) URL(string) (string, error) {
	return "", fmt.Errorf("empty storage has no URLs")
}

func (s emptyStorage) List(prefix string) ([]string, error) {
	return nil, nil
}
<|endoftext|>


<commit_before>// Golang URL Minifier
// Creates tiny URLS from a given URL.
// https://github.com/nickvellios/Golang-URL-Minifier
// Nick Vellios
// 11/23/2016

package main

import (
	"encoding/json"
	"fmt"
	_ "github.com/lib/pq"
	"html/template"
	"net/http"
	"strconv"
	"time"
)

type urlMapRow struct {
	path    string
	url     string
	ip      string
	t_stamp string
}

type Charts struct {
	Cols []Columns `json:"cols"`
	Rws  []Rows    `json:"rows"`
}

type Columns struct {
	Label      string `json:"label"`
	ColumnType string `json:"type"`
}

type Rows struct {
	C []C2 `json:"c"`
}

type C2 struct {
	V string `json:"v"`
	F string `json:"f"`
}

// HTTP handler for /stats/ path
func (udb *urlDB) statsHandler(w http.ResponseWriter, r *http.Request) {
	var rws []Rows
	var cols = []Columns{
		{
			Label:      "X",
			ColumnType: "date",
		},
		{
			Label:      "Daily Total",
			ColumnType: "number",
		},
	}
	rows, err := udb.db.Query("SELECT COUNT(*) as count, t_stamp::DATE as ts FROM url_map GROUP BY ts ORDER BY ts")
	checkDBErr(err)

	for rows.Next() {
		var t time.Time
		var count int
		err := rows.Scan(&count, &t)
		checkDBErr(err)
		const layout = "Jan 2, 2006"
		date := t.Format(layout)

		datestr := fmt.Sprintf("Date(%d,%d,%d)", t.Year(), t.Month(), t.Day())
		dailytotal := strconv.FormatInt(int64(count), 10)

		rws = append(rws, Rows{
			C: []C2{
				{
					V: datestr,
					F: date,
				},
				{
					V: dailytotal,
					F: dailytotal,
				},
			},
		})
	}

	chart := &Charts{Cols: cols, Rws: rws}

	cht, _ := json.Marshal(chart)
	vars := map[string]interface{}{
		"js": template.HTML(string(cht)),
	}
	err = templates.ExecuteTemplate(w, "stats", vars)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}
<commit_msg>Fixed date on /stats/<commit_after>// Golang URL Minifier
// Creates tiny URLS from a given URL.
// https://github.com/nickvellios/Golang-URL-Minifier
// Nick Vellios
// 11/23/2016

package main

import (
	"encoding/json"
	"fmt"
	_ "github.com/lib/pq"
	"html/template"
	"net/http"
	"strconv"
	"time"
)

type urlMapRow struct {
	path    string
	url     string
	ip      string
	t_stamp string
}

type Charts struct {
	Cols []Columns `json:"cols"`
	Rws  []Rows    `json:"rows"`
}

type Columns struct {
	Label      string `json:"label"`
	ColumnType string `json:"type"`
}

type Rows struct {
	C []C2 `json:"c"`
}

type C2 struct {
	V string `json:"v"`
	F string `json:"f"`
}

// HTTP handler for /stats/ path
func (udb *urlDB) statsHandler(w http.ResponseWriter, r *http.Request) {
	var rws []Rows
	var cols = []Columns{
		{
			Label:      "X",
			ColumnType: "date",
		},
		{
			Label:      "Daily Total",
			ColumnType: "number",
		},
	}
	rows, err := udb.db.Query("SELECT COUNT(*) as count, t_stamp::DATE as ts FROM url_map GROUP BY ts ORDER BY ts")
	checkDBErr(err)

	for rows.Next() {
		var t time.Time
		var count int
		err := rows.Scan(&count, &t)
		checkDBErr(err)
		const layout = "Jan 2, 2006"
		date := t.Format(layout)

		datestr := fmt.Sprintf("Date(%d,%d,%d)", t.Year(), t.Month()-1, t.Day())
		dailytotal := strconv.FormatInt(int64(count), 10)

		rws = append(rws, Rows{
			C: []C2{
				{
					V: datestr,
					F: date,
				},
				{
					V: dailytotal,
					F: dailytotal,
				},
			},
		})
	}

	chart := &Charts{Cols: cols, Rws: rws}

	cht, _ := json.Marshal(chart)
	vars := map[string]interface{}{
		"js": template.HTML(string(cht)),
	}
	err = templates.ExecuteTemplate(w, "stats", vars)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}
<|endoftext|>


<commit_before>package client

import (
	"doozer/proto"
	"doozer/util"
	"encoding/binary"
	"log"
	"net"
	"io"
	"os"
	pb "goprotobuf.googlecode.com/hg/proto"
	"sync"
)

const (
	Valid = 1 << iota
	Done
)

var lg = util.NewLogger("client")

var (
	ErrNoAddrs = os.NewError("no known address")
)

// Response errors
var (
	ErrIsDir       = os.NewError("is a directory")
	ErrInvalidSnap = os.NewError("is a directory")
)

type OtherError string

func (o OtherError) String() string {
	return "Other error: " + string(o)
}

type Event struct {
	Cas  string
	Path string
	Body []byte
	Err  os.Error
}

type T proto.Request

type R proto.Response

func (r *R) err() os.Error {
	if r.ErrCode != nil {
		switch ec := int32(*r.ErrCode); ec {
		case proto.Response_OTHER:
			return OtherError(pb.GetString(r.ErrDetail))
		case proto.Response_ISDIR:
			return ErrIsDir
		case proto.Response_INVALID_SNAP:
			return ErrInvalidSnap
		case proto.Response_REDIRECT:
			return os.EAGAIN

		// These cases should never happen.
		case proto.Response_TAG_IN_USE:
			fallthrough
		case proto.Response_UNKNOWN_VERB:
			fallthrough
		default:
			return OtherError(proto.Response_Err_name[ec])
		}
	}
	return nil
}

type conn struct {
	c   net.Conn
	clk sync.Mutex // write lock
	err os.Error   // unrecoverable error

	// callback management
	n    int32             // next tag
	cb   map[int32]chan *R // callback channels
	cblk sync.Mutex

	lg *log.Logger

	// redirect handling
	redirectAddr string
	redirected   bool
}

func (c *conn) writeT(t *T) os.Error {
	if c.err != nil {
		return c.err
	}

	buf, err := pb.Marshal(t)
	if err != nil {
		return err
	}

	c.err = binary.Write(c.c, binary.BigEndian, int32(len(buf)))
	if c.err != nil {
		return c.err
	}

	for len(buf) > 0 {
		n, err := c.c.Write(buf)
		if err != nil {
			c.err = err
			return err
		}

		buf = buf[n:]
	}

	return nil
}

func (c *conn) send(t *T) (chan *R, os.Error) {
	if c.err != nil {
		return nil, c.err
	}

	ch := make(chan *R)

	// Find an unused tag and
	// put the reply chan in the table.
	c.cblk.Lock()
	for _, ok := c.cb[c.n]; ok; _, ok = c.cb[c.n] {
		c.n++
	}
	tag := c.n
	c.cb[tag] = ch
	c.cblk.Unlock()

	t.Tag = &tag

	c.clk.Lock()
	err := c.writeT(t)
	c.clk.Unlock()

	if err != nil {
		c.cblk.Lock()
		c.cb[tag] = nil, false
		c.cblk.Unlock()
		return nil, err
	}

	return ch, nil
}

func (c *conn) call(t *T) (*R, os.Error) {
	ch, err := c.send(t)
	if err != nil {
		return nil, err
	}

	r := <-ch
	if err := r.err(); err != nil {
		return nil, err
	}

	return r, nil
}

func (c *conn) readR() (*R, os.Error) {
	var size int32
	err := binary.Read(c.c, binary.BigEndian, &size)
	if err != nil {
		return nil, err
	}

	buf := make([]byte, size)
	_, err = io.ReadFull(c.c, buf)
	if err != nil {
		return nil, err
	}

	var r R
	err = pb.Unmarshal(buf, &r)
	if err != nil {
		return nil, err
	}
	return &r, nil
}

func (c *conn) readResponses() {
	for {
		r, err := c.readR()
		if err != nil {
			c.lg.Println(err)
			return
		}

		if r.ErrCode != nil && *r.ErrCode == proto.Response_REDIRECT {
			c.redirectAddr = pb.GetString(r.ErrDetail)
			c.redirected = true
		}

		tag := pb.GetInt32(r.Tag)
		flags := pb.GetInt32(r.Flags)

		c.cblk.Lock()
		ch, ok := c.cb[tag]
		if ok && flags&Done != 0 {
			c.cb[tag] = nil, false
		}
		c.cblk.Unlock()

		if ok {
			if flags&Valid != 0 {
				ch <- r
			}

			if flags&Done != 0 {
				close(ch)
			}
		}
	}
}

func (c *conn) cancel(tag int32) os.Error {
	verb := proto.NewRequest_Verb(proto.Request_CANCEL)
	_, err := c.call(&T{Verb: verb, Id: &tag})
	if err != nil {
		return err
	}

	c.cblk.Lock()
	ch, ok := c.cb[tag]
	if ok {
		c.cb[tag] = nil, false
	}
	c.cblk.Unlock()

	if ok {
		close(ch)
	}
	return nil
}

type Client struct {
	Name string
	c    *conn     // current connection
	ra    []string // known readable addresses
	wa    []string // known writable address
	lg   *log.Logger
	lk   sync.Mutex
}

// Name is the name of this cluster.
// Addr is an initial readable address to connect to.
func New(name, raddr string) *Client {
	return &Client{Name: name, ra: []string{raddr}}
}

func (c *Client) AddRaddr(a string) {
	c.lk.Lock()
	defer c.lk.Unlock()
	for _, s := range c.ra {
		if s == a {
			return
		}
	}
	c.ra = append(c.ra, a)
}

func (c *Client) AddWaddr(a string) {
	c.lk.Lock()
	defer c.lk.Unlock()
	for _, s := range c.wa {
		if s == a {
			return
		}
	}
	c.wa = append(c.wa, a)
}

func (cl *Client) dial(addr string) (*conn, os.Error) {
	var c conn
	var err os.Error

	c.c, err = net.Dial("tcp", "", addr)
	if err != nil {
		return nil, err
	}

	c.cb = make(map[int32]chan *R)
	c.lg = util.NewLogger(addr)
	go c.readResponses()
	return &c, nil
}

// This is a little subtle. We want to follow redirects while still pipelining
// requests, and we want to allow as many requests as possible to succeed
// without retrying unnecessarily.
//
// In particular, reads never need to redirect, and writes must always go to
// the leader. So we want that read requests never retry, and write requests
// retry if and only if necessary. Here's how it works:
//
// In the conn, when we get a redirect response, we raise a flag noting
// the new address. This flag only goes up, never down. This flag effectively
// means the connection is deprecated. Any pending requests can go ahead, but
// new requests should use the new address.
//
// In the Client, when we notice that a redirect has occurred (i.e. the flag is
// set), we establish a new connection to the new address. Calls in the future
// will use the new connection. But we also allow the old connection to
// continue functioning as it was. Any writes on the old connection will retry,
// and then they are guaranteed to pick up the new connection. Any reads on the
// old connection will just succeed directly.
func (cl *Client) conn() (c *conn, err os.Error) {
	cl.lk.Lock()
	defer cl.lk.Unlock()

	if cl.c == nil {
		if len(cl.ra) < 1 {
			return nil, ErrNoAddrs
		}

		cl.c, err = cl.dial(cl.ra[0])
		if err != nil {
			cl.ra = cl.ra[1:]
		}

		return cl.c, err
	}

	if cl.c.redirected {
		cl.AddWaddr(cl.c.redirectAddr)
		if len(cl.wa) < 1 {
			return nil, ErrNoAddrs
		}

		cl.c, err = cl.dial(cl.wa[0])
		if err != nil {
			cl.wa = cl.wa[1:]
		}

		return cl.c, err
	}

	return cl.c, nil
}

func (cl *Client) call(verb int32, t *T) (r *R, err os.Error) {
	t.Verb = proto.NewRequest_Verb(verb)

	for err = os.EAGAIN; err == os.EAGAIN; {
		var c *conn
		c, err = cl.conn()
		if err != nil {
			continue
		}

		r, err = c.call(t)
	}

	if err != nil {
		lg.Println(err)
	}

	return
}

func (cl *Client) Join(id, addr string) (seqn uint64, snapshot string, err os.Error) {
	r, err := cl.call(proto.Request_JOIN, &T{Path: &id, Value: []byte(addr)})
	if err != nil {
		return 0, "", err
	}

	return uint64(pb.GetInt64(r.Seqn)), string(r.Value), nil
}

func (cl *Client) Set(path, oldCas string, body []byte) (newCas string, err os.Error) {
	r, err := cl.call(proto.Request_SET, &T{Path: &path, Value: body, Cas: &oldCas})
	if err != nil {
		return "", err
	}

	return pb.GetString(r.Cas), nil
}

// Returns the body and CAS token of the file at path.
// If snapId is 0, uses the current state, otherwise,
// snapId must be a value previously returned from Snap.
// If path does not denote a file, returns an error.
func (cl *Client) Get(path string, snapId int32) (body []byte, cas string, err os.Error) {
	r, err := cl.call(proto.Request_GET, &T{Path: &path, Id: &snapId})
	if err != nil {
		return nil, "", err
	}

	return r.Value, pb.GetString(r.Cas), nil
}

func (cl *Client) Del(path, cas string) os.Error {
	_, err := cl.call(proto.Request_DEL, &T{Path: &path, Cas: &cas})
	return err
}

func (cl *Client) Noop() os.Error {
	_, err := cl.call(proto.Request_NOOP, &T{})
	return err
}

func (cl *Client) Checkin(id, cas string) (string, os.Error) {
	r, err := cl.call(proto.Request_CHECKIN, &T{Path: &id, Cas: &cas})
	if err != nil {
		return "", err
	}

	return pb.GetString(r.Cas), nil
}

func (cl *Client) Snap() (id int32, ver uint64, err os.Error) {
	r, err := cl.call(proto.Request_SNAP, &T{})
	if err != nil {
		return 0, 0, err
	}

	return pb.GetInt32(r.Id), uint64(pb.GetInt64(r.Seqn)), nil
}

func (cl *Client) DelSnap(id int32) os.Error {
	_, err := cl.call(proto.Request_DELSNAP, &T{Id: &id})
	return err
}

func (cl *Client) Watch(glob string) (*Watch, os.Error) {
	c, err := cl.conn()
	if err != nil {
		return nil, err
	}

	var t T
	t.Verb = proto.NewRequest_Verb(proto.Request_WATCH)
	t.Path = &glob
	ch, err := c.send(&t)
	if err != nil {
		return nil, err
	}

	evs := make(chan *Event)
	w := &Watch{evs, c, *t.Tag}
	go func() {
		for r := range ch {
			var ev Event
			if err := r.err(); err != nil {
				ev.Err = err
			} else {
				ev.Cas = pb.GetString(r.Cas)
				ev.Path = pb.GetString(r.Path)
				ev.Body = r.Value
			}
			evs <- &ev
		}
		close(evs)
	}()

	return w, nil
}

type Watch struct {
	C   <-chan *Event // to caller
	c   *conn
	tag int32
}

func (w *Watch) Cancel() os.Error {
	return w.c.cancel(w.tag)
}
<commit_msg>fix out-of-date comment<commit_after>package client

import (
	"doozer/proto"
	"doozer/util"
	"encoding/binary"
	"log"
	"net"
	"io"
	"os"
	pb "goprotobuf.googlecode.com/hg/proto"
	"sync"
)

const (
	Valid = 1 << iota
	Done
)

var lg = util.NewLogger("client")

var (
	ErrNoAddrs = os.NewError("no known address")
)

// Response errors
var (
	ErrIsDir       = os.NewError("is a directory")
	ErrInvalidSnap = os.NewError("is a directory")
)

type OtherError string

func (o OtherError) String() string {
	return "Other error: " + string(o)
}

type Event struct {
	Cas  string
	Path string
	Body []byte
	Err  os.Error
}

type T proto.Request

type R proto.Response

func (r *R) err() os.Error {
	if r.ErrCode != nil {
		switch ec := int32(*r.ErrCode); ec {
		case proto.Response_OTHER:
			return OtherError(pb.GetString(r.ErrDetail))
		case proto.Response_ISDIR:
			return ErrIsDir
		case proto.Response_INVALID_SNAP:
			return ErrInvalidSnap
		case proto.Response_REDIRECT:
			return os.EAGAIN

		// These cases should never happen.
		case proto.Response_TAG_IN_USE:
			fallthrough
		case proto.Response_UNKNOWN_VERB:
			fallthrough
		default:
			return OtherError(proto.Response_Err_name[ec])
		}
	}
	return nil
}

type conn struct {
	c   net.Conn
	clk sync.Mutex // write lock
	err os.Error   // unrecoverable error

	// callback management
	n    int32             // next tag
	cb   map[int32]chan *R // callback channels
	cblk sync.Mutex

	lg *log.Logger

	// redirect handling
	redirectAddr string
	redirected   bool
}

func (c *conn) writeT(t *T) os.Error {
	if c.err != nil {
		return c.err
	}

	buf, err := pb.Marshal(t)
	if err != nil {
		return err
	}

	c.err = binary.Write(c.c, binary.BigEndian, int32(len(buf)))
	if c.err != nil {
		return c.err
	}

	for len(buf) > 0 {
		n, err := c.c.Write(buf)
		if err != nil {
			c.err = err
			return err
		}

		buf = buf[n:]
	}

	return nil
}

func (c *conn) send(t *T) (chan *R, os.Error) {
	if c.err != nil {
		return nil, c.err
	}

	ch := make(chan *R)

	// Find an unused tag and
	// put the reply chan in the table.
	c.cblk.Lock()
	for _, ok := c.cb[c.n]; ok; _, ok = c.cb[c.n] {
		c.n++
	}
	tag := c.n
	c.cb[tag] = ch
	c.cblk.Unlock()

	t.Tag = &tag

	c.clk.Lock()
	err := c.writeT(t)
	c.clk.Unlock()

	if err != nil {
		c.cblk.Lock()
		c.cb[tag] = nil, false
		c.cblk.Unlock()
		return nil, err
	}

	return ch, nil
}

func (c *conn) call(t *T) (*R, os.Error) {
	ch, err := c.send(t)
	if err != nil {
		return nil, err
	}

	r := <-ch
	if err := r.err(); err != nil {
		return nil, err
	}

	return r, nil
}

func (c *conn) readR() (*R, os.Error) {
	var size int32
	err := binary.Read(c.c, binary.BigEndian, &size)
	if err != nil {
		return nil, err
	}

	buf := make([]byte, size)
	_, err = io.ReadFull(c.c, buf)
	if err != nil {
		return nil, err
	}

	var r R
	err = pb.Unmarshal(buf, &r)
	if err != nil {
		return nil, err
	}
	return &r, nil
}

func (c *conn) readResponses() {
	for {
		r, err := c.readR()
		if err != nil {
			c.lg.Println(err)
			return
		}

		if r.ErrCode != nil && *r.ErrCode == proto.Response_REDIRECT {
			c.redirectAddr = pb.GetString(r.ErrDetail)
			c.redirected = true
		}

		tag := pb.GetInt32(r.Tag)
		flags := pb.GetInt32(r.Flags)

		c.cblk.Lock()
		ch, ok := c.cb[tag]
		if ok && flags&Done != 0 {
			c.cb[tag] = nil, false
		}
		c.cblk.Unlock()

		if ok {
			if flags&Valid != 0 {
				ch <- r
			}

			if flags&Done != 0 {
				close(ch)
			}
		}
	}
}

func (c *conn) cancel(tag int32) os.Error {
	verb := proto.NewRequest_Verb(proto.Request_CANCEL)
	_, err := c.call(&T{Verb: verb, Id: &tag})
	if err != nil {
		return err
	}

	c.cblk.Lock()
	ch, ok := c.cb[tag]
	if ok {
		c.cb[tag] = nil, false
	}
	c.cblk.Unlock()

	if ok {
		close(ch)
	}
	return nil
}

type Client struct {
	Name string
	c    *conn     // current connection
	ra    []string // known readable addresses
	wa    []string // known writable address
	lg   *log.Logger
	lk   sync.Mutex
}

// Name is the name of this cluster.
// Addr is an initial readable address to connect to.
func New(name, raddr string) *Client {
	return &Client{Name: name, ra: []string{raddr}}
}

func (c *Client) AddRaddr(a string) {
	c.lk.Lock()
	defer c.lk.Unlock()
	for _, s := range c.ra {
		if s == a {
			return
		}
	}
	c.ra = append(c.ra, a)
}

func (c *Client) AddWaddr(a string) {
	c.lk.Lock()
	defer c.lk.Unlock()
	for _, s := range c.wa {
		if s == a {
			return
		}
	}
	c.wa = append(c.wa, a)
}

func (cl *Client) dial(addr string) (*conn, os.Error) {
	var c conn
	var err os.Error

	c.c, err = net.Dial("tcp", "", addr)
	if err != nil {
		return nil, err
	}

	c.cb = make(map[int32]chan *R)
	c.lg = util.NewLogger(addr)
	go c.readResponses()
	return &c, nil
}

// This is a little subtle. We want to follow redirects while still pipelining
// requests, and we want to allow as many requests as possible to succeed
// without retrying unnecessarily.
//
// In particular, reads never need to redirect, and writes must always go to
// a CAL node. So we want that read requests never retry, and write requests
// retry if and only if necessary. Here's how it works:
//
// In the conn, when we get a redirect response, we raise a flag noting
// the new address. This flag only goes up, never down. This flag effectively
// means the connection is deprecated. Any pending requests can go ahead, but
// new requests should use the new address.
//
// In the Client, when we notice that a redirect has occurred (i.e. the flag is
// set), we establish a new connection to the new address. Calls in the future
// will use the new connection. But we also allow the old connection to
// continue functioning as it was. Any writes on the old connection will retry,
// and then they are guaranteed to pick up the new connection. Any reads on the
// old connection will just succeed directly.
func (cl *Client) conn() (c *conn, err os.Error) {
	cl.lk.Lock()
	defer cl.lk.Unlock()

	if cl.c == nil {
		if len(cl.ra) < 1 {
			return nil, ErrNoAddrs
		}

		cl.c, err = cl.dial(cl.ra[0])
		if err != nil {
			cl.ra = cl.ra[1:]
		}

		return cl.c, err
	}

	if cl.c.redirected {
		cl.AddWaddr(cl.c.redirectAddr)
		if len(cl.wa) < 1 {
			return nil, ErrNoAddrs
		}

		cl.c, err = cl.dial(cl.wa[0])
		if err != nil {
			cl.wa = cl.wa[1:]
		}

		return cl.c, err
	}

	return cl.c, nil
}

func (cl *Client) call(verb int32, t *T) (r *R, err os.Error) {
	t.Verb = proto.NewRequest_Verb(verb)

	for err = os.EAGAIN; err == os.EAGAIN; {
		var c *conn
		c, err = cl.conn()
		if err != nil {
			continue
		}

		r, err = c.call(t)
	}

	if err != nil {
		lg.Println(err)
	}

	return
}

func (cl *Client) Join(id, addr string) (seqn uint64, snapshot string, err os.Error) {
	r, err := cl.call(proto.Request_JOIN, &T{Path: &id, Value: []byte(addr)})
	if err != nil {
		return 0, "", err
	}

	return uint64(pb.GetInt64(r.Seqn)), string(r.Value), nil
}

func (cl *Client) Set(path, oldCas string, body []byte) (newCas string, err os.Error) {
	r, err := cl.call(proto.Request_SET, &T{Path: &path, Value: body, Cas: &oldCas})
	if err != nil {
		return "", err
	}

	return pb.GetString(r.Cas), nil
}

// Returns the body and CAS token of the file at path.
// If snapId is 0, uses the current state, otherwise,
// snapId must be a value previously returned from Snap.
// If path does not denote a file, returns an error.
func (cl *Client) Get(path string, snapId int32) (body []byte, cas string, err os.Error) {
	r, err := cl.call(proto.Request_GET, &T{Path: &path, Id: &snapId})
	if err != nil {
		return nil, "", err
	}

	return r.Value, pb.GetString(r.Cas), nil
}

func (cl *Client) Del(path, cas string) os.Error {
	_, err := cl.call(proto.Request_DEL, &T{Path: &path, Cas: &cas})
	return err
}

func (cl *Client) Noop() os.Error {
	_, err := cl.call(proto.Request_NOOP, &T{})
	return err
}

func (cl *Client) Checkin(id, cas string) (string, os.Error) {
	r, err := cl.call(proto.Request_CHECKIN, &T{Path: &id, Cas: &cas})
	if err != nil {
		return "", err
	}

	return pb.GetString(r.Cas), nil
}

func (cl *Client) Snap() (id int32, ver uint64, err os.Error) {
	r, err := cl.call(proto.Request_SNAP, &T{})
	if err != nil {
		return 0, 0, err
	}

	return pb.GetInt32(r.Id), uint64(pb.GetInt64(r.Seqn)), nil
}

func (cl *Client) DelSnap(id int32) os.Error {
	_, err := cl.call(proto.Request_DELSNAP, &T{Id: &id})
	return err
}

func (cl *Client) Watch(glob string) (*Watch, os.Error) {
	c, err := cl.conn()
	if err != nil {
		return nil, err
	}

	var t T
	t.Verb = proto.NewRequest_Verb(proto.Request_WATCH)
	t.Path = &glob
	ch, err := c.send(&t)
	if err != nil {
		return nil, err
	}

	evs := make(chan *Event)
	w := &Watch{evs, c, *t.Tag}
	go func() {
		for r := range ch {
			var ev Event
			if err := r.err(); err != nil {
				ev.Err = err
			} else {
				ev.Cas = pb.GetString(r.Cas)
				ev.Path = pb.GetString(r.Path)
				ev.Body = r.Value
			}
			evs <- &ev
		}
		close(evs)
	}()

	return w, nil
}

type Watch struct {
	C   <-chan *Event // to caller
	c   *conn
	tag int32
}

func (w *Watch) Cancel() os.Error {
	return w.c.cancel(w.tag)
}
<|endoftext|>


<commit_before>// Copyright 2011 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 build

import (
	"errors"
	"fmt"
	"log"
	"os"
	"path/filepath"
	"runtime"
)

// Path is a validated list of Trees derived from $GOROOT and $GOPATH at init.
var Path []*Tree

// Tree describes a Go source tree, either $GOROOT or one from $GOPATH.
type Tree struct {
	Path   string
	Goroot bool
}

func newTree(p string) (*Tree, error) {
	if !filepath.IsAbs(p) {
		return nil, errors.New("must be absolute")
	}
	ep, err := filepath.EvalSymlinks(p)
	if err != nil {
		return nil, err
	}
	return &Tree{Path: ep}, nil
}

// SrcDir returns the tree's package source directory.
func (t *Tree) SrcDir() string {
	if t.Goroot {
		return filepath.Join(t.Path, "src", "pkg")
	}
	return filepath.Join(t.Path, "src")
}

// PkgDir returns the tree's package object directory.
func (t *Tree) PkgDir() string {
	goos, goarch := runtime.GOOS, runtime.GOARCH
	if e := os.Getenv("GOOS"); e != "" {
		goos = e
	}
	if e := os.Getenv("GOARCH"); e != "" {
		goarch = e
	}
	return filepath.Join(t.Path, "pkg", goos+"_"+goarch)
}

// BinDir returns the tree's binary executable directory.
func (t *Tree) BinDir() string {
	if t.Goroot {
		if gobin := os.Getenv("GOBIN"); gobin != "" {
			return filepath.Clean(gobin)
		}
	}
	return filepath.Join(t.Path, "bin")
}

// HasSrc returns whether the given package's
// source can be found inside this Tree.
func (t *Tree) HasSrc(pkg string) bool {
	fi, err := os.Stat(filepath.Join(t.SrcDir(), pkg))
	if err != nil {
		return false
	}
	return fi.IsDir()
}

// HasPkg returns whether the given package's
// object file can be found inside this Tree.
func (t *Tree) HasPkg(pkg string) bool {
	fi, err := os.Stat(filepath.Join(t.PkgDir(), pkg+".a"))
	if err != nil {
		return false
	}
	return !fi.IsDir()
	// TODO(adg): check object version is consistent
}

var (
	ErrNotFound     = errors.New("package could not be found locally")
	ErrTreeNotFound = errors.New("no valid GOROOT or GOPATH could be found")
)

// FindTree takes an import or filesystem path and returns the
// tree where the package source should be and the package import path.
func FindTree(path string) (tree *Tree, pkg string, err error) {
	if isLocalPath(path) {
		if path, err = filepath.Abs(path); err != nil {
			return
		}
		if path, err = filepath.EvalSymlinks(path); err != nil {
			return
		}
		for _, t := range Path {
			tpath := t.SrcDir() + string(filepath.Separator)
			if !filepath.HasPrefix(path, tpath) {
				continue
			}
			tree = t
			pkg = filepath.ToSlash(path[len(tpath):])
			return
		}
		err = fmt.Errorf("path %q not inside a GOPATH", path)
		return
	}
	tree = defaultTree
	pkg = filepath.ToSlash(path)
	for _, t := range Path {
		if t.HasSrc(pkg) {
			tree = t
			return
		}
	}
	if tree == nil {
		err = ErrTreeNotFound
	} else {
		err = ErrNotFound
	}
	return
}

// isLocalPath returns whether the given path is local (/foo ./foo ../foo . ..)
// Windows paths that starts with drive letter (c:\foo c:foo) are considered local.
func isLocalPath(s string) bool {
	const sep = string(filepath.Separator)
	return s == "." || s == ".." ||
		filepath.HasPrefix(s, sep) ||
		filepath.HasPrefix(s, "."+sep) || filepath.HasPrefix(s, ".."+sep) ||
		filepath.VolumeName(s) != ""
}

var (
	// argument lists used by the build's gc and ld methods
	gcImportArgs []string
	ldImportArgs []string

	// default tree for remote packages
	defaultTree *Tree
)

// set up Path: parse and validate GOROOT and GOPATH variables
func init() {
	root := runtime.GOROOT()
	t, err := newTree(root)
	if err != nil {
		log.Printf("invalid GOROOT %q: %v", root, err)
	} else {
		t.Goroot = true
		Path = []*Tree{t}
	}

Loop:
	for _, p := range filepath.SplitList(os.Getenv("GOPATH")) {
		if p == "" {
			continue
		}
		t, err := newTree(p)
		if err != nil {
			log.Printf("invalid GOPATH %q: %v", p, err)
			continue
		}

		// Check for dupes.
		// TODO(alexbrainman): make this correct under windows (case insensitive).
		for _, t2 := range Path {
			if t2.Path != t.Path {
				continue
			}
			if t2.Goroot {
				log.Printf("GOPATH is the same as GOROOT: %q", t.Path)
			} else {
				log.Printf("duplicate GOPATH entry: %q", t.Path)
			}
			continue Loop
		}

		Path = append(Path, t)
		gcImportArgs = append(gcImportArgs, "-I", t.PkgDir())
		ldImportArgs = append(ldImportArgs, "-L", t.PkgDir())

		// select first GOPATH entry as default
		if defaultTree == nil {
			defaultTree = t
		}
	}

	// use GOROOT if no valid GOPATH specified
	if defaultTree == nil && len(Path) > 0 {
		defaultTree = Path[0]
	}
}
<commit_msg>go/build: silence all warnings<commit_after>// Copyright 2011 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 build

import (
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"runtime"
)

// Path is a validated list of Trees derived from $GOROOT and $GOPATH at init.
var Path []*Tree

// Tree describes a Go source tree, either $GOROOT or one from $GOPATH.
type Tree struct {
	Path   string
	Goroot bool
}

func newTree(p string) (*Tree, error) {
	if !filepath.IsAbs(p) {
		return nil, errors.New("must be absolute")
	}
	ep, err := filepath.EvalSymlinks(p)
	if err != nil {
		return nil, err
	}
	return &Tree{Path: ep}, nil
}

// SrcDir returns the tree's package source directory.
func (t *Tree) SrcDir() string {
	if t.Goroot {
		return filepath.Join(t.Path, "src", "pkg")
	}
	return filepath.Join(t.Path, "src")
}

// PkgDir returns the tree's package object directory.
func (t *Tree) PkgDir() string {
	goos, goarch := runtime.GOOS, runtime.GOARCH
	if e := os.Getenv("GOOS"); e != "" {
		goos = e
	}
	if e := os.Getenv("GOARCH"); e != "" {
		goarch = e
	}
	return filepath.Join(t.Path, "pkg", goos+"_"+goarch)
}

// BinDir returns the tree's binary executable directory.
func (t *Tree) BinDir() string {
	if t.Goroot {
		if gobin := os.Getenv("GOBIN"); gobin != "" {
			return filepath.Clean(gobin)
		}
	}
	return filepath.Join(t.Path, "bin")
}

// HasSrc returns whether the given package's
// source can be found inside this Tree.
func (t *Tree) HasSrc(pkg string) bool {
	fi, err := os.Stat(filepath.Join(t.SrcDir(), pkg))
	if err != nil {
		return false
	}
	return fi.IsDir()
}

// HasPkg returns whether the given package's
// object file can be found inside this Tree.
func (t *Tree) HasPkg(pkg string) bool {
	fi, err := os.Stat(filepath.Join(t.PkgDir(), pkg+".a"))
	if err != nil {
		return false
	}
	return !fi.IsDir()
}

var (
	ErrNotFound     = errors.New("package could not be found locally")
	ErrTreeNotFound = errors.New("no valid GOROOT or GOPATH could be found")
)

// FindTree takes an import or filesystem path and returns the
// tree where the package source should be and the package import path.
func FindTree(path string) (tree *Tree, pkg string, err error) {
	if isLocalPath(path) {
		if path, err = filepath.Abs(path); err != nil {
			return
		}
		if path, err = filepath.EvalSymlinks(path); err != nil {
			return
		}
		for _, t := range Path {
			tpath := t.SrcDir() + string(filepath.Separator)
			if !filepath.HasPrefix(path, tpath) {
				continue
			}
			tree = t
			pkg = filepath.ToSlash(path[len(tpath):])
			return
		}
		err = fmt.Errorf("path %q not inside a GOPATH", path)
		return
	}
	tree = defaultTree
	pkg = filepath.ToSlash(path)
	for _, t := range Path {
		if t.HasSrc(pkg) {
			tree = t
			return
		}
	}
	if tree == nil {
		err = ErrTreeNotFound
	} else {
		err = ErrNotFound
	}
	return
}

// isLocalPath returns whether the given path is local (/foo ./foo ../foo . ..)
// Windows paths that starts with drive letter (c:\foo c:foo) are considered local.
func isLocalPath(s string) bool {
	const sep = string(filepath.Separator)
	return s == "." || s == ".." ||
		filepath.HasPrefix(s, sep) ||
		filepath.HasPrefix(s, "."+sep) || filepath.HasPrefix(s, ".."+sep) ||
		filepath.VolumeName(s) != ""
}

var (
	// argument lists used by the build's gc and ld methods
	gcImportArgs []string
	ldImportArgs []string

	// default tree for remote packages
	defaultTree *Tree
)

// set up Path: parse and validate GOROOT and GOPATH variables
func init() {
	root := runtime.GOROOT()
	t, err := newTree(root)
	if err == nil {
		t.Goroot = true
		Path = []*Tree{t}
	}

	for _, p := range filepath.SplitList(os.Getenv("GOPATH")) {
		if p == "" {
			continue
		}
		t, err := newTree(p)
		if err != nil {
			continue
		}

		Path = append(Path, t)
		gcImportArgs = append(gcImportArgs, "-I", t.PkgDir())
		ldImportArgs = append(ldImportArgs, "-L", t.PkgDir())

		// select first GOPATH entry as default
		if defaultTree == nil {
			defaultTree = t
		}
	}

	// use GOROOT if no valid GOPATH specified
	if defaultTree == nil && len(Path) > 0 {
		defaultTree = Path[0]
	}
}
<|endoftext|>


<commit_before>// Copyright 2009 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.

// +build ignore

package main

import (
	"bytes"
	"expvar"
	"flag"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"strconv"
)

// hello world, the web server
var helloRequests = expvar.NewInt("hello-requests")

func HelloServer(w http.ResponseWriter, req *http.Request) {
	helloRequests.Add(1)
	io.WriteString(w, "hello, world!\n")
}

// Simple counter server. POSTing to it will set the value.
type Counter struct {
	n int
}

// This makes Counter satisfy the expvar.Var interface, so we can export
// it directly.
func (ctr *Counter) String() string { return fmt.Sprintf("%d", ctr.n) }

func (ctr *Counter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	switch req.Method {
	case "GET":
		ctr.n++
	case "POST":
		buf := new(bytes.Buffer)
		io.Copy(buf, req.Body)
		body := buf.String()
		if n, err := strconv.Atoi(body); err != nil {
			fmt.Fprintf(w, "bad POST: %v\nbody: [%v]\n", err, body)
		} else {
			ctr.n = n
			fmt.Fprint(w, "counter reset\n")
		}
	}
	fmt.Fprintf(w, "counter = %d\n", ctr.n)
}

// simple flag server
var booleanflag = flag.Bool("boolean", true, "another flag for testing")

func FlagServer(w http.ResponseWriter, req *http.Request) {
	w.Header().Set("Content-Type", "text/plain; charset=utf-8")
	fmt.Fprint(w, "Flags:\n")
	flag.VisitAll(func(f *flag.Flag) {
		if f.Value.String() != f.DefValue {
			fmt.Fprintf(w, "%s = %s [default = %s]\n", f.Name, f.Value.String(), f.DefValue)
		} else {
			fmt.Fprintf(w, "%s = %s\n", f.Name, f.Value.String())
		}
	})
}

// simple argument server
func ArgServer(w http.ResponseWriter, req *http.Request) {
	for _, s := range os.Args {
		fmt.Fprint(w, s, " ")
	}
}

// a channel (just for the fun of it)
type Chan chan int

func ChanCreate() Chan {
	c := make(Chan)
	go func(c Chan) {
		for x := 0; ; x++ {
			c <- x
		}
	}(c)
	return c
}

func (ch Chan) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	io.WriteString(w, fmt.Sprintf("channel send #%d\n", <-ch))
}

// exec a program, redirecting output
func DateServer(rw http.ResponseWriter, req *http.Request) {
	rw.Header().Set("Content-Type", "text/plain; charset=utf-8")
	r, w, err := os.Pipe()
	if err != nil {
		fmt.Fprintf(rw, "pipe: %s\n", err)
		return
	}

	p, err := os.StartProcess("/bin/date", []string{"date"}, &os.ProcAttr{Files: []*os.File{nil, w, w}})
	defer r.Close()
	w.Close()
	if err != nil {
		fmt.Fprintf(rw, "fork/exec: %s\n", err)
		return
	}
	io.Copy(rw, r)
	wait, err := p.Wait(0)
	if err != nil {
		fmt.Fprintf(rw, "wait: %s\n", err)
		return
	}
	if !wait.Exited() || wait.ExitStatus() != 0 {
		fmt.Fprintf(rw, "date: %v\n", wait)
		return
	}
}

func Logger(w http.ResponseWriter, req *http.Request) {
	log.Print(req.URL.Raw)
	w.WriteHeader(404)
	w.Write([]byte("oops"))
}

var webroot = flag.String("root", "/home/rsc", "web root directory")

func main() {
	flag.Parse()

	// The counter is published as a variable directly.
	ctr := new(Counter)
	http.Handle("/counter", ctr)
	expvar.Publish("counter", ctr)

	http.Handle("/", http.HandlerFunc(Logger))
	http.Handle("/go/", http.StripPrefix("/go/", http.FileServer(http.Dir(*webroot))))
	http.Handle("/flags", http.HandlerFunc(FlagServer))
	http.Handle("/args", http.HandlerFunc(ArgServer))
	http.Handle("/go/hello", http.HandlerFunc(HelloServer))
	http.Handle("/chan", ChanCreate())
	http.Handle("/date", http.HandlerFunc(DateServer))
	err := http.ListenAndServe(":12345", nil)
	if err != nil {
		log.Panicln("ListenAndServe:", err)
	}
}
<commit_msg>net/http: ensure triv.go compiles and runs<commit_after>// Copyright 2009 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.

// +build ignore

package main

import (
	"bytes"
	"expvar"
	"flag"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"os/exec"
	"strconv"
)

// hello world, the web server
var helloRequests = expvar.NewInt("hello-requests")

func HelloServer(w http.ResponseWriter, req *http.Request) {
	helloRequests.Add(1)
	io.WriteString(w, "hello, world!\n")
}

// Simple counter server. POSTing to it will set the value.
type Counter struct {
	n int
}

// This makes Counter satisfy the expvar.Var interface, so we can export
// it directly.
func (ctr *Counter) String() string { return fmt.Sprintf("%d", ctr.n) }

func (ctr *Counter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	switch req.Method {
	case "GET":
		ctr.n++
	case "POST":
		buf := new(bytes.Buffer)
		io.Copy(buf, req.Body)
		body := buf.String()
		if n, err := strconv.Atoi(body); err != nil {
			fmt.Fprintf(w, "bad POST: %v\nbody: [%v]\n", err, body)
		} else {
			ctr.n = n
			fmt.Fprint(w, "counter reset\n")
		}
	}
	fmt.Fprintf(w, "counter = %d\n", ctr.n)
}

// simple flag server
var booleanflag = flag.Bool("boolean", true, "another flag for testing")

func FlagServer(w http.ResponseWriter, req *http.Request) {
	w.Header().Set("Content-Type", "text/plain; charset=utf-8")
	fmt.Fprint(w, "Flags:\n")
	flag.VisitAll(func(f *flag.Flag) {
		if f.Value.String() != f.DefValue {
			fmt.Fprintf(w, "%s = %s [default = %s]\n", f.Name, f.Value.String(), f.DefValue)
		} else {
			fmt.Fprintf(w, "%s = %s\n", f.Name, f.Value.String())
		}
	})
}

// simple argument server
func ArgServer(w http.ResponseWriter, req *http.Request) {
	for _, s := range os.Args {
		fmt.Fprint(w, s, " ")
	}
}

// a channel (just for the fun of it)
type Chan chan int

func ChanCreate() Chan {
	c := make(Chan)
	go func(c Chan) {
		for x := 0; ; x++ {
			c <- x
		}
	}(c)
	return c
}

func (ch Chan) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	io.WriteString(w, fmt.Sprintf("channel send #%d\n", <-ch))
}

// exec a program, redirecting output
func DateServer(rw http.ResponseWriter, req *http.Request) {
	rw.Header().Set("Content-Type", "text/plain; charset=utf-8")

	date, err := exec.Command("/bin/date").Output()
	if err != nil {
		http.Error(rw, err.Error(), 500)
		return
	}
	rw.Write(date)
}

func Logger(w http.ResponseWriter, req *http.Request) {
	log.Print(req.URL)
	http.Error(w, "oops", 404)
}

var webroot = flag.String("root", "/home/rsc", "web root directory")

func main() {
	flag.Parse()

	// The counter is published as a variable directly.
	ctr := new(Counter)
	http.Handle("/counter", ctr)
	expvar.Publish("counter", ctr)

	http.Handle("/", http.HandlerFunc(Logger))
	http.Handle("/go/", http.StripPrefix("/go/", http.FileServer(http.Dir(*webroot))))
	http.Handle("/flags", http.HandlerFunc(FlagServer))
	http.Handle("/args", http.HandlerFunc(ArgServer))
	http.Handle("/go/hello", http.HandlerFunc(HelloServer))
	http.Handle("/chan", ChanCreate())
	http.Handle("/date", http.HandlerFunc(DateServer))
	err := http.ListenAndServe(":12345", nil)
	if err != nil {
		log.Panicln("ListenAndServe:", err)
	}
}
<|endoftext|>


<commit_before>// Copyright 2009 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.

// +build darwin dragonfly freebsd linux netbsd openbsd windows

package os

import (
	"syscall"
	"time"
)

func sigpipe() // implemented in package runtime

// Link creates newname as a hard link to the oldname file.
// If there is an error, it will be of type *LinkError.
func Link(oldname, newname string) error {
	e := syscall.Link(oldname, newname)
	if e != nil {
		return &LinkError{"link", oldname, newname, e}
	}
	return nil
}

// Symlink creates newname as a symbolic link to oldname.
// If there is an error, it will be of type *LinkError.
func Symlink(oldname, newname string) error {
	e := syscall.Symlink(oldname, newname)
	if e != nil {
		return &LinkError{"symlink", oldname, newname, e}
	}
	return nil
}

// Readlink returns the destination of the named symbolic link.
// If there is an error, it will be of type *PathError.
func Readlink(name string) (string, error) {
	for len := 128; ; len *= 2 {
		b := make([]byte, len)
		n, e := syscall.Readlink(name, b)
		if e != nil {
			return "", &PathError{"readlink", name, e}
		}
		if n < len {
			return string(b[0:n]), nil
		}
	}
}

func rename(oldname, newname string) error {
	e := syscall.Rename(oldname, newname)
	if e != nil {
		return &LinkError{"rename", oldname, newname, e}
	}
	return nil
}

// syscallMode returns the syscall-specific mode bits from Go's portable mode bits.
func syscallMode(i FileMode) (o uint32) {
	o |= uint32(i.Perm())
	if i&ModeSetuid != 0 {
		o |= syscall.S_ISUID
	}
	if i&ModeSetgid != 0 {
		o |= syscall.S_ISGID
	}
	if i&ModeSticky != 0 {
		o |= syscall.S_ISVTX
	}
	// No mapping for Go's ModeTemporary (plan9 only).
	return
}

// Chmod changes the mode of the named file to mode.
// If the file is a symbolic link, it changes the mode of the link's target.
// If there is an error, it will be of type *PathError.
func Chmod(name string, mode FileMode) error {
	if e := syscall.Chmod(name, syscallMode(mode)); e != nil {
		return &PathError{"chmod", name, e}
	}
	return nil
}

// Chmod changes the mode of the file to mode.
// If there is an error, it will be of type *PathError.
func (f *File) Chmod(mode FileMode) error {
	if f == nil {
		return ErrInvalid
	}
	if e := syscall.Fchmod(f.fd, syscallMode(mode)); e != nil {
		return &PathError{"chmod", f.name, e}
	}
	return nil
}

// Chown changes the numeric uid and gid of the named file.
// If the file is a symbolic link, it changes the uid and gid of the link's target.
// If there is an error, it will be of type *PathError.
func Chown(name string, uid, gid int) error {
	if e := syscall.Chown(name, uid, gid); e != nil {
		return &PathError{"chown", name, e}
	}
	return nil
}

// Lchown changes the numeric uid and gid of the named file.
// If the file is a symbolic link, it changes the uid and gid of the link itself.
// If there is an error, it will be of type *PathError.
func Lchown(name string, uid, gid int) error {
	if e := syscall.Lchown(name, uid, gid); e != nil {
		return &PathError{"lchown", name, e}
	}
	return nil
}

// Chown changes the numeric uid and gid of the named file.
// If there is an error, it will be of type *PathError.
func (f *File) Chown(uid, gid int) error {
	if f == nil {
		return ErrInvalid
	}
	if e := syscall.Fchown(f.fd, uid, gid); e != nil {
		return &PathError{"chown", f.name, e}
	}
	return nil
}

// Truncate changes the size of the file.
// It does not change the I/O offset.
// If there is an error, it will be of type *PathError.
func (f *File) Truncate(size int64) error {
	if f == nil {
		return ErrInvalid
	}
	if e := syscall.Ftruncate(f.fd, size); e != nil {
		return &PathError{"truncate", f.name, e}
	}
	return nil
}

// Sync commits the current contents of the file to stable storage.
// Typically, this means flushing the file system's in-memory copy
// of recently written data to disk.
func (f *File) Sync() (err error) {
	if f == nil {
		return syscall.EINVAL
	}
	if e := syscall.Fsync(f.fd); e != nil {
		return NewSyscallError("fsync", e)
	}
	return nil
}

// Chtimes changes the access and modification times of the named
// file, similar to the Unix utime() or utimes() functions.
//
// The underlying filesystem may truncate or round the values to a
// less precise time unit.
// If there is an error, it will be of type *PathError.
func Chtimes(name string, atime time.Time, mtime time.Time) error {
	var utimes [2]syscall.Timespec
	utimes[0] = syscall.NsecToTimespec(atime.UnixNano())
	utimes[1] = syscall.NsecToTimespec(mtime.UnixNano())
	if e := syscall.UtimesNano(name, utimes[0:]); e != nil {
		return &PathError{"chtimes", name, e}
	}
	return nil
}
<commit_msg>os: return ErrInvalid if receiver is nil.<commit_after>// Copyright 2009 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.

// +build darwin dragonfly freebsd linux netbsd openbsd windows

package os

import (
	"syscall"
	"time"
)

func sigpipe() // implemented in package runtime

// Link creates newname as a hard link to the oldname file.
// If there is an error, it will be of type *LinkError.
func Link(oldname, newname string) error {
	e := syscall.Link(oldname, newname)
	if e != nil {
		return &LinkError{"link", oldname, newname, e}
	}
	return nil
}

// Symlink creates newname as a symbolic link to oldname.
// If there is an error, it will be of type *LinkError.
func Symlink(oldname, newname string) error {
	e := syscall.Symlink(oldname, newname)
	if e != nil {
		return &LinkError{"symlink", oldname, newname, e}
	}
	return nil
}

// Readlink returns the destination of the named symbolic link.
// If there is an error, it will be of type *PathError.
func Readlink(name string) (string, error) {
	for len := 128; ; len *= 2 {
		b := make([]byte, len)
		n, e := syscall.Readlink(name, b)
		if e != nil {
			return "", &PathError{"readlink", name, e}
		}
		if n < len {
			return string(b[0:n]), nil
		}
	}
}

func rename(oldname, newname string) error {
	e := syscall.Rename(oldname, newname)
	if e != nil {
		return &LinkError{"rename", oldname, newname, e}
	}
	return nil
}

// syscallMode returns the syscall-specific mode bits from Go's portable mode bits.
func syscallMode(i FileMode) (o uint32) {
	o |= uint32(i.Perm())
	if i&ModeSetuid != 0 {
		o |= syscall.S_ISUID
	}
	if i&ModeSetgid != 0 {
		o |= syscall.S_ISGID
	}
	if i&ModeSticky != 0 {
		o |= syscall.S_ISVTX
	}
	// No mapping for Go's ModeTemporary (plan9 only).
	return
}

// Chmod changes the mode of the named file to mode.
// If the file is a symbolic link, it changes the mode of the link's target.
// If there is an error, it will be of type *PathError.
func Chmod(name string, mode FileMode) error {
	if e := syscall.Chmod(name, syscallMode(mode)); e != nil {
		return &PathError{"chmod", name, e}
	}
	return nil
}

// Chmod changes the mode of the file to mode.
// If there is an error, it will be of type *PathError.
func (f *File) Chmod(mode FileMode) error {
	if f == nil {
		return ErrInvalid
	}
	if e := syscall.Fchmod(f.fd, syscallMode(mode)); e != nil {
		return &PathError{"chmod", f.name, e}
	}
	return nil
}

// Chown changes the numeric uid and gid of the named file.
// If the file is a symbolic link, it changes the uid and gid of the link's target.
// If there is an error, it will be of type *PathError.
func Chown(name string, uid, gid int) error {
	if e := syscall.Chown(name, uid, gid); e != nil {
		return &PathError{"chown", name, e}
	}
	return nil
}

// Lchown changes the numeric uid and gid of the named file.
// If the file is a symbolic link, it changes the uid and gid of the link itself.
// If there is an error, it will be of type *PathError.
func Lchown(name string, uid, gid int) error {
	if e := syscall.Lchown(name, uid, gid); e != nil {
		return &PathError{"lchown", name, e}
	}
	return nil
}

// Chown changes the numeric uid and gid of the named file.
// If there is an error, it will be of type *PathError.
func (f *File) Chown(uid, gid int) error {
	if f == nil {
		return ErrInvalid
	}
	if e := syscall.Fchown(f.fd, uid, gid); e != nil {
		return &PathError{"chown", f.name, e}
	}
	return nil
}

// Truncate changes the size of the file.
// It does not change the I/O offset.
// If there is an error, it will be of type *PathError.
func (f *File) Truncate(size int64) error {
	if f == nil {
		return ErrInvalid
	}
	if e := syscall.Ftruncate(f.fd, size); e != nil {
		return &PathError{"truncate", f.name, e}
	}
	return nil
}

// Sync commits the current contents of the file to stable storage.
// Typically, this means flushing the file system's in-memory copy
// of recently written data to disk.
func (f *File) Sync() (err error) {
	if f == nil {
		return ErrInvalid
	}
	if e := syscall.Fsync(f.fd); e != nil {
		return NewSyscallError("fsync", e)
	}
	return nil
}

// Chtimes changes the access and modification times of the named
// file, similar to the Unix utime() or utimes() functions.
//
// The underlying filesystem may truncate or round the values to a
// less precise time unit.
// If there is an error, it will be of type *PathError.
func Chtimes(name string, atime time.Time, mtime time.Time) error {
	var utimes [2]syscall.Timespec
	utimes[0] = syscall.NsecToTimespec(atime.UnixNano())
	utimes[1] = syscall.NsecToTimespec(mtime.UnixNano())
	if e := syscall.UtimesNano(name, utimes[0:]); e != nil {
		return &PathError{"chtimes", name, e}
	}
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2009 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 unsafe contains operations that step around the type safety of Go programs.
*/
package unsafe

// ArbitraryType is here for the purposes of documentation only and is not actually
// part of the unsafe package.  It represents the type of an arbitrary Go expression.
type ArbitraryType int

// Pointer represents a pointer to an arbitrary type.  There are three special operations
// available for type Pointer that are not available for other types.
//	1) A pointer value of any type can be converted to a Pointer.
//	2) A Pointer can be converted to a pointer value of any type.
//	3) A uintptr can be converted to a Pointer.
//	4) A Pointer can be converted to a uintptr.
// Pointer therefore allows a program to defeat the type system and read and write
// arbitrary memory. It should be used with extreme care.
type Pointer *ArbitraryType

// Sizeof returns the size in bytes occupied by the value v.  The size is that of the
// "top level" of the value only.  For instance, if v is a slice, it returns the size of
// the slice descriptor, not the size of the memory referenced by the slice.
func Sizeof(v ArbitraryType) uintptr

// Offsetof returns the offset within the struct of the field represented by v,
// which must be of the form struct_value.field.  In other words, it returns the
// number of bytes between the start of the struct and the start of the field.
func Offsetof(v ArbitraryType) uintptr

// Alignof returns the alignment of the value v.  It is the maximum value m such
// that the address of a variable with the type of v will always always be zero mod m.
// If v is of the form obj.f, it returns the alignment of field f within struct object obj.
func Alignof(v ArbitraryType) uintptr

// Typeof returns the type of an interface value, a runtime.Type.
func Typeof(i interface{}) (typ interface{})

// Reflect unpacks an interface value into its type and the address of a copy of the
// internal value.
func Reflect(i interface{}) (typ interface{}, addr Pointer)

// Unreflect inverts Reflect: Given a type and a pointer to a value, it returns an
// empty interface value with contents the type and the value (not the pointer to
// the value).  The typ is assumed to contain a pointer to a runtime type; the type
// information in the interface{} is ignored, so that, for example, both
// *reflect.structType and *runtime.StructType can be passed for typ.
func Unreflect(typ interface{}, addr Pointer) (ret interface{})

// New allocates and returns a pointer to memory for a new value of the given type.
// The typ is assumed to hold a pointer to a runtime type.
// Callers should use reflect.MakeZero instead of invoking unsafe.New directly.
func New(typ interface{}) Pointer

// NewArray allocates and returns a pointer to an array of n elements of the given type.
// The typ is assumed to hold a pointer to a runtime type.
// Callers should use reflect.MakeSlice instead of invoking unsafe.NewArray directly.
func NewArray(typ interface{}, n int) Pointer
<commit_msg>unsafe: refer to correct reflect functions<commit_after>// Copyright 2009 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 unsafe contains operations that step around the type safety of Go programs.
*/
package unsafe

// ArbitraryType is here for the purposes of documentation only and is not actually
// part of the unsafe package.  It represents the type of an arbitrary Go expression.
type ArbitraryType int

// Pointer represents a pointer to an arbitrary type.  There are three special operations
// available for type Pointer that are not available for other types.
//	1) A pointer value of any type can be converted to a Pointer.
//	2) A Pointer can be converted to a pointer value of any type.
//	3) A uintptr can be converted to a Pointer.
//	4) A Pointer can be converted to a uintptr.
// Pointer therefore allows a program to defeat the type system and read and write
// arbitrary memory. It should be used with extreme care.
type Pointer *ArbitraryType

// Sizeof returns the size in bytes occupied by the value v.  The size is that of the
// "top level" of the value only.  For instance, if v is a slice, it returns the size of
// the slice descriptor, not the size of the memory referenced by the slice.
func Sizeof(v ArbitraryType) uintptr

// Offsetof returns the offset within the struct of the field represented by v,
// which must be of the form struct_value.field.  In other words, it returns the
// number of bytes between the start of the struct and the start of the field.
func Offsetof(v ArbitraryType) uintptr

// Alignof returns the alignment of the value v.  It is the maximum value m such
// that the address of a variable with the type of v will always always be zero mod m.
// If v is of the form obj.f, it returns the alignment of field f within struct object obj.
func Alignof(v ArbitraryType) uintptr

// Typeof returns the type of an interface value, a runtime.Type.
func Typeof(i interface{}) (typ interface{})

// Reflect unpacks an interface value into its type and the address of a copy of the
// internal value.
func Reflect(i interface{}) (typ interface{}, addr Pointer)

// Unreflect inverts Reflect: Given a type and a pointer to a value, it returns an
// empty interface value with contents the type and the value (not the pointer to
// the value).  The typ is assumed to contain a pointer to a runtime type; the type
// information in the interface{} is ignored, so that, for example, both
// *reflect.structType and *runtime.StructType can be passed for typ.
func Unreflect(typ interface{}, addr Pointer) (ret interface{})

// New allocates and returns a pointer to memory for a new value of the given type.
// The typ is assumed to hold a pointer to a runtime type.
// Callers should use reflect.New or reflect.Zero instead of invoking unsafe.New directly.
func New(typ interface{}) Pointer

// NewArray allocates and returns a pointer to an array of n elements of the given type.
// The typ is assumed to hold a pointer to a runtime type.
// Callers should use reflect.MakeSlice instead of invoking unsafe.NewArray directly.
func NewArray(typ interface{}, n int) Pointer
<|endoftext|>


<commit_before>package restic

import "restic/crypto"

// Repository stores data in a backend. It provides high-level functions and
// transparently encrypts/decrypts data.
type Repository interface {

	// Backend returns the backend used by the repository
	Backend() Backend

	Key() *crypto.Key

	SetIndex(Index)

	Index() Index
	SaveFullIndex() error

	SaveJSON(BlobType, interface{}) (ID, error)
	SaveUnpacked(FileType, []byte) (ID, error)

	Config() Config

	SaveAndEncrypt(BlobType, []byte, *ID) (ID, error)
	SaveJSONUnpacked(FileType, interface{}) (ID, error)
	SaveIndex() error

	LoadJSONPack(BlobType, ID, interface{}) error
	LoadJSONUnpacked(FileType, ID, interface{}) error
	LoadBlob(ID, BlobType, []byte) ([]byte, error)
	LoadAndDecrypt(FileType, ID) ([]byte, error)

	LookupBlobSize(ID, BlobType) (uint, error)

	List(FileType, <-chan struct{}) <-chan ID
	ListPack(ID) ([]Blob, int64, error)

	Flush() error
}

// Deleter removes all data stored in a backend/repo.
type Deleter interface {
	Delete() error
}

// Lister allows listing files in a backend.
type Lister interface {
	List(FileType, <-chan struct{}) <-chan string
}

// Index keeps track of the blobs are stored within files.
type Index interface {
	Has(ID, BlobType) bool
	Lookup(ID, BlobType) ([]PackedBlob, error)
	Count(BlobType) uint
}
<commit_msg>Reorder methods in interface Repository<commit_after>package restic

import "restic/crypto"

// Repository stores data in a backend. It provides high-level functions and
// transparently encrypts/decrypts data.
type Repository interface {

	// Backend returns the backend used by the repository
	Backend() Backend

	Key() *crypto.Key

	SetIndex(Index)

	Index() Index
	SaveFullIndex() error
	SaveIndex() error

	Config() Config

	LookupBlobSize(ID, BlobType) (uint, error)

	List(FileType, <-chan struct{}) <-chan ID
	ListPack(ID) ([]Blob, int64, error)

	Flush() error

	SaveJSON(BlobType, interface{}) (ID, error)
	SaveUnpacked(FileType, []byte) (ID, error)
	SaveAndEncrypt(BlobType, []byte, *ID) (ID, error)
	SaveJSONUnpacked(FileType, interface{}) (ID, error)

	LoadJSONPack(BlobType, ID, interface{}) error
	LoadJSONUnpacked(FileType, ID, interface{}) error
	LoadBlob(ID, BlobType, []byte) ([]byte, error)
	LoadAndDecrypt(FileType, ID) ([]byte, error)
}

// Deleter removes all data stored in a backend/repo.
type Deleter interface {
	Delete() error
}

// Lister allows listing files in a backend.
type Lister interface {
	List(FileType, <-chan struct{}) <-chan string
}

// Index keeps track of the blobs are stored within files.
type Index interface {
	Has(ID, BlobType) bool
	Lookup(ID, BlobType) ([]PackedBlob, error)
	Count(BlobType) uint
}
<|endoftext|>


<commit_before>// Copyright 2013 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 runtime_test

import (
	"fmt"
	"math"
	"reflect"
	"runtime"
	"sort"
	"strings"
	"sync"
	"testing"
)

// negative zero is a good test because:
//  1) 0 and -0 are equal, yet have distinct representations.
//  2) 0 is represented as all zeros, -0 isn't.
// I'm not sure the language spec actually requires this behavior,
// but it's what the current map implementation does.
func TestNegativeZero(t *testing.T) {
	m := make(map[float64]bool, 0)

	m[+0.0] = true
	m[math.Copysign(0.0, -1.0)] = true // should overwrite +0 entry

	if len(m) != 1 {
		t.Error("length wrong")
	}

	for k := range m {
		if math.Copysign(1.0, k) > 0 {
			t.Error("wrong sign")
		}
	}

	m = make(map[float64]bool, 0)
	m[math.Copysign(0.0, -1.0)] = true
	m[+0.0] = true // should overwrite -0.0 entry

	if len(m) != 1 {
		t.Error("length wrong")
	}

	for k := range m {
		if math.Copysign(1.0, k) < 0 {
			t.Error("wrong sign")
		}
	}
}

// nan is a good test because nan != nan, and nan has
// a randomized hash value.
func TestNan(t *testing.T) {
	m := make(map[float64]int, 0)
	nan := math.NaN()
	m[nan] = 1
	m[nan] = 2
	m[nan] = 4
	if len(m) != 3 {
		t.Error("length wrong")
	}
	s := 0
	for k, v := range m {
		if k == k {
			t.Error("nan disappeared")
		}
		if (v & (v - 1)) != 0 {
			t.Error("value wrong")
		}
		s |= v
	}
	if s != 7 {
		t.Error("values wrong")
	}
}

// Maps aren't actually copied on assignment.
func TestAlias(t *testing.T) {
	m := make(map[int]int, 0)
	m[0] = 5
	n := m
	n[0] = 6
	if m[0] != 6 {
		t.Error("alias didn't work")
	}
}

func TestGrowWithNaN(t *testing.T) {
	m := make(map[float64]int, 4)
	nan := math.NaN()
	m[nan] = 1
	m[nan] = 2
	m[nan] = 4
	cnt := 0
	s := 0
	growflag := true
	for k, v := range m {
		if growflag {
			// force a hashtable resize
			for i := 0; i < 100; i++ {
				m[float64(i)] = i
			}
			growflag = false
		}
		if k != k {
			cnt++
			s |= v
		}
	}
	if cnt != 3 {
		t.Error("NaN keys lost during grow")
	}
	if s != 7 {
		t.Error("NaN values lost during grow")
	}
}

type FloatInt struct {
	x float64
	y int
}

func TestGrowWithNegativeZero(t *testing.T) {
	negzero := math.Copysign(0.0, -1.0)
	m := make(map[FloatInt]int, 4)
	m[FloatInt{0.0, 0}] = 1
	m[FloatInt{0.0, 1}] = 2
	m[FloatInt{0.0, 2}] = 4
	m[FloatInt{0.0, 3}] = 8
	growflag := true
	s := 0
	cnt := 0
	negcnt := 0
	// The first iteration should return the +0 key.
	// The subsequent iterations should return the -0 key.
	// I'm not really sure this is required by the spec,
	// but it makes sense.
	// TODO: are we allowed to get the first entry returned again???
	for k, v := range m {
		if v == 0 {
			continue
		} // ignore entries added to grow table
		cnt++
		if math.Copysign(1.0, k.x) < 0 {
			if v&16 == 0 {
				t.Error("key/value not updated together 1")
			}
			negcnt++
			s |= v & 15
		} else {
			if v&16 == 16 {
				t.Error("key/value not updated together 2", k, v)
			}
			s |= v
		}
		if growflag {
			// force a hashtable resize
			for i := 0; i < 100; i++ {
				m[FloatInt{3.0, i}] = 0
			}
			// then change all the entries
			// to negative zero
			m[FloatInt{negzero, 0}] = 1 | 16
			m[FloatInt{negzero, 1}] = 2 | 16
			m[FloatInt{negzero, 2}] = 4 | 16
			m[FloatInt{negzero, 3}] = 8 | 16
			growflag = false
		}
	}
	if s != 15 {
		t.Error("entry missing", s)
	}
	if cnt != 4 {
		t.Error("wrong number of entries returned by iterator", cnt)
	}
	if negcnt != 3 {
		t.Error("update to negzero missed by iteration", negcnt)
	}
}

func TestIterGrowAndDelete(t *testing.T) {
	m := make(map[int]int, 4)
	for i := 0; i < 100; i++ {
		m[i] = i
	}
	growflag := true
	for k := range m {
		if growflag {
			// grow the table
			for i := 100; i < 1000; i++ {
				m[i] = i
			}
			// delete all odd keys
			for i := 1; i < 1000; i += 2 {
				delete(m, i)
			}
			growflag = false
		} else {
			if k&1 == 1 {
				t.Error("odd value returned")
			}
		}
	}
}

// make sure old bucket arrays don't get GCd while
// an iterator is still using them.
func TestIterGrowWithGC(t *testing.T) {
	m := make(map[int]int, 4)
	for i := 0; i < 16; i++ {
		m[i] = i
	}
	growflag := true
	bitmask := 0
	for k := range m {
		if k < 16 {
			bitmask |= 1 << uint(k)
		}
		if growflag {
			// grow the table
			for i := 100; i < 1000; i++ {
				m[i] = i
			}
			// trigger a gc
			runtime.GC()
			growflag = false
		}
	}
	if bitmask != 1<<16-1 {
		t.Error("missing key", bitmask)
	}
}

func testConcurrentReadsAfterGrowth(t *testing.T, useReflect bool) {
	if runtime.GOMAXPROCS(-1) == 1 {
		defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(16))
	}
	numLoop := 10
	numGrowStep := 250
	numReader := 16
	if testing.Short() {
		numLoop, numGrowStep = 2, 500
	}
	for i := 0; i < numLoop; i++ {
		m := make(map[int]int, 0)
		for gs := 0; gs < numGrowStep; gs++ {
			m[gs] = gs
			var wg sync.WaitGroup
			wg.Add(numReader * 2)
			for nr := 0; nr < numReader; nr++ {
				go func() {
					defer wg.Done()
					for _ = range m {
					}
				}()
				go func() {
					defer wg.Done()
					for key := 0; key < gs; key++ {
						_ = m[key]
					}
				}()
				if useReflect {
					wg.Add(1)
					go func() {
						defer wg.Done()
						mv := reflect.ValueOf(m)
						keys := mv.MapKeys()
						for _, k := range keys {
							mv.MapIndex(k)
						}
					}()
				}
			}
			wg.Wait()
		}
	}
}

func TestConcurrentReadsAfterGrowth(t *testing.T) {
	testConcurrentReadsAfterGrowth(t, false)
}

func TestConcurrentReadsAfterGrowthReflect(t *testing.T) {
	testConcurrentReadsAfterGrowth(t, true)
}

func TestBigItems(t *testing.T) {
	var key [256]string
	for i := 0; i < 256; i++ {
		key[i] = "foo"
	}
	m := make(map[[256]string][256]string, 4)
	for i := 0; i < 100; i++ {
		key[37] = fmt.Sprintf("string%02d", i)
		m[key] = key
	}
	var keys [100]string
	var values [100]string
	i := 0
	for k, v := range m {
		keys[i] = k[37]
		values[i] = v[37]
		i++
	}
	sort.Strings(keys[:])
	sort.Strings(values[:])
	for i := 0; i < 100; i++ {
		if keys[i] != fmt.Sprintf("string%02d", i) {
			t.Errorf("#%d: missing key: %v", i, keys[i])
		}
		if values[i] != fmt.Sprintf("string%02d", i) {
			t.Errorf("#%d: missing value: %v", i, values[i])
		}
	}
}

type empty struct {
}

func TestEmptyKeyAndValue(t *testing.T) {
	a := make(map[int]empty, 4)
	b := make(map[empty]int, 4)
	c := make(map[empty]empty, 4)
	a[0] = empty{}
	b[empty{}] = 0
	b[empty{}] = 1
	c[empty{}] = empty{}

	if len(a) != 1 {
		t.Errorf("empty value insert problem")
	}
	if b[empty{}] != 1 {
		t.Errorf("empty key returned wrong value")
	}
}

// Tests a map with a single bucket, with same-lengthed short keys
// ("quick keys") as well as long keys.
func TestSingleBucketMapStringKeys_DupLen(t *testing.T) {
	testMapLookups(t, map[string]string{
		"x":    "x1val",
		"xx":   "x2val",
		"foo":  "fooval",
		"bar":  "barval", // same key length as "foo"
		"xxxx": "x4val",
		strings.Repeat("x", 128): "longval1",
		strings.Repeat("y", 128): "longval2",
	})
}

// Tests a map with a single bucket, with all keys having different lengths.
func TestSingleBucketMapStringKeys_NoDupLen(t *testing.T) {
	testMapLookups(t, map[string]string{
		"x":                      "x1val",
		"xx":                     "x2val",
		"foo":                    "fooval",
		"xxxx":                   "x4val",
		"xxxxx":                  "x5val",
		"xxxxxx":                 "x6val",
		strings.Repeat("x", 128): "longval",
	})
}

func testMapLookups(t *testing.T, m map[string]string) {
	for k, v := range m {
		if m[k] != v {
			t.Fatalf("m[%q] = %q; want %q", k, m[k], v)
		}
	}
}

// Tests whether the iterator returns the right elements when
// started in the middle of a grow, when the keys are NaNs.
func TestMapNanGrowIterator(t *testing.T) {
	m := make(map[float64]int)
	nan := math.NaN()
	const nBuckets = 16
	// To fill nBuckets buckets takes LOAD * nBuckets keys.
	nKeys := int(nBuckets * *runtime.HashLoad)

	// Get map to full point with nan keys.
	for i := 0; i < nKeys; i++ {
		m[nan] = i
	}
	// Trigger grow
	m[1.0] = 1
	delete(m, 1.0)

	// Run iterator
	found := make(map[int]struct{})
	for _, v := range m {
		if v != -1 {
			if _, repeat := found[v]; repeat {
				t.Fatalf("repeat of value %d", v)
			}
			found[v] = struct{}{}
		}
		if len(found) == nKeys/2 {
			// Halfway through iteration, finish grow.
			for i := 0; i < nBuckets; i++ {
				delete(m, 1.0)
			}
		}
	}
	if len(found) != nKeys {
		t.Fatalf("missing value")
	}
}

func TestMapIterOrder(t *testing.T) {
	// TODO: For issue 6719, add 3 and 7 to this list.
	for _, n := range [...]int{9, 15} {
		// Make m be {0: true, 1: true, ..., n-1: true}.
		m := make(map[int]bool)
		for i := 0; i < n; i++ {
			m[i] = true
		}
		// Check that iterating over the map produces at least two different orderings.
		ord := func() []int {
			var s []int
			for key := range m {
				s = append(s, key)
			}
			return s
		}
		first := ord()
		ok := false
		for try := 0; try < 5; try++ {
			if !reflect.DeepEqual(first, ord()) {
				ok = true
				break
			}
		}
		if !ok {
			t.Errorf("Map with n=%d elements had consistent iteration order: %v", n, first)
		}
	}
}
<commit_msg>runtime: increase attempt count for map iteration order test.<commit_after>// Copyright 2013 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 runtime_test

import (
	"fmt"
	"math"
	"reflect"
	"runtime"
	"sort"
	"strings"
	"sync"
	"testing"
)

// negative zero is a good test because:
//  1) 0 and -0 are equal, yet have distinct representations.
//  2) 0 is represented as all zeros, -0 isn't.
// I'm not sure the language spec actually requires this behavior,
// but it's what the current map implementation does.
func TestNegativeZero(t *testing.T) {
	m := make(map[float64]bool, 0)

	m[+0.0] = true
	m[math.Copysign(0.0, -1.0)] = true // should overwrite +0 entry

	if len(m) != 1 {
		t.Error("length wrong")
	}

	for k := range m {
		if math.Copysign(1.0, k) > 0 {
			t.Error("wrong sign")
		}
	}

	m = make(map[float64]bool, 0)
	m[math.Copysign(0.0, -1.0)] = true
	m[+0.0] = true // should overwrite -0.0 entry

	if len(m) != 1 {
		t.Error("length wrong")
	}

	for k := range m {
		if math.Copysign(1.0, k) < 0 {
			t.Error("wrong sign")
		}
	}
}

// nan is a good test because nan != nan, and nan has
// a randomized hash value.
func TestNan(t *testing.T) {
	m := make(map[float64]int, 0)
	nan := math.NaN()
	m[nan] = 1
	m[nan] = 2
	m[nan] = 4
	if len(m) != 3 {
		t.Error("length wrong")
	}
	s := 0
	for k, v := range m {
		if k == k {
			t.Error("nan disappeared")
		}
		if (v & (v - 1)) != 0 {
			t.Error("value wrong")
		}
		s |= v
	}
	if s != 7 {
		t.Error("values wrong")
	}
}

// Maps aren't actually copied on assignment.
func TestAlias(t *testing.T) {
	m := make(map[int]int, 0)
	m[0] = 5
	n := m
	n[0] = 6
	if m[0] != 6 {
		t.Error("alias didn't work")
	}
}

func TestGrowWithNaN(t *testing.T) {
	m := make(map[float64]int, 4)
	nan := math.NaN()
	m[nan] = 1
	m[nan] = 2
	m[nan] = 4
	cnt := 0
	s := 0
	growflag := true
	for k, v := range m {
		if growflag {
			// force a hashtable resize
			for i := 0; i < 100; i++ {
				m[float64(i)] = i
			}
			growflag = false
		}
		if k != k {
			cnt++
			s |= v
		}
	}
	if cnt != 3 {
		t.Error("NaN keys lost during grow")
	}
	if s != 7 {
		t.Error("NaN values lost during grow")
	}
}

type FloatInt struct {
	x float64
	y int
}

func TestGrowWithNegativeZero(t *testing.T) {
	negzero := math.Copysign(0.0, -1.0)
	m := make(map[FloatInt]int, 4)
	m[FloatInt{0.0, 0}] = 1
	m[FloatInt{0.0, 1}] = 2
	m[FloatInt{0.0, 2}] = 4
	m[FloatInt{0.0, 3}] = 8
	growflag := true
	s := 0
	cnt := 0
	negcnt := 0
	// The first iteration should return the +0 key.
	// The subsequent iterations should return the -0 key.
	// I'm not really sure this is required by the spec,
	// but it makes sense.
	// TODO: are we allowed to get the first entry returned again???
	for k, v := range m {
		if v == 0 {
			continue
		} // ignore entries added to grow table
		cnt++
		if math.Copysign(1.0, k.x) < 0 {
			if v&16 == 0 {
				t.Error("key/value not updated together 1")
			}
			negcnt++
			s |= v & 15
		} else {
			if v&16 == 16 {
				t.Error("key/value not updated together 2", k, v)
			}
			s |= v
		}
		if growflag {
			// force a hashtable resize
			for i := 0; i < 100; i++ {
				m[FloatInt{3.0, i}] = 0
			}
			// then change all the entries
			// to negative zero
			m[FloatInt{negzero, 0}] = 1 | 16
			m[FloatInt{negzero, 1}] = 2 | 16
			m[FloatInt{negzero, 2}] = 4 | 16
			m[FloatInt{negzero, 3}] = 8 | 16
			growflag = false
		}
	}
	if s != 15 {
		t.Error("entry missing", s)
	}
	if cnt != 4 {
		t.Error("wrong number of entries returned by iterator", cnt)
	}
	if negcnt != 3 {
		t.Error("update to negzero missed by iteration", negcnt)
	}
}

func TestIterGrowAndDelete(t *testing.T) {
	m := make(map[int]int, 4)
	for i := 0; i < 100; i++ {
		m[i] = i
	}
	growflag := true
	for k := range m {
		if growflag {
			// grow the table
			for i := 100; i < 1000; i++ {
				m[i] = i
			}
			// delete all odd keys
			for i := 1; i < 1000; i += 2 {
				delete(m, i)
			}
			growflag = false
		} else {
			if k&1 == 1 {
				t.Error("odd value returned")
			}
		}
	}
}

// make sure old bucket arrays don't get GCd while
// an iterator is still using them.
func TestIterGrowWithGC(t *testing.T) {
	m := make(map[int]int, 4)
	for i := 0; i < 16; i++ {
		m[i] = i
	}
	growflag := true
	bitmask := 0
	for k := range m {
		if k < 16 {
			bitmask |= 1 << uint(k)
		}
		if growflag {
			// grow the table
			for i := 100; i < 1000; i++ {
				m[i] = i
			}
			// trigger a gc
			runtime.GC()
			growflag = false
		}
	}
	if bitmask != 1<<16-1 {
		t.Error("missing key", bitmask)
	}
}

func testConcurrentReadsAfterGrowth(t *testing.T, useReflect bool) {
	if runtime.GOMAXPROCS(-1) == 1 {
		defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(16))
	}
	numLoop := 10
	numGrowStep := 250
	numReader := 16
	if testing.Short() {
		numLoop, numGrowStep = 2, 500
	}
	for i := 0; i < numLoop; i++ {
		m := make(map[int]int, 0)
		for gs := 0; gs < numGrowStep; gs++ {
			m[gs] = gs
			var wg sync.WaitGroup
			wg.Add(numReader * 2)
			for nr := 0; nr < numReader; nr++ {
				go func() {
					defer wg.Done()
					for _ = range m {
					}
				}()
				go func() {
					defer wg.Done()
					for key := 0; key < gs; key++ {
						_ = m[key]
					}
				}()
				if useReflect {
					wg.Add(1)
					go func() {
						defer wg.Done()
						mv := reflect.ValueOf(m)
						keys := mv.MapKeys()
						for _, k := range keys {
							mv.MapIndex(k)
						}
					}()
				}
			}
			wg.Wait()
		}
	}
}

func TestConcurrentReadsAfterGrowth(t *testing.T) {
	testConcurrentReadsAfterGrowth(t, false)
}

func TestConcurrentReadsAfterGrowthReflect(t *testing.T) {
	testConcurrentReadsAfterGrowth(t, true)
}

func TestBigItems(t *testing.T) {
	var key [256]string
	for i := 0; i < 256; i++ {
		key[i] = "foo"
	}
	m := make(map[[256]string][256]string, 4)
	for i := 0; i < 100; i++ {
		key[37] = fmt.Sprintf("string%02d", i)
		m[key] = key
	}
	var keys [100]string
	var values [100]string
	i := 0
	for k, v := range m {
		keys[i] = k[37]
		values[i] = v[37]
		i++
	}
	sort.Strings(keys[:])
	sort.Strings(values[:])
	for i := 0; i < 100; i++ {
		if keys[i] != fmt.Sprintf("string%02d", i) {
			t.Errorf("#%d: missing key: %v", i, keys[i])
		}
		if values[i] != fmt.Sprintf("string%02d", i) {
			t.Errorf("#%d: missing value: %v", i, values[i])
		}
	}
}

type empty struct {
}

func TestEmptyKeyAndValue(t *testing.T) {
	a := make(map[int]empty, 4)
	b := make(map[empty]int, 4)
	c := make(map[empty]empty, 4)
	a[0] = empty{}
	b[empty{}] = 0
	b[empty{}] = 1
	c[empty{}] = empty{}

	if len(a) != 1 {
		t.Errorf("empty value insert problem")
	}
	if b[empty{}] != 1 {
		t.Errorf("empty key returned wrong value")
	}
}

// Tests a map with a single bucket, with same-lengthed short keys
// ("quick keys") as well as long keys.
func TestSingleBucketMapStringKeys_DupLen(t *testing.T) {
	testMapLookups(t, map[string]string{
		"x":    "x1val",
		"xx":   "x2val",
		"foo":  "fooval",
		"bar":  "barval", // same key length as "foo"
		"xxxx": "x4val",
		strings.Repeat("x", 128): "longval1",
		strings.Repeat("y", 128): "longval2",
	})
}

// Tests a map with a single bucket, with all keys having different lengths.
func TestSingleBucketMapStringKeys_NoDupLen(t *testing.T) {
	testMapLookups(t, map[string]string{
		"x":                      "x1val",
		"xx":                     "x2val",
		"foo":                    "fooval",
		"xxxx":                   "x4val",
		"xxxxx":                  "x5val",
		"xxxxxx":                 "x6val",
		strings.Repeat("x", 128): "longval",
	})
}

func testMapLookups(t *testing.T, m map[string]string) {
	for k, v := range m {
		if m[k] != v {
			t.Fatalf("m[%q] = %q; want %q", k, m[k], v)
		}
	}
}

// Tests whether the iterator returns the right elements when
// started in the middle of a grow, when the keys are NaNs.
func TestMapNanGrowIterator(t *testing.T) {
	m := make(map[float64]int)
	nan := math.NaN()
	const nBuckets = 16
	// To fill nBuckets buckets takes LOAD * nBuckets keys.
	nKeys := int(nBuckets * *runtime.HashLoad)

	// Get map to full point with nan keys.
	for i := 0; i < nKeys; i++ {
		m[nan] = i
	}
	// Trigger grow
	m[1.0] = 1
	delete(m, 1.0)

	// Run iterator
	found := make(map[int]struct{})
	for _, v := range m {
		if v != -1 {
			if _, repeat := found[v]; repeat {
				t.Fatalf("repeat of value %d", v)
			}
			found[v] = struct{}{}
		}
		if len(found) == nKeys/2 {
			// Halfway through iteration, finish grow.
			for i := 0; i < nBuckets; i++ {
				delete(m, 1.0)
			}
		}
	}
	if len(found) != nKeys {
		t.Fatalf("missing value")
	}
}

func TestMapIterOrder(t *testing.T) {
	// TODO: For issue 6719, add 3 and 7 to this list.
	for _, n := range [...]int{9, 15} {
		// Make m be {0: true, 1: true, ..., n-1: true}.
		m := make(map[int]bool)
		for i := 0; i < n; i++ {
			m[i] = true
		}
		// Check that iterating over the map produces at least two different orderings.
		ord := func() []int {
			var s []int
			for key := range m {
				s = append(s, key)
			}
			return s
		}
		first := ord()
		ok := false
		for try := 0; try < 100; try++ {
			if !reflect.DeepEqual(first, ord()) {
				ok = true
				break
			}
		}
		if !ok {
			t.Errorf("Map with n=%d elements had consistent iteration order: %v", n, first)
		}
	}
}
<|endoftext|>