<commit_before>// +build linux

package mount

import (
	"os"
	"path"
	"syscall"
	"testing"
)

// nothing is propogated in or out
func TestSubtreePrivate(t *testing.T) {
	tmp := path.Join(os.TempDir(), "mount-tests")
	if err := os.MkdirAll(tmp, 0777); err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(tmp)

	var (
		sourceDir   = path.Join(tmp, "source")
		targetDir   = path.Join(tmp, "target")
		outside1Dir = path.Join(tmp, "outside1")
		outside2Dir = path.Join(tmp, "outside2")

		outside1Path      = path.Join(outside1Dir, "file.txt")
		outside2Path      = path.Join(outside2Dir, "file.txt")
		outside1CheckPath = path.Join(targetDir, "a", "file.txt")
		outside2CheckPath = path.Join(sourceDir, "b", "file.txt")
	)
	if err := os.MkdirAll(path.Join(sourceDir, "a"), 0777); err != nil {
		t.Fatal(err)
	}
	if err := os.MkdirAll(path.Join(sourceDir, "b"), 0777); err != nil {
		t.Fatal(err)
	}
	if err := os.Mkdir(targetDir, 0777); err != nil {
		t.Fatal(err)
	}
	if err := os.Mkdir(outside1Dir, 0777); err != nil {
		t.Fatal(err)
	}
	if err := os.Mkdir(outside2Dir, 0777); err != nil {
		t.Fatal(err)
	}

	if err := createFile(outside1Path); err != nil {
		t.Fatal(err)
	}
	if err := createFile(outside2Path); err != nil {
		t.Fatal(err)
	}

	// mount the shared directory to a target
	if err := Mount(sourceDir, targetDir, "none", "bind,rw"); err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := Unmount(targetDir); err != nil {
			t.Fatal(err)
		}
	}()

	// next, make the target private
	if err := MakePrivate(targetDir); err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := Unmount(targetDir); err != nil {
			t.Fatal(err)
		}
	}()

	// mount in an outside path to a mounted path inside the _source_
	if err := Mount(outside1Dir, path.Join(sourceDir, "a"), "none", "bind,rw"); err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := Unmount(path.Join(sourceDir, "a")); err != nil {
			t.Fatal(err)
		}
	}()

	// check that this file _does_not_ show in the _target_
	if _, err := os.Stat(outside1CheckPath); err != nil && !os.IsNotExist(err) {
		t.Fatal(err)
	} else if err == nil {
		t.Fatalf("%q should not be visible, but is", outside1CheckPath)
	}

	// next mount outside2Dir into the _target_
	if err := Mount(outside2Dir, path.Join(targetDir, "b"), "none", "bind,rw"); err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := Unmount(path.Join(targetDir, "b")); err != nil {
			t.Fatal(err)
		}
	}()

	// check that this file _does_not_ show in the _source_
	if _, err := os.Stat(outside2CheckPath); err != nil && !os.IsNotExist(err) {
		t.Fatal(err)
	} else if err == nil {
		t.Fatalf("%q should not be visible, but is", outside2CheckPath)
	}
}

// Testing that when a target is a shared mount,
// then child mounts propogate to the source
func TestSubtreeShared(t *testing.T) {
	tmp := path.Join(os.TempDir(), "mount-tests")
	if err := os.MkdirAll(tmp, 0777); err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(tmp)

	var (
		sourceDir  = path.Join(tmp, "source")
		targetDir  = path.Join(tmp, "target")
		outsideDir = path.Join(tmp, "outside")

		outsidePath     = path.Join(outsideDir, "file.txt")
		sourceCheckPath = path.Join(sourceDir, "a", "file.txt")
	)

	if err := os.MkdirAll(path.Join(sourceDir, "a"), 0777); err != nil {
		t.Fatal(err)
	}
	if err := os.Mkdir(targetDir, 0777); err != nil {
		t.Fatal(err)
	}
	if err := os.Mkdir(outsideDir, 0777); err != nil {
		t.Fatal(err)
	}

	if err := createFile(outsidePath); err != nil {
		t.Fatal(err)
	}

	// mount the source as shared
	if err := MakeShared(sourceDir); err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := Unmount(sourceDir); err != nil {
			t.Fatal(err)
		}
	}()

	// mount the shared directory to a target
	if err := Mount(sourceDir, targetDir, "none", "bind,rw"); err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := Unmount(targetDir); err != nil {
			t.Fatal(err)
		}
	}()

	// mount in an outside path to a mounted path inside the target
	if err := Mount(outsideDir, path.Join(targetDir, "a"), "none", "bind,rw"); err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := Unmount(path.Join(targetDir, "a")); err != nil {
			t.Fatal(err)
		}
	}()

	// NOW, check that the file from the outside directory is avaible in the source directory
	if _, err := os.Stat(sourceCheckPath); err != nil {
		t.Fatal(err)
	}
}

// testing that mounts to a shared source show up in the slave target,
// and that mounts into a slave target do _not_ show up in the shared source
func TestSubtreeSharedSlave(t *testing.T) {
	tmp := path.Join(os.TempDir(), "mount-tests")
	if err := os.MkdirAll(tmp, 0777); err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(tmp)

	var (
		sourceDir   = path.Join(tmp, "source")
		targetDir   = path.Join(tmp, "target")
		outside1Dir = path.Join(tmp, "outside1")
		outside2Dir = path.Join(tmp, "outside2")

		outside1Path      = path.Join(outside1Dir, "file.txt")
		outside2Path      = path.Join(outside2Dir, "file.txt")
		outside1CheckPath = path.Join(targetDir, "a", "file.txt")
		outside2CheckPath = path.Join(sourceDir, "b", "file.txt")
	)
	if err := os.MkdirAll(path.Join(sourceDir, "a"), 0777); err != nil {
		t.Fatal(err)
	}
	if err := os.MkdirAll(path.Join(sourceDir, "b"), 0777); err != nil {
		t.Fatal(err)
	}
	if err := os.Mkdir(targetDir, 0777); err != nil {
		t.Fatal(err)
	}
	if err := os.Mkdir(outside1Dir, 0777); err != nil {
		t.Fatal(err)
	}
	if err := os.Mkdir(outside2Dir, 0777); err != nil {
		t.Fatal(err)
	}

	if err := createFile(outside1Path); err != nil {
		t.Fatal(err)
	}
	if err := createFile(outside2Path); err != nil {
		t.Fatal(err)
	}

	// mount the source as shared
	if err := MakeShared(sourceDir); err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := Unmount(sourceDir); err != nil {
			t.Fatal(err)
		}
	}()

	// mount the shared directory to a target
	if err := Mount(sourceDir, targetDir, "none", "bind,rw"); err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := Unmount(targetDir); err != nil {
			t.Fatal(err)
		}
	}()

	// next, make the target slave
	if err := MakeSlave(targetDir); err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := Unmount(targetDir); err != nil {
			t.Fatal(err)
		}
	}()

	// mount in an outside path to a mounted path inside the _source_
	if err := Mount(outside1Dir, path.Join(sourceDir, "a"), "none", "bind,rw"); err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := Unmount(path.Join(sourceDir, "a")); err != nil {
			t.Fatal(err)
		}
	}()

	// check that this file _does_ show in the _target_
	if _, err := os.Stat(outside1CheckPath); err != nil {
		t.Fatal(err)
	}

	// next mount outside2Dir into the _target_
	if err := Mount(outside2Dir, path.Join(targetDir, "b"), "none", "bind,rw"); err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := Unmount(path.Join(targetDir, "b")); err != nil {
			t.Fatal(err)
		}
	}()

	// check that this file _does_not_ show in the _source_
	if _, err := os.Stat(outside2CheckPath); err != nil && !os.IsNotExist(err) {
		t.Fatal(err)
	} else if err == nil {
		t.Fatalf("%q should not be visible, but is", outside2CheckPath)
	}
}

func TestSubtreeUnbindable(t *testing.T) {
	tmp := path.Join(os.TempDir(), "mount-tests")
	if err := os.MkdirAll(tmp, 0777); err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(tmp)

	var (
		sourceDir = path.Join(tmp, "source")
		targetDir = path.Join(tmp, "target")
	)
	if err := os.MkdirAll(sourceDir, 0777); err != nil {
		t.Fatal(err)
	}
	if err := os.MkdirAll(targetDir, 0777); err != nil {
		t.Fatal(err)
	}

	// next, make the source unbindable
	if err := MakeUnbindable(sourceDir); err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := Unmount(sourceDir); err != nil {
			t.Fatal(err)
		}
	}()

	// then attempt to mount it to target. It should fail
	if err := Mount(sourceDir, targetDir, "none", "bind,rw"); err != nil && err != syscall.EINVAL {
		t.Fatal(err)
	} else if err == nil {
		t.Fatalf("%q should not have been bindable", sourceDir)
	}
	defer func() {
		if err := Unmount(targetDir); err != nil {
			t.Fatal(err)
		}
	}()
}

func createFile(path string) error {
	f, err := os.Create(path)
	if err != nil {
		return err
	}
	f.WriteString("hello world!")
	return f.Close()
}
<commit_msg>fix comments typos<commit_after>// +build linux

package mount

import (
	"os"
	"path"
	"syscall"
	"testing"
)

// nothing is propagated in or out
func TestSubtreePrivate(t *testing.T) {
	tmp := path.Join(os.TempDir(), "mount-tests")
	if err := os.MkdirAll(tmp, 0777); err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(tmp)

	var (
		sourceDir   = path.Join(tmp, "source")
		targetDir   = path.Join(tmp, "target")
		outside1Dir = path.Join(tmp, "outside1")
		outside2Dir = path.Join(tmp, "outside2")

		outside1Path      = path.Join(outside1Dir, "file.txt")
		outside2Path      = path.Join(outside2Dir, "file.txt")
		outside1CheckPath = path.Join(targetDir, "a", "file.txt")
		outside2CheckPath = path.Join(sourceDir, "b", "file.txt")
	)
	if err := os.MkdirAll(path.Join(sourceDir, "a"), 0777); err != nil {
		t.Fatal(err)
	}
	if err := os.MkdirAll(path.Join(sourceDir, "b"), 0777); err != nil {
		t.Fatal(err)
	}
	if err := os.Mkdir(targetDir, 0777); err != nil {
		t.Fatal(err)
	}
	if err := os.Mkdir(outside1Dir, 0777); err != nil {
		t.Fatal(err)
	}
	if err := os.Mkdir(outside2Dir, 0777); err != nil {
		t.Fatal(err)
	}

	if err := createFile(outside1Path); err != nil {
		t.Fatal(err)
	}
	if err := createFile(outside2Path); err != nil {
		t.Fatal(err)
	}

	// mount the shared directory to a target
	if err := Mount(sourceDir, targetDir, "none", "bind,rw"); err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := Unmount(targetDir); err != nil {
			t.Fatal(err)
		}
	}()

	// next, make the target private
	if err := MakePrivate(targetDir); err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := Unmount(targetDir); err != nil {
			t.Fatal(err)
		}
	}()

	// mount in an outside path to a mounted path inside the _source_
	if err := Mount(outside1Dir, path.Join(sourceDir, "a"), "none", "bind,rw"); err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := Unmount(path.Join(sourceDir, "a")); err != nil {
			t.Fatal(err)
		}
	}()

	// check that this file _does_not_ show in the _target_
	if _, err := os.Stat(outside1CheckPath); err != nil && !os.IsNotExist(err) {
		t.Fatal(err)
	} else if err == nil {
		t.Fatalf("%q should not be visible, but is", outside1CheckPath)
	}

	// next mount outside2Dir into the _target_
	if err := Mount(outside2Dir, path.Join(targetDir, "b"), "none", "bind,rw"); err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := Unmount(path.Join(targetDir, "b")); err != nil {
			t.Fatal(err)
		}
	}()

	// check that this file _does_not_ show in the _source_
	if _, err := os.Stat(outside2CheckPath); err != nil && !os.IsNotExist(err) {
		t.Fatal(err)
	} else if err == nil {
		t.Fatalf("%q should not be visible, but is", outside2CheckPath)
	}
}

// Testing that when a target is a shared mount,
// then child mounts propogate to the source
func TestSubtreeShared(t *testing.T) {
	tmp := path.Join(os.TempDir(), "mount-tests")
	if err := os.MkdirAll(tmp, 0777); err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(tmp)

	var (
		sourceDir  = path.Join(tmp, "source")
		targetDir  = path.Join(tmp, "target")
		outsideDir = path.Join(tmp, "outside")

		outsidePath     = path.Join(outsideDir, "file.txt")
		sourceCheckPath = path.Join(sourceDir, "a", "file.txt")
	)

	if err := os.MkdirAll(path.Join(sourceDir, "a"), 0777); err != nil {
		t.Fatal(err)
	}
	if err := os.Mkdir(targetDir, 0777); err != nil {
		t.Fatal(err)
	}
	if err := os.Mkdir(outsideDir, 0777); err != nil {
		t.Fatal(err)
	}

	if err := createFile(outsidePath); err != nil {
		t.Fatal(err)
	}

	// mount the source as shared
	if err := MakeShared(sourceDir); err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := Unmount(sourceDir); err != nil {
			t.Fatal(err)
		}
	}()

	// mount the shared directory to a target
	if err := Mount(sourceDir, targetDir, "none", "bind,rw"); err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := Unmount(targetDir); err != nil {
			t.Fatal(err)
		}
	}()

	// mount in an outside path to a mounted path inside the target
	if err := Mount(outsideDir, path.Join(targetDir, "a"), "none", "bind,rw"); err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := Unmount(path.Join(targetDir, "a")); err != nil {
			t.Fatal(err)
		}
	}()

	// NOW, check that the file from the outside directory is avaible in the source directory
	if _, err := os.Stat(sourceCheckPath); err != nil {
		t.Fatal(err)
	}
}

// testing that mounts to a shared source show up in the slave target,
// and that mounts into a slave target do _not_ show up in the shared source
func TestSubtreeSharedSlave(t *testing.T) {
	tmp := path.Join(os.TempDir(), "mount-tests")
	if err := os.MkdirAll(tmp, 0777); err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(tmp)

	var (
		sourceDir   = path.Join(tmp, "source")
		targetDir   = path.Join(tmp, "target")
		outside1Dir = path.Join(tmp, "outside1")
		outside2Dir = path.Join(tmp, "outside2")

		outside1Path      = path.Join(outside1Dir, "file.txt")
		outside2Path      = path.Join(outside2Dir, "file.txt")
		outside1CheckPath = path.Join(targetDir, "a", "file.txt")
		outside2CheckPath = path.Join(sourceDir, "b", "file.txt")
	)
	if err := os.MkdirAll(path.Join(sourceDir, "a"), 0777); err != nil {
		t.Fatal(err)
	}
	if err := os.MkdirAll(path.Join(sourceDir, "b"), 0777); err != nil {
		t.Fatal(err)
	}
	if err := os.Mkdir(targetDir, 0777); err != nil {
		t.Fatal(err)
	}
	if err := os.Mkdir(outside1Dir, 0777); err != nil {
		t.Fatal(err)
	}
	if err := os.Mkdir(outside2Dir, 0777); err != nil {
		t.Fatal(err)
	}

	if err := createFile(outside1Path); err != nil {
		t.Fatal(err)
	}
	if err := createFile(outside2Path); err != nil {
		t.Fatal(err)
	}

	// mount the source as shared
	if err := MakeShared(sourceDir); err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := Unmount(sourceDir); err != nil {
			t.Fatal(err)
		}
	}()

	// mount the shared directory to a target
	if err := Mount(sourceDir, targetDir, "none", "bind,rw"); err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := Unmount(targetDir); err != nil {
			t.Fatal(err)
		}
	}()

	// next, make the target slave
	if err := MakeSlave(targetDir); err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := Unmount(targetDir); err != nil {
			t.Fatal(err)
		}
	}()

	// mount in an outside path to a mounted path inside the _source_
	if err := Mount(outside1Dir, path.Join(sourceDir, "a"), "none", "bind,rw"); err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := Unmount(path.Join(sourceDir, "a")); err != nil {
			t.Fatal(err)
		}
	}()

	// check that this file _does_ show in the _target_
	if _, err := os.Stat(outside1CheckPath); err != nil {
		t.Fatal(err)
	}

	// next mount outside2Dir into the _target_
	if err := Mount(outside2Dir, path.Join(targetDir, "b"), "none", "bind,rw"); err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := Unmount(path.Join(targetDir, "b")); err != nil {
			t.Fatal(err)
		}
	}()

	// check that this file _does_not_ show in the _source_
	if _, err := os.Stat(outside2CheckPath); err != nil && !os.IsNotExist(err) {
		t.Fatal(err)
	} else if err == nil {
		t.Fatalf("%q should not be visible, but is", outside2CheckPath)
	}
}

func TestSubtreeUnbindable(t *testing.T) {
	tmp := path.Join(os.TempDir(), "mount-tests")
	if err := os.MkdirAll(tmp, 0777); err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(tmp)

	var (
		sourceDir = path.Join(tmp, "source")
		targetDir = path.Join(tmp, "target")
	)
	if err := os.MkdirAll(sourceDir, 0777); err != nil {
		t.Fatal(err)
	}
	if err := os.MkdirAll(targetDir, 0777); err != nil {
		t.Fatal(err)
	}

	// next, make the source unbindable
	if err := MakeUnbindable(sourceDir); err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := Unmount(sourceDir); err != nil {
			t.Fatal(err)
		}
	}()

	// then attempt to mount it to target. It should fail
	if err := Mount(sourceDir, targetDir, "none", "bind,rw"); err != nil && err != syscall.EINVAL {
		t.Fatal(err)
	} else if err == nil {
		t.Fatalf("%q should not have been bindable", sourceDir)
	}
	defer func() {
		if err := Unmount(targetDir); err != nil {
			t.Fatal(err)
		}
	}()
}

func createFile(path string) error {
	f, err := os.Create(path)
	if err != nil {
		return err
	}
	f.WriteString("hello world!")
	return f.Close()
}
<|endoftext|>


<commit_before>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package cli

import (
	"os"
	"sort"
	"strings"

	"github.com/spf13/cobra"
	"mynewt.apache.org/newt/newt/downloader"
	"mynewt.apache.org/newt/newt/interfaces"
	"mynewt.apache.org/newt/newt/newtutil"
	"mynewt.apache.org/newt/newt/project"
	"mynewt.apache.org/newt/newt/repo"
	"mynewt.apache.org/newt/util"
)

var infoRemote bool

func newRunCmd(cmd *cobra.Command, args []string) {
	if len(args) < 1 {
		NewtUsage(cmd, util.NewNewtError("Must specify "+
			"a project directory to newt new"))
	}

	newDir := args[0]

	if util.NodeExist(newDir) {
		NewtUsage(cmd, util.NewNewtError("Cannot create new project, "+
			"directory already exists"))
	}

	util.StatusMessage(util.VERBOSITY_DEFAULT, "Downloading "+
		"project skeleton from apache/mynewt-blinky...\n")
	dl := downloader.NewGithubDownloader()
	dl.User = "apache"
	dl.Repo = "mynewt-blinky"

	tmpdir, err := newtutil.MakeTempRepoDir()
	if err != nil {
		NewtUsage(nil, err)
	}
	defer os.RemoveAll(tmpdir)

	if err := dl.Clone(newtutil.NewtBlinkyTag, tmpdir); err != nil {
		NewtUsage(nil, err)
	}

	util.StatusMessage(util.VERBOSITY_DEFAULT, "Installing "+
		"skeleton in %s...\n", newDir)

	if err := util.CopyDir(tmpdir, newDir); err != nil {
		NewtUsage(cmd, err)
	}

	if err := os.RemoveAll(newDir + "/" + "/.git/"); err != nil {
		NewtUsage(cmd, err)
	}

	util.StatusMessage(util.VERBOSITY_DEFAULT,
		"Project %s successfully created.\n", newDir)
}

// Builds a repo selection predicate based on the specified names.  If no names
// are specified, the resulting function selects all non-local repos.
// Otherwise, the function selects each non-local repo whose name is specified.
func makeRepoPredicate(repoNames []string) func(r *repo.Repo) bool {
	// If the user didn't specify any repo names, apply the operation to all
	// repos in `project.yml`.
	if len(repoNames) == 0 {
		proj := project.GetProject()
		return func(r *repo.Repo) bool { return proj.RepoIsRoot(r.Name()) }
	}

	return func(r *repo.Repo) bool {
		if !r.IsLocal() {
			for _, arg := range repoNames {
				if strings.TrimPrefix(r.Name(), "@") == arg {
					return true
				}
			}
		}
		return false
	}
}

func installRunCmd(cmd *cobra.Command, args []string) {
	proj := TryGetOrDownloadProject()
	interfaces.SetProject(proj)

	pred := makeRepoPredicate(args)
	if err := proj.UpgradeIf(
		newtutil.NewtForce, newtutil.NewtAsk, pred); err != nil {

		NewtUsage(nil, err)
	}
}

func upgradeRunCmd(cmd *cobra.Command, args []string) {
	proj := TryGetOrDownloadProject()
	interfaces.SetProject(proj)

	pred := makeRepoPredicate(args)
	if err := proj.UpgradeIf(
		newtutil.NewtForce, newtutil.NewtAsk, pred); err != nil {

		NewtUsage(nil, err)
	}
}

func infoRunCmd(cmd *cobra.Command, args []string) {
	proj := TryGetProject()

	// If no arguments specified, print status of all installed repos.
	if len(args) == 0 {
		pred := func(r *repo.Repo) bool { return true }
		if err := proj.InfoIf(pred, infoRemote); err != nil {
			NewtUsage(nil, err)
		}

		return
	}

	// Otherwise, list packages specified repo contains.
	reqRepoName := strings.TrimPrefix(args[0], "@")

	repoNames := []string{}
	for repoName, _ := range proj.PackageList() {
		repoNames = append(repoNames, repoName)
	}
	sort.Strings(repoNames)

	firstRepo := true
	for _, repoName := range repoNames {
		if reqRepoName == "all" || reqRepoName == repoName {
			packNames := []string{}
			for _, pack := range *proj.PackageList()[repoName] {
				// Don't display the special unittest target; this is used
				// internally by newt, so the user doesn't need to know about
				// it.
				// XXX: This is a hack; come up with a better solution for
				// unit testing.
				if !strings.HasSuffix(pack.Name(), "/unittest") {
					packNames = append(packNames, pack.Name())
				}
			}

			sort.Strings(packNames)
			if !firstRepo {
				util.StatusMessage(util.VERBOSITY_DEFAULT, "\n")
			} else {
				firstRepo = false
			}
			util.StatusMessage(util.VERBOSITY_DEFAULT, "Packages in @%s:\n",
				repoName)
			for _, pkgName := range packNames {
				util.StatusMessage(util.VERBOSITY_DEFAULT, "    * %s\n",
					pkgName)
			}
		}
	}
}

func syncRunCmd(cmd *cobra.Command, args []string) {
	proj := TryGetOrDownloadProject()
	pred := makeRepoPredicate(args)

	if err := proj.UpgradeIf(
		newtutil.NewtForce, newtutil.NewtAsk, pred); err != nil {

		NewtUsage(nil, err)
	}
}

func AddProjectCommands(cmd *cobra.Command) {
	installHelpText := ""
	installHelpEx := "  newt install\n"
	installHelpEx += "    Installs all repositories specified in project.yml.\n\n"
	installHelpEx += "  newt install apache-mynewt-core\n"
	installHelpEx += "    Installs the apache-mynewt-core repository."
	installCmd := &cobra.Command{
		Use:        "install [repo-1] [repo-2] [...]",
		Deprecated: "use \"upgrade\" instead",
		Long:       installHelpText,
		Example:    installHelpEx,
		Run:        installRunCmd,
	}
	installCmd.PersistentFlags().BoolVarP(&newtutil.NewtForce,
		"force", "f", false,
		"Force install of the repositories in project, regardless of what "+
			"exists in repos directory")
	installCmd.PersistentFlags().BoolVarP(&newtutil.NewtAsk,
		"ask", "a", false, "Prompt user before installing any repos")

	cmd.AddCommand(installCmd)

	upgradeHelpText := ""
	upgradeHelpEx := "  newt upgrade\n"
	upgradeHelpEx += "    Upgrades all repositories specified in project.yml.\n\n"
	upgradeHelpEx += "  newt upgrade apache-mynewt-core\n"
	upgradeHelpEx += "    Upgrades the apache-mynewt-core repository."
	upgradeCmd := &cobra.Command{
		Use:     "upgrade [repo-1] [repo-2] [...]",
		Short:   "Upgrade project dependencies",
		Long:    upgradeHelpText,
		Example: upgradeHelpEx,
		Run:     upgradeRunCmd,
	}
	upgradeCmd.PersistentFlags().BoolVarP(&newtutil.NewtForce,
		"force", "f", false,
		"Force upgrade of the repositories to latest state in project.yml")
	upgradeCmd.PersistentFlags().BoolVarP(&newtutil.NewtAsk,
		"ask", "a", false, "Prompt user before upgrading any repos")

	cmd.AddCommand(upgradeCmd)

	syncHelpText := ""
	syncHelpEx := "  newt sync\n"
	syncHelpEx += "    Syncs all repositories specified in project.yml.\n\n"
	syncHelpEx += "  newt sync apache-mynewt-core\n"
	syncHelpEx += "    Syncs the apache-mynewt-core repository."
	syncCmd := &cobra.Command{
		Use:        "sync [repo-1] [repo-2] [...]",
		Deprecated: "use \"upgrade\" instead",
		Long:       syncHelpText,
		Example:    syncHelpEx,
		Run:        syncRunCmd,
	}
	syncCmd.PersistentFlags().BoolVarP(&newtutil.NewtForce,
		"force", "f", false,
		"Force overwrite of existing remote repositories.")
	syncCmd.PersistentFlags().BoolVarP(&newtutil.NewtAsk,
		"ask", "a", false, "Prompt user before syncing any repos")
	cmd.AddCommand(syncCmd)

	newHelpText := ""
	newHelpEx := ""
	newCmd := &cobra.Command{
		Use:     "new <project-dir>",
		Short:   "Create a new project",
		Long:    newHelpText,
		Example: newHelpEx,
		Run:     newRunCmd,
	}

	cmd.AddCommand(newCmd)

	infoHelpText := "Show information about the current project."
	infoHelpEx := "  newt info\n"

	infoCmd := &cobra.Command{
		Use:     "info",
		Short:   "Show project info",
		Long:    infoHelpText,
		Example: infoHelpEx,
		Run:     infoRunCmd,
	}
	infoCmd.PersistentFlags().BoolVarP(&infoRemote,
		"remote", "r", false,
		"Fetch latest repos to determine if upgrades are required")

	cmd.AddCommand(infoCmd)
}
<commit_msg>`newt info`: Include newt version at top of output<commit_after>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package cli

import (
	"os"
	"sort"
	"strings"

	"github.com/spf13/cobra"
	"mynewt.apache.org/newt/newt/downloader"
	"mynewt.apache.org/newt/newt/interfaces"
	"mynewt.apache.org/newt/newt/newtutil"
	"mynewt.apache.org/newt/newt/project"
	"mynewt.apache.org/newt/newt/repo"
	"mynewt.apache.org/newt/util"
)

var infoRemote bool

func newRunCmd(cmd *cobra.Command, args []string) {
	if len(args) < 1 {
		NewtUsage(cmd, util.NewNewtError("Must specify "+
			"a project directory to newt new"))
	}

	newDir := args[0]

	if util.NodeExist(newDir) {
		NewtUsage(cmd, util.NewNewtError("Cannot create new project, "+
			"directory already exists"))
	}

	util.StatusMessage(util.VERBOSITY_DEFAULT, "Downloading "+
		"project skeleton from apache/mynewt-blinky...\n")
	dl := downloader.NewGithubDownloader()
	dl.User = "apache"
	dl.Repo = "mynewt-blinky"

	tmpdir, err := newtutil.MakeTempRepoDir()
	if err != nil {
		NewtUsage(nil, err)
	}
	defer os.RemoveAll(tmpdir)

	if err := dl.Clone(newtutil.NewtBlinkyTag, tmpdir); err != nil {
		NewtUsage(nil, err)
	}

	util.StatusMessage(util.VERBOSITY_DEFAULT, "Installing "+
		"skeleton in %s...\n", newDir)

	if err := util.CopyDir(tmpdir, newDir); err != nil {
		NewtUsage(cmd, err)
	}

	if err := os.RemoveAll(newDir + "/" + "/.git/"); err != nil {
		NewtUsage(cmd, err)
	}

	util.StatusMessage(util.VERBOSITY_DEFAULT,
		"Project %s successfully created.\n", newDir)
}

// Builds a repo selection predicate based on the specified names.  If no names
// are specified, the resulting function selects all non-local repos.
// Otherwise, the function selects each non-local repo whose name is specified.
func makeRepoPredicate(repoNames []string) func(r *repo.Repo) bool {
	// If the user didn't specify any repo names, apply the operation to all
	// repos in `project.yml`.
	if len(repoNames) == 0 {
		proj := project.GetProject()
		return func(r *repo.Repo) bool { return proj.RepoIsRoot(r.Name()) }
	}

	return func(r *repo.Repo) bool {
		if !r.IsLocal() {
			for _, arg := range repoNames {
				if strings.TrimPrefix(r.Name(), "@") == arg {
					return true
				}
			}
		}
		return false
	}
}

func installRunCmd(cmd *cobra.Command, args []string) {
	proj := TryGetOrDownloadProject()
	interfaces.SetProject(proj)

	pred := makeRepoPredicate(args)
	if err := proj.UpgradeIf(
		newtutil.NewtForce, newtutil.NewtAsk, pred); err != nil {

		NewtUsage(nil, err)
	}
}

func upgradeRunCmd(cmd *cobra.Command, args []string) {
	proj := TryGetOrDownloadProject()
	interfaces.SetProject(proj)

	pred := makeRepoPredicate(args)
	if err := proj.UpgradeIf(
		newtutil.NewtForce, newtutil.NewtAsk, pred); err != nil {

		NewtUsage(nil, err)
	}
}

func infoRunCmd(cmd *cobra.Command, args []string) {
	newtutil.PrintNewtVersion()

	proj := TryGetProject()

	// If no arguments specified, print status of all installed repos.
	if len(args) == 0 {
		pred := func(r *repo.Repo) bool { return true }
		if err := proj.InfoIf(pred, infoRemote); err != nil {
			NewtUsage(nil, err)
		}

		return
	}

	// Otherwise, list packages specified repo contains.
	reqRepoName := strings.TrimPrefix(args[0], "@")

	repoNames := []string{}
	for repoName, _ := range proj.PackageList() {
		repoNames = append(repoNames, repoName)
	}
	sort.Strings(repoNames)

	firstRepo := true
	for _, repoName := range repoNames {
		if reqRepoName == "all" || reqRepoName == repoName {
			packNames := []string{}
			for _, pack := range *proj.PackageList()[repoName] {
				// Don't display the special unittest target; this is used
				// internally by newt, so the user doesn't need to know about
				// it.
				// XXX: This is a hack; come up with a better solution for
				// unit testing.
				if !strings.HasSuffix(pack.Name(), "/unittest") {
					packNames = append(packNames, pack.Name())
				}
			}

			sort.Strings(packNames)
			if !firstRepo {
				util.StatusMessage(util.VERBOSITY_DEFAULT, "\n")
			} else {
				firstRepo = false
			}
			util.StatusMessage(util.VERBOSITY_DEFAULT, "Packages in @%s:\n",
				repoName)
			for _, pkgName := range packNames {
				util.StatusMessage(util.VERBOSITY_DEFAULT, "    * %s\n",
					pkgName)
			}
		}
	}
}

func syncRunCmd(cmd *cobra.Command, args []string) {
	proj := TryGetOrDownloadProject()
	pred := makeRepoPredicate(args)

	if err := proj.UpgradeIf(
		newtutil.NewtForce, newtutil.NewtAsk, pred); err != nil {

		NewtUsage(nil, err)
	}
}

func AddProjectCommands(cmd *cobra.Command) {
	installHelpText := ""
	installHelpEx := "  newt install\n"
	installHelpEx += "    Installs all repositories specified in project.yml.\n\n"
	installHelpEx += "  newt install apache-mynewt-core\n"
	installHelpEx += "    Installs the apache-mynewt-core repository."
	installCmd := &cobra.Command{
		Use:        "install [repo-1] [repo-2] [...]",
		Deprecated: "use \"upgrade\" instead",
		Long:       installHelpText,
		Example:    installHelpEx,
		Run:        installRunCmd,
	}
	installCmd.PersistentFlags().BoolVarP(&newtutil.NewtForce,
		"force", "f", false,
		"Force install of the repositories in project, regardless of what "+
			"exists in repos directory")
	installCmd.PersistentFlags().BoolVarP(&newtutil.NewtAsk,
		"ask", "a", false, "Prompt user before installing any repos")

	cmd.AddCommand(installCmd)

	upgradeHelpText := ""
	upgradeHelpEx := "  newt upgrade\n"
	upgradeHelpEx += "    Upgrades all repositories specified in project.yml.\n\n"
	upgradeHelpEx += "  newt upgrade apache-mynewt-core\n"
	upgradeHelpEx += "    Upgrades the apache-mynewt-core repository."
	upgradeCmd := &cobra.Command{
		Use:     "upgrade [repo-1] [repo-2] [...]",
		Short:   "Upgrade project dependencies",
		Long:    upgradeHelpText,
		Example: upgradeHelpEx,
		Run:     upgradeRunCmd,
	}
	upgradeCmd.PersistentFlags().BoolVarP(&newtutil.NewtForce,
		"force", "f", false,
		"Force upgrade of the repositories to latest state in project.yml")
	upgradeCmd.PersistentFlags().BoolVarP(&newtutil.NewtAsk,
		"ask", "a", false, "Prompt user before upgrading any repos")

	cmd.AddCommand(upgradeCmd)

	syncHelpText := ""
	syncHelpEx := "  newt sync\n"
	syncHelpEx += "    Syncs all repositories specified in project.yml.\n\n"
	syncHelpEx += "  newt sync apache-mynewt-core\n"
	syncHelpEx += "    Syncs the apache-mynewt-core repository."
	syncCmd := &cobra.Command{
		Use:        "sync [repo-1] [repo-2] [...]",
		Deprecated: "use \"upgrade\" instead",
		Long:       syncHelpText,
		Example:    syncHelpEx,
		Run:        syncRunCmd,
	}
	syncCmd.PersistentFlags().BoolVarP(&newtutil.NewtForce,
		"force", "f", false,
		"Force overwrite of existing remote repositories.")
	syncCmd.PersistentFlags().BoolVarP(&newtutil.NewtAsk,
		"ask", "a", false, "Prompt user before syncing any repos")
	cmd.AddCommand(syncCmd)

	newHelpText := ""
	newHelpEx := ""
	newCmd := &cobra.Command{
		Use:     "new <project-dir>",
		Short:   "Create a new project",
		Long:    newHelpText,
		Example: newHelpEx,
		Run:     newRunCmd,
	}

	cmd.AddCommand(newCmd)

	infoHelpText := "Show information about the current project."
	infoHelpEx := "  newt info\n"

	infoCmd := &cobra.Command{
		Use:     "info",
		Short:   "Show project info",
		Long:    infoHelpText,
		Example: infoHelpEx,
		Run:     infoRunCmd,
	}
	infoCmd.PersistentFlags().BoolVarP(&infoRemote,
		"remote", "r", false,
		"Fetch latest repos to determine if upgrades are required")

	cmd.AddCommand(infoCmd)
}
<|endoftext|>


<commit_before>/* vim: set sw=4 sts=4 et foldmethod=syntax : */

/*
 * Copyright (c) 2011 Alexander Færøy <ahf@0x90.dk>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice, this
 *   list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package main

import (
    "crypto/rand"
    "crypto/tls"
    "fmt"
    "io/ioutil"
    "log"
    "os"
    "strconv"
    "strings"
    "time"
)
type Ircd struct {
    *log.Logger
    listeners []Listener
    config *ConfigurationFile

    motdFile string
    motdContent []string

    clientRegistry *ClientRegistry
}

func NewIrcd() *Ircd {
    ircd := new(Ircd)
    ircd.Logger = log.New(os.Stderr, "", log.Ldate | log.Ltime)
    ircd.listeners = make([]Listener, 0)
    ircd.clientRegistry = NewClientRegistry()

    return ircd
}

func (this *Ircd) SetConfigurationFile(config *ConfigurationFile) {
    this.config = config

    for i := range this.config.Ircd.Listeners {
        listener := this.config.Ircd.Listeners[i]
        hostport := listener.Host + ":" + strconv.Itoa(listener.Port)
        protocol := ProtocolFromString(listener.Type)

        if protocol == nil {
            this.Printf("Unknown protocol type: %s\n", listener.Type)
            continue
        }

        if listener.Tls {
            this.addSecureListener(*protocol, hostport)
        } else {
            this.addListener(*protocol, hostport)
        }
    }
}

func (this *Ircd) addCommonListener(p Protocol, address string, config *tls.Config) {
    var listener Listener

    switch p {
        case TCP: listener = NewTCPListener(this, address, config)
        case WebSocket: listener = NewWebSocketListener(this, address, config)
        default: panic("Unhandled Protocol.")
    }

    if listener != nil {
        this.listeners = append(this.listeners, listener)
    }
}

func (this *Ircd) addListener(protocol Protocol, address string) {
    this.addCommonListener(protocol, address, nil)
}

func (this *Ircd) addSecureListener(protocol Protocol, address string) {
    cert := this.config.Ircd.ServerInfo.Tls.Certificate
    key := this.config.Ircd.ServerInfo.Tls.Key
    errorMessage := fmt.Sprintf("Unable to add secure listener for %s", address)

    if cert == "" {
        this.Printf("%s: %s", errorMessage, "Empty TLS certificate in configuration file.")
        return
    }

    if key == "" {
        this.Printf("%s: %s", errorMessage, "Empty TLS key in configuration file.")
        return
    }

    certificate, error := tls.LoadX509KeyPair(cert, key)

    if error != nil {
        this.Printf("Error Loading Certificate: %s", error)
        return
    }

    config := &tls.Config{
        Rand: rand.Reader,
        Time: time.Seconds,
    }

    config.Certificates = make([]tls.Certificate, 1)
    config.Certificates[0] = certificate

    if protocol == WebSocket {
        config.NextProtos = []string{"http/1.1"}
    }

    this.addCommonListener(protocol, address, config)
}

func (this *Ircd) Run() {
    if len(this.listeners) == 0 {
        fmt.Printf("Error: No Listeners Defined...\n")
        os.Exit(1)
    }

    this.Printf("Opening up for incoming connections")

    for i := range this.listeners {
        listener := this.listeners[i]

        this.Printf("Listening on %s (%s %s)", listener.Address(), listener.Secure(), listener.Protocol())
        go listener.Listen()
    }
}

func (this *Ircd) Me() string {
    return this.config.Ircd.ServerInfo.Name
}

func (this *Ircd) Description() string {
    return this.config.Ircd.ServerInfo.Description
}

func (this *Ircd) SetMotdFile(path string) {
    this.motdFile = path

    this.LoadMotd()
}

func (this *Ircd) LoadMotd() {
    content, error := ioutil.ReadFile(this.motdFile)

    if error != nil {
        this.Printf("Unable to load MOTD file: %s", error)
        return
    }

    this.motdContent = strings.Split(string(content), "\n", -1)
}

func (this *Ircd) FindClient(nick string) *Client {
    return this.clientRegistry.Find(nick)
}
<commit_msg>Add Motd() call to the Ircd-type to access the MOTD data.<commit_after>/* vim: set sw=4 sts=4 et foldmethod=syntax : */

/*
 * Copyright (c) 2011 Alexander Færøy <ahf@0x90.dk>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice, this
 *   list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package main

import (
    "crypto/rand"
    "crypto/tls"
    "fmt"
    "io/ioutil"
    "log"
    "os"
    "strconv"
    "strings"
    "time"
)
type Ircd struct {
    *log.Logger
    listeners []Listener
    config *ConfigurationFile

    motdFile string
    motdContent []string

    clientRegistry *ClientRegistry
}

func NewIrcd() *Ircd {
    ircd := new(Ircd)
    ircd.Logger = log.New(os.Stderr, "", log.Ldate | log.Ltime)
    ircd.listeners = make([]Listener, 0)
    ircd.clientRegistry = NewClientRegistry()

    return ircd
}

func (this *Ircd) SetConfigurationFile(config *ConfigurationFile) {
    this.config = config

    for i := range this.config.Ircd.Listeners {
        listener := this.config.Ircd.Listeners[i]
        hostport := listener.Host + ":" + strconv.Itoa(listener.Port)
        protocol := ProtocolFromString(listener.Type)

        if protocol == nil {
            this.Printf("Unknown protocol type: %s\n", listener.Type)
            continue
        }

        if listener.Tls {
            this.addSecureListener(*protocol, hostport)
        } else {
            this.addListener(*protocol, hostport)
        }
    }
}

func (this *Ircd) addCommonListener(p Protocol, address string, config *tls.Config) {
    var listener Listener

    switch p {
        case TCP: listener = NewTCPListener(this, address, config)
        case WebSocket: listener = NewWebSocketListener(this, address, config)
        default: panic("Unhandled Protocol.")
    }

    if listener != nil {
        this.listeners = append(this.listeners, listener)
    }
}

func (this *Ircd) addListener(protocol Protocol, address string) {
    this.addCommonListener(protocol, address, nil)
}

func (this *Ircd) addSecureListener(protocol Protocol, address string) {
    cert := this.config.Ircd.ServerInfo.Tls.Certificate
    key := this.config.Ircd.ServerInfo.Tls.Key
    errorMessage := fmt.Sprintf("Unable to add secure listener for %s", address)

    if cert == "" {
        this.Printf("%s: %s", errorMessage, "Empty TLS certificate in configuration file.")
        return
    }

    if key == "" {
        this.Printf("%s: %s", errorMessage, "Empty TLS key in configuration file.")
        return
    }

    certificate, error := tls.LoadX509KeyPair(cert, key)

    if error != nil {
        this.Printf("Error Loading Certificate: %s", error)
        return
    }

    config := &tls.Config{
        Rand: rand.Reader,
        Time: time.Seconds,
    }

    config.Certificates = make([]tls.Certificate, 1)
    config.Certificates[0] = certificate

    if protocol == WebSocket {
        config.NextProtos = []string{"http/1.1"}
    }

    this.addCommonListener(protocol, address, config)
}

func (this *Ircd) Run() {
    if len(this.listeners) == 0 {
        fmt.Printf("Error: No Listeners Defined...\n")
        os.Exit(1)
    }

    this.Printf("Opening up for incoming connections")

    for i := range this.listeners {
        listener := this.listeners[i]

        this.Printf("Listening on %s (%s %s)", listener.Address(), listener.Secure(), listener.Protocol())
        go listener.Listen()
    }
}

func (this *Ircd) Me() string {
    return this.config.Ircd.ServerInfo.Name
}

func (this *Ircd) Description() string {
    return this.config.Ircd.ServerInfo.Description
}

func (this *Ircd) SetMotdFile(path string) {
    this.motdFile = path

    this.LoadMotd()
}

func (this *Ircd) LoadMotd() {
    content, error := ioutil.ReadFile(this.motdFile)

    if error != nil {
        this.Printf("Unable to load MOTD file: %s", error)
        return
    }

    this.motdContent = strings.Split(string(content), "\n", -1)
}

func (this *Ircd) Motd() *[]string {
    if len(this.motdContent) == 0 {
        return nil
    }

    return &this.motdContent
}

func (this *Ircd) FindClient(nick string) *Client {
    return this.clientRegistry.Find(nick)
}
<|endoftext|>


<commit_before>// inner_events.go provides EventsAPI particular inner events

package slackevents

import "encoding/json"

// EventsAPIInnerEvent the inner event of a EventsAPI event_callback Event.
type EventsAPIInnerEvent struct {
	Type string `json:"type"`
	Data interface{}
}

// AppMentionEvent is an (inner) EventsAPI subscribable event.
type AppMentionEvent struct {
	Type           string      `json:"type"`
	User           string      `json:"user"`
	Text           string      `json:"text"`
	TimeStamp      string      `json:"ts"`
	Channel        string      `json:"channel"`
	EventTimeStamp json.Number `json:"event_ts"`
}

// AppUninstalledEvent Your Slack app was uninstalled.
type AppUninstalledEvent struct {
	Type string `json:"type"`
}

// GridMigrationFinishedEvent An enterprise grid migration has finished on this workspace.
type GridMigrationFinishedEvent struct {
	Type         string `json:"type"`
	EnterpriseID string `json:"enterprise_id"`
}

// GridMigrationStartedEvent An enterprise grid migration has started on this workspace.
type GridMigrationStartedEvent struct {
	Type         string `json:"type"`
	EnterpriseID string `json:"enterprise_id"`
}

// LinkSharedEvent A message was posted containing one or more links relevant to your application
type LinkSharedEvent struct {
	Type             string        `json:"type"`
	User             string        `json:"user"`
	TimeStamp        string        `json:"ts"`
	Channel          string        `json:"channel"`
	MessageTimeStamp json.Number   `json:"message_ts"`
	Links            []sharedLinks `json:"links"`
}

type sharedLinks struct {
	Domain string `json:"domain"`
	URL    string `json:"url"`
}

// MessageEvent occurs when a variety of types of messages has been posted.
// Parse ChannelType to see which
// if ChannelType = "group", this is a private channel message
// if ChannelType = "channel", this message was sent to a channel
// if ChannelType = "im", this is a private message
// if ChannelType = "mim", A message was posted in a multiparty direct message channel
// TODO: Improve this so that it is not required to manually parse ChannelType
type MessageEvent struct {
	// Basic Message Event - https://api.slack.com/events/message
	Type            string      `json:"type"`
        User            string      `json:"user"`
	Text            string      `json:"text"`
	ThreadTimeStamp string      `json:"thread_ts"`
	TimeStamp       string      `json:"ts"`
	Channel         string      `json:"channel"`
	ChannelType     string      `json:"channel_type"`
	EventTimeStamp  json.Number `json:"event_ts"`

	// Message Subtypes
	SubType string `json:"subtype,omitempty"`

	// bot_message (https://api.slack.com/events/message/bot_message)
	BotID    string `json:"bot_id,omitempty"`
	Username string `json:"username,omitempty"`
	Icons    *Icon  `json:"icons,omitempty"`
}

// Icon is used for bot messages
type Icon struct {
	IconURL   string `json:"icon_url,omitempty"`
	IconEmoji string `json:"icon_emoji,omitempty"`
}

const (
	// AppMention is an Events API subscribable event
	AppMention = "app_mention"
	// AppUninstalled Your Slack app was uninstalled.
	AppUninstalled = "app_uninstalled"
	// GridMigrationFinished An enterprise grid migration has finished on this workspace.
	GridMigrationFinished = "grid_migration_finished"
	// GridMigrationStarted An enterprise grid migration has started on this workspace.
	GridMigrationStarted = "grid_migration_started"
	// LinkShared A message was posted containing one or more links relevant to your application
	LinkShared = "link_shared"
	// Message A message was posted to a channel, private channel (group), im, or mim
	Message = "message"
)

// EventsAPIInnerEventMapping maps INNER Event API events to their corresponding struct
// implementations. The structs should be instances of the unmarshalling
// target for the matching event type.
var EventsAPIInnerEventMapping = map[string]interface{}{
	AppMention:            AppMentionEvent{},
	AppUninstalled:        AppUninstalledEvent{},
	GridMigrationFinished: GridMigrationFinishedEvent{},
	GridMigrationStarted:  GridMigrationStartedEvent{},
	LinkShared:            LinkSharedEvent{},
	Message:               MessageEvent{},
}
<commit_msg>add files to message events<commit_after>// inner_events.go provides EventsAPI particular inner events

package slackevents

import "encoding/json"

// EventsAPIInnerEvent the inner event of a EventsAPI event_callback Event.
type EventsAPIInnerEvent struct {
	Type string `json:"type"`
	Data interface{}
}

// AppMentionEvent is an (inner) EventsAPI subscribable event.
type AppMentionEvent struct {
	Type           string      `json:"type"`
	User           string      `json:"user"`
	Text           string      `json:"text"`
	TimeStamp      string      `json:"ts"`
	Channel        string      `json:"channel"`
	EventTimeStamp json.Number `json:"event_ts"`
}

// AppUninstalledEvent Your Slack app was uninstalled.
type AppUninstalledEvent struct {
	Type string `json:"type"`
}

// GridMigrationFinishedEvent An enterprise grid migration has finished on this workspace.
type GridMigrationFinishedEvent struct {
	Type         string `json:"type"`
	EnterpriseID string `json:"enterprise_id"`
}

// GridMigrationStartedEvent An enterprise grid migration has started on this workspace.
type GridMigrationStartedEvent struct {
	Type         string `json:"type"`
	EnterpriseID string `json:"enterprise_id"`
}

// LinkSharedEvent A message was posted containing one or more links relevant to your application
type LinkSharedEvent struct {
	Type             string        `json:"type"`
	User             string        `json:"user"`
	TimeStamp        string        `json:"ts"`
	Channel          string        `json:"channel"`
	MessageTimeStamp json.Number   `json:"message_ts"`
	Links            []sharedLinks `json:"links"`
}

type sharedLinks struct {
	Domain string `json:"domain"`
	URL    string `json:"url"`
}

// MessageEvent occurs when a variety of types of messages has been posted.
// Parse ChannelType to see which
// if ChannelType = "group", this is a private channel message
// if ChannelType = "channel", this message was sent to a channel
// if ChannelType = "im", this is a private message
// if ChannelType = "mim", A message was posted in a multiparty direct message channel
// TODO: Improve this so that it is not required to manually parse ChannelType
type MessageEvent struct {
	// Basic Message Event - https://api.slack.com/events/message
	Type            string      `json:"type"`
	User            string      `json:"user"`
	Text            string      `json:"text"`
	ThreadTimeStamp string      `json:"thread_ts"`
	TimeStamp       string      `json:"ts"`
	Channel         string      `json:"channel"`
	ChannelType     string      `json:"channel_type"`
	EventTimeStamp  json.Number `json:"event_ts"`

	// Message Subtypes
	SubType string `json:"subtype,omitempty"`

	// bot_message (https://api.slack.com/events/message/bot_message)
	BotID    string `json:"bot_id,omitempty"`
	Username string `json:"username,omitempty"`
	Icons    *Icon  `json:"icons,omitempty"`

	Upload bool   `json:"upload"`
	Files  []File `json:"files"`
}

// File is a file upload
type File struct {
	ID                 string `json:"id"`
	Created            int    `json:"created"`
	Timestamp          int    `json:"timestamp"`
	Name               string `json:"name"`
	Title              string `json:"title"`
	Mimetype           string `json:"mimetype"`
	Filetype           string `json:"filetype"`
	PrettyType         string `json:"pretty_type"`
	User               string `json:"user"`
	Editable           bool   `json:"editable"`
	Size               int    `json:"size"`
	Mode               string `json:"mode"`
	IsExternal         bool   `json:"is_external"`
	ExternalType       string `json:"external_type"`
	IsPublic           bool   `json:"is_public"`
	PublicURLShared    bool   `json:"public_url_shared"`
	DisplayAsBot       bool   `json:"display_as_bot"`
	Username           string `json:"username"`
	URLPrivate         string `json:"url_private"`
	URLPrivateDownload string `json:"url_private_download"`
	Thumb64            string `json:"thumb_64"`
	Thumb80            string `json:"thumb_80"`
	Thumb360           string `json:"thumb_360"`
	Thumb360W          int    `json:"thumb_360_w"`
	Thumb360H          int    `json:"thumb_360_h"`
	Thumb480           string `json:"thumb_480"`
	Thumb480W          int    `json:"thumb_480_w"`
	Thumb480H          int    `json:"thumb_480_h"`
	Thumb160           string `json:"thumb_160"`
	Thumb720           string `json:"thumb_720"`
	Thumb720W          int    `json:"thumb_720_w"`
	Thumb720H          int    `json:"thumb_720_h"`
	Thumb800           string `json:"thumb_800"`
	Thumb800W          int    `json:"thumb_800_w"`
	Thumb800H          int    `json:"thumb_800_h"`
	Thumb960           string `json:"thumb_960"`
	Thumb960W          int    `json:"thumb_960_w"`
	Thumb960H          int    `json:"thumb_960_h"`
	Thumb1024          string `json:"thumb_1024"`
	Thumb1024W         int    `json:"thumb_1024_w"`
	Thumb1024H         int    `json:"thumb_1024_h"`
	ImageExifRotation  int    `json:"image_exif_rotation"`
	OriginalW          int    `json:"original_w"`
	OriginalH          int    `json:"original_h"`
	Permalink          string `json:"permalink"`
	PermalinkPublic    string `json:"permalink_public"`
}

// Icon is used for bot messages
type Icon struct {
	IconURL   string `json:"icon_url,omitempty"`
	IconEmoji string `json:"icon_emoji,omitempty"`
}

const (
	// AppMention is an Events API subscribable event
	AppMention = "app_mention"
	// AppUninstalled Your Slack app was uninstalled.
	AppUninstalled = "app_uninstalled"
	// GridMigrationFinished An enterprise grid migration has finished on this workspace.
	GridMigrationFinished = "grid_migration_finished"
	// GridMigrationStarted An enterprise grid migration has started on this workspace.
	GridMigrationStarted = "grid_migration_started"
	// LinkShared A message was posted containing one or more links relevant to your application
	LinkShared = "link_shared"
	// Message A message was posted to a channel, private channel (group), im, or mim
	Message = "message"
)

// EventsAPIInnerEventMapping maps INNER Event API events to their corresponding struct
// implementations. The structs should be instances of the unmarshalling
// target for the matching event type.
var EventsAPIInnerEventMapping = map[string]interface{}{
	AppMention:            AppMentionEvent{},
	AppUninstalled:        AppUninstalledEvent{},
	GridMigrationFinished: GridMigrationFinishedEvent{},
	GridMigrationStarted:  GridMigrationStartedEvent{},
	LinkShared:            LinkSharedEvent{},
	Message:               MessageEvent{},
}
<|endoftext|>


<commit_before>package tester

import (
	"bytes"
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"net/url"
	"strings"
	"testing"

	"github.com/PuerkitoBio/goquery"
)

type Tester struct {
	mux *http.ServeMux
	t   *testing.T
}

func New(mux *http.ServeMux, t *testing.T) *Tester {
	return &Tester{
		mux: mux,
		t:   t,
	}
}

func (t *Tester) GetHTML(u string, h *http.Header) (*goquery.Document, *httptest.ResponseRecorder) {
	req, err := http.NewRequest("GET", u, nil)
	if err != nil {
		t.t.Fatal(err)
	}

	if h != nil {
		req.Header = *h
	}

	rw := httptest.NewRecorder()
	t.mux.ServeHTTP(rw, req)

	doc, err := goquery.NewDocumentFromReader(rw.Body)
	if err != nil {
		t.t.Fatal(err)
	}
	return doc, rw
}

func (t *Tester) GetBody(u string, h *http.Header) (rw *httptest.ResponseRecorder) {
	req, err := http.NewRequest("GET", u, nil)
	if err != nil {
		t.t.Fatal(err)
	}

	if h != nil {
		req.Header = *h
	}

	rw = httptest.NewRecorder()
	t.mux.ServeHTTP(rw, req)
	return
}

func (t *Tester) GetJSON(u string, v interface{}) (rw *httptest.ResponseRecorder) {
	req, err := http.NewRequest("GET", u, nil)
	if err != nil {
		t.t.Fatal(err)
	}

	rw = httptest.NewRecorder()
	t.mux.ServeHTTP(rw, req)
	body := rw.Body.Bytes()
	if rw.Code == 200 {
		if err = json.Unmarshal(body, v); err != nil {
			t.t.Log("Body:", string(body))
			t.t.Fatal(err)
		}
	}

	return
}

func (t *Tester) SendJSON(u string, v interface{}) (rw *httptest.ResponseRecorder) {
	blob, err := json.Marshal(v)
	if err != nil {
		t.t.Fatal(err)
	}

	req, err := http.NewRequest("POST", u, bytes.NewReader(blob))
	if err != nil {
		t.t.Fatal(err)
	}

	req.Header.Set("Content-Type", "application/json")

	rw = httptest.NewRecorder()
	t.mux.ServeHTTP(rw, req)
	return
}

func (t *Tester) PostForm(u string, v url.Values) (rw *httptest.ResponseRecorder) {
	req, err := http.NewRequest("POST", u, strings.NewReader(v.Encode()))
	if err != nil {
		t.t.Fatal(err)
	}
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")

	rw = httptest.NewRecorder()
	t.mux.ServeHTTP(rw, req)
	return
}
<commit_msg>tester: inject logger into http stack<commit_after>package tester

import (
	"bytes"
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"net/url"
	"strings"
	"testing"

	"github.com/PuerkitoBio/goquery"
	"github.com/cryptix/go/logging"
	"github.com/cryptix/go/logging/logtest"
)

type Tester struct {
	mux http.Handler
	t   *testing.T
}

func New(mux *http.ServeMux, t *testing.T) *Tester {
	l, _ := logtest.KitLogger("http/tester", t)
	return &Tester{
		mux: logging.InjectHandler(l)(mux),
		t:   t,
	}
}

func (t *Tester) GetHTML(u string, h *http.Header) (*goquery.Document, *httptest.ResponseRecorder) {
	req, err := http.NewRequest("GET", u, nil)
	if err != nil {
		t.t.Fatal(err)
	}

	if h != nil {
		req.Header = *h
	}

	rw := httptest.NewRecorder()
	t.mux.ServeHTTP(rw, req)

	doc, err := goquery.NewDocumentFromReader(rw.Body)
	if err != nil {
		t.t.Fatal(err)
	}
	return doc, rw
}

func (t *Tester) GetBody(u string, h *http.Header) (rw *httptest.ResponseRecorder) {
	req, err := http.NewRequest("GET", u, nil)
	if err != nil {
		t.t.Fatal(err)
	}

	if h != nil {
		req.Header = *h
	}

	rw = httptest.NewRecorder()
	t.mux.ServeHTTP(rw, req)
	return
}

func (t *Tester) GetJSON(u string, v interface{}) (rw *httptest.ResponseRecorder) {
	req, err := http.NewRequest("GET", u, nil)
	if err != nil {
		t.t.Fatal(err)
	}

	rw = httptest.NewRecorder()
	t.mux.ServeHTTP(rw, req)
	body := rw.Body.Bytes()
	if rw.Code == 200 {
		if err = json.Unmarshal(body, v); err != nil {
			t.t.Log("Body:", string(body))
			t.t.Fatal(err)
		}
	}

	return
}

func (t *Tester) SendJSON(u string, v interface{}) (rw *httptest.ResponseRecorder) {
	blob, err := json.Marshal(v)
	if err != nil {
		t.t.Fatal(err)
	}

	req, err := http.NewRequest("POST", u, bytes.NewReader(blob))
	if err != nil {
		t.t.Fatal(err)
	}

	req.Header.Set("Content-Type", "application/json")

	rw = httptest.NewRecorder()
	t.mux.ServeHTTP(rw, req)
	return
}

func (t *Tester) PostForm(u string, v url.Values) (rw *httptest.ResponseRecorder) {
	req, err := http.NewRequest("POST", u, strings.NewReader(v.Encode()))
	if err != nil {
		t.t.Fatal(err)
	}
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")

	rw = httptest.NewRecorder()
	t.mux.ServeHTTP(rw, req)
	return
}
<|endoftext|>


<commit_before>package projects

import (
	"archive/zip"
	"bytes"
	"encoding/json"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"strings"

	log "github.com/Sirupsen/logrus"
	"github.com/citruspi/milou/configuration"
	"github.com/citruspi/milou/notifications"
)

type Project struct {
	Owner      string `json:"owner"`
	Repository string `json:"repository"`
	Version    string `json:"version"`
	Identifier string `json:"identifier"`
	Path       string `json:"path"`
}

var (
	conf configuration.Configuration
	list []Project
)

func init() {
	conf = configuration.Load()

	files, err := ioutil.ReadDir(conf.Projects)

	if err != nil {
		log.Fatal(err)
	}

	for _, file := range files {
		var project Project

		source, err := ioutil.ReadFile(conf.Projects + file.Name())

		if err != nil {
			log.Fatal(err)
		}

		err = json.Unmarshal(source, &project)

		if err != nil {
			log.Fatal(err)
		}

		list = append(list, project)
	}

	if conf.Mode == "standalone" || conf.Mode == "client" {
		DeployAll()
	}
}

func (p Project) ArchivePath() string {
	var buffer bytes.Buffer

	buffer.WriteString(p.TemporaryPath())
	buffer.WriteString(p.Version)
	buffer.WriteString(".zip")

	return string(buffer.Bytes())
}

func (p Project) TemporaryPath() string {
	var buffer bytes.Buffer

	buffer.WriteString(p.Path[:len(p.Path)-1])
	buffer.WriteString(".milou/")

	return string(buffer.Bytes())
}

func (p Project) ExtractPath() string {
	var buffer bytes.Buffer

	buffer.WriteString(p.TemporaryPath())
	buffer.WriteString(p.Repository)

	return string(buffer.Bytes())
}

func (p Project) ArchiveLocation() string {
	var buffer bytes.Buffer

	buffer.WriteString("https://s3.amazonaws.com/")
	buffer.WriteString(p.Identifier)
	buffer.WriteString("/")
	buffer.WriteString(p.Version)
	buffer.WriteString(".zip")

	return string(buffer.Bytes())
}

func (p Project) Extract() error {
	r, err := zip.OpenReader(p.ArchivePath())
	if err != nil {
		return err
	}
	defer r.Close()

	for _, f := range r.File {
		rc, err := f.Open()
		if err != nil {
			return err
		}
		defer rc.Close()

		fpath := filepath.Join(p.ExtractPath(), f.Name)
		if f.FileInfo().IsDir() {
			os.MkdirAll(fpath, f.Mode())
		} else {
			var fdir string
			if lastIndex := strings.LastIndex(fpath, string(os.PathSeparator)); lastIndex > -1 {
				fdir = fpath[:lastIndex]
			}

			err = os.MkdirAll(fdir, f.Mode())
			if err != nil {
				log.Fatal(err)
				return err
			}
			f, err := os.OpenFile(
				fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
			if err != nil {
				return err
			}
			defer f.Close()

			_, err = io.Copy(f, rc)
			if err != nil {
				return err
			}
		}
	}
	return nil
}

func (p Project) Download() {
	response, err := http.Get(p.ArchiveLocation())
	defer response.Body.Close()

	if err != nil {
		log.Fatal(err)
	}

	archive, err := os.Create(p.ArchivePath())
	defer archive.Close()

	_, err = io.Copy(archive, response.Body)

	if err != nil {
		log.Fatal(err)
	}
}

func (p Project) Place() {
	err := os.RemoveAll(p.Path)

	if err != nil {
		log.Fatal(err)
	}

	err = os.Rename(p.ExtractPath(), p.Path)

	if err != nil {
		log.Fatal(err)
	}
}

func (p Project) Prepare() {
	if _, err := os.Stat(p.TemporaryPath()); os.IsNotExist(err) {
		err = os.MkdirAll(p.TemporaryPath(), 0700)

		if err != nil {
			log.Fatal(err)
		}
	}
}

func (p Project) CleanUp() {
	err := os.RemoveAll(p.TemporaryPath())

	if err != nil {
		log.Fatal(err)
	}
}

func (p Project) Deploy() {
	p.Prepare()
	p.Download()
	p.Extract()
	p.Place()
	p.CleanUp()
}

func DeployAll() {
	for _, project := range list {
		project.Deploy()
	}
}

func Process(n notifications.Notification) {
	for _, project := range list {
		if project.Repository == n.Repository {
			if project.Owner == n.Owner {
				if project.Version == n.Commit {
					project.Deploy()
				} else if project.Version == n.Branch {
					project.Deploy()
				}
			}
		}
	}
}
<commit_msg>Allowed a version type - branch or commit - to be specified<commit_after>package projects

import (
	"archive/zip"
	"bytes"
	"encoding/json"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"strings"

	log "github.com/Sirupsen/logrus"
	"github.com/citruspi/milou/configuration"
	"github.com/citruspi/milou/notifications"
)

type Project struct {
	Owner      string `json:"owner"`
	Repository string `json:"repository"`
	Version    struct {
		Type  string `json:"type"`
		Value string `json:"value"`
	} `json:"version"`
	Identifier string `json:"identifier"`
	Path       string `json:"path"`
}

var (
	conf configuration.Configuration
	list []Project
)

func init() {
	conf = configuration.Load()

	files, err := ioutil.ReadDir(conf.Projects)

	if err != nil {
		log.Fatal(err)
	}

	for _, file := range files {
		var project Project

		source, err := ioutil.ReadFile(conf.Projects + file.Name())

		if err != nil {
			log.Fatal(err)
		}

		err = json.Unmarshal(source, &project)

		if err != nil {
			log.Fatal(err)
		}

		list = append(list, project)
	}

	if conf.Mode == "standalone" || conf.Mode == "client" {
		DeployAll()
	}
}

func (p Project) ArchivePath() string {
	var buffer bytes.Buffer

	buffer.WriteString(p.TemporaryPath())
	buffer.WriteString(p.Version.Value)
	buffer.WriteString(".zip")

	return string(buffer.Bytes())
}

func (p Project) TemporaryPath() string {
	var buffer bytes.Buffer

	buffer.WriteString(p.Path[:len(p.Path)-1])
	buffer.WriteString(".milou/")

	return string(buffer.Bytes())
}

func (p Project) ExtractPath() string {
	var buffer bytes.Buffer

	buffer.WriteString(p.TemporaryPath())
	buffer.WriteString(p.Repository)

	return string(buffer.Bytes())
}

func (p Project) ArchiveLocation() string {
	var buffer bytes.Buffer

	buffer.WriteString("https://s3.amazonaws.com/")
	buffer.WriteString(p.Identifier)
	buffer.WriteString("/")
	buffer.WriteString(p.Version.Value)
	buffer.WriteString(".zip")

	return string(buffer.Bytes())
}

func (p Project) Extract() error {
	r, err := zip.OpenReader(p.ArchivePath())
	if err != nil {
		return err
	}
	defer r.Close()

	for _, f := range r.File {
		rc, err := f.Open()
		if err != nil {
			return err
		}
		defer rc.Close()

		fpath := filepath.Join(p.ExtractPath(), f.Name)
		if f.FileInfo().IsDir() {
			os.MkdirAll(fpath, f.Mode())
		} else {
			var fdir string
			if lastIndex := strings.LastIndex(fpath, string(os.PathSeparator)); lastIndex > -1 {
				fdir = fpath[:lastIndex]
			}

			err = os.MkdirAll(fdir, f.Mode())
			if err != nil {
				log.Fatal(err)
				return err
			}
			f, err := os.OpenFile(
				fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
			if err != nil {
				return err
			}
			defer f.Close()

			_, err = io.Copy(f, rc)
			if err != nil {
				return err
			}
		}
	}
	return nil
}

func (p Project) Download() {
	response, err := http.Get(p.ArchiveLocation())
	defer response.Body.Close()

	if err != nil {
		log.Fatal(err)
	}

	archive, err := os.Create(p.ArchivePath())
	defer archive.Close()

	_, err = io.Copy(archive, response.Body)

	if err != nil {
		log.Fatal(err)
	}
}

func (p Project) Place() {
	err := os.RemoveAll(p.Path)

	if err != nil {
		log.Fatal(err)
	}

	err = os.Rename(p.ExtractPath(), p.Path)

	if err != nil {
		log.Fatal(err)
	}
}

func (p Project) Prepare() {
	if _, err := os.Stat(p.TemporaryPath()); os.IsNotExist(err) {
		err = os.MkdirAll(p.TemporaryPath(), 0700)

		if err != nil {
			log.Fatal(err)
		}
	}
}

func (p Project) CleanUp() {
	err := os.RemoveAll(p.TemporaryPath())

	if err != nil {
		log.Fatal(err)
	}
}

func (p Project) Deploy() {
	p.Prepare()
	p.Download()
	p.Extract()
	p.Place()
	p.CleanUp()
}

func DeployAll() {
	for _, project := range list {
		project.Deploy()
	}
}

func Process(n notifications.Notification) {
	for _, project := range list {
		if project.Repository != n.Repository {
			continue
		}

		if project.Owner != n.Owner {
			continue
		}

		if project.Version.Type == "commit" {
			if project.Version.Value == n.Commit {
				project.Deploy()
				continue
			}
		}

		if project.Version.Type == "branch" {
			if project.Version.Value == n.Branch {
				project.Deploy()
			}
		}
	}
}
<|endoftext|>


<commit_before>package httpaccesslog

import (
	"fmt"
	"log"
	"net/http"
	"testing"
	"time"
)

type ExpectationChecker struct {
	t        *testing.T
	Expected string
}

func (this ExpectationChecker) Write(p []byte) (n int, err error) {
	actual := string(p)
	expected := fmt.Sprintf(this.Expected, time.Now().Format("02/Jan/2006:15:04:05 -0700"))
	if actual != expected {
		this.t.Errorf("\nactual\n%s\nexpected\n%s", actual, expected)
	}

	return len(p), nil
}

type BlackHole struct {
}

func (this BlackHole) Write(p []byte) (n int, err error) {
	return len(p), nil
}

func (this BlackHole) WriteHeader(int) {
}

func (this BlackHole) Header() http.Header {
	return nil
}

var usageMessage = []byte(`
supported requests:
	/render/?target=
	/metrics/find/?query=
	/info/?target=
`)

func usageHandler(w http.ResponseWriter, r *http.Request) {
	w.Write(usageMessage)
}

func deniedHandler(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(401)
}

func delayedHandler(w http.ResponseWriter, r *http.Request) {
	time.Sleep(50 * time.Millisecond)
}

func TestServeMux(t *testing.T) {
	expectationChecker := &ExpectationChecker{t, ""}
	accessLogger := AccessLogger{*log.New(expectationChecker, "", 0)}
	http.HandleFunc("/usage", accessLogger.Handle(usageHandler))
	http.HandleFunc("/denied", accessLogger.Handle(deniedHandler))
	http.HandleFunc("/delayed", accessLogger.Handle(delayedHandler))
	go http.ListenAndServe(":5000", nil)
	expectationChecker.Expected = "127.0.0.1 - user [%s] \"GET /usage HTTP/1.1\" 200 78 0.000/0.000 \"-\" \"-\" - -\n"
	http.Get("http://user:pass@localhost:5000/usage")
	expectationChecker.Expected = "127.0.0.1 - - [%s] \"GET /denied HTTP/1.1\" 401 0 0.000/0.000 \"-\" \"-\" - -\n"
	http.Get("http://localhost:5000/denied")
	expectationChecker.Expected = "127.0.0.1 - - [%s] \"GET /delayed HTTP/1.1\" 200 0 0.050/0.050 \"-\" \"-\" - -\n"
	http.Get("http://localhost:5000/delayed")
}

func TestHandle(t *testing.T) {
	expectationChecker := &ExpectationChecker{t, ""}
	accessLogger := AccessLogger{*log.New(expectationChecker, "", 0)}
	log.SetFlags(0)
	log.SetOutput(expectationChecker)
	tests := []struct {
		remoteAddr string
		username   string
		method     string
		path       string
		proto      string
		referer    string
		userAgent  string
		handler    http.HandlerFunc
		expected   string
	}{
		{
			"127.0.0.1:1234",
			"frank",
			http.MethodGet,
			"/apache_pb.gif",
			"HTTP/1.0",
			"http://www.example.com/start.html",
			"Mozilla/4.08 [en] (Win98; I ;Nav)",
			usageHandler,
			"127.0.0.1 - frank [%s] \"GET /apache_pb.gif HTTP/1.0\" 200 78 0.000/0.000 \"http://www.example.com/start.html\" \"Mozilla/4.08 [en] (Win98; I ;Nav)\" - -\n",
		},
		{
			"10.1.2.254:4567",
			"",
			http.MethodGet,
			"/",
			"HTTP/1.1",
			"",
			"Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko)",
			deniedHandler,
			"10.1.2.254 - - [%s] \"GET / HTTP/1.1\" 401 0 0.000/0.000 \"-\" \"Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko)\" - -\n",
		},
		{
			"10.1.2.254",
			"",
			http.MethodGet,
			"/somepage",
			"HTTP/1.1",
			"https://github.com/",
			"Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko)",
			delayedHandler,
			"10.1.2.254 - - [%s] \"GET /somepage HTTP/1.1\" 200 0 0.050/0.050 \"https://github.com/\" \"Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko)\" - -\n",
		},
	}

	for _, tt := range tests {
		request, err := http.NewRequest(tt.method, tt.path, nil)
		if err != nil {
			t.Error("failed to create request")
		}

		request.Proto = tt.proto
		request.RemoteAddr = tt.remoteAddr
		request.SetBasicAuth(tt.username, "")
		if tt.referer != "" {
			request.Header["Referer"] = []string{tt.referer}
		}
		if tt.userAgent != "" {
			request.Header["UserAgent"] = []string{tt.userAgent}
		}
		expectationChecker.Expected = tt.expected
		accessLogger.Handle(tt.handler)(BlackHole{}, request)
	}
}

func TestFormatAccessLog(t *testing.T) {
	mst, err := time.LoadLocation("MST")
	if err != nil {
		t.Error("Error loading timezone MST")
	}

	cet, err := time.LoadLocation("CET")
	if err != nil {
		t.Error("Error loading timezone CET")
	}

	tests := []struct {
		remoteAddr        string
		username          string
		dateTime          time.Time
		method            string
		path              string
		proto             string
		status            int
		responseBodyBytes int
		requestTime       time.Duration
		upstreamTime      time.Duration
		referer           string
		userAgent         string
		compressionRatio  float64
		expected          string
	}{
		{
			"127.0.0.1:1234",
			"frank",
			time.Date(2000, time.October, 10, 13, 55, 36, 0, mst),
			http.MethodGet,
			"/apache_pb.gif",
			"HTTP/1.0",
			http.StatusOK,
			2326,
			0,
			0,
			"http://www.example.com/start.html",
			"Mozilla/4.08 [en] (Win98; I ;Nav)",
			0,
			"127.0.0.1 - frank [10/Oct/2000:13:55:36 -0700] \"GET /apache_pb.gif HTTP/1.0\" 200 2326 0.000/0.000 \"http://www.example.com/start.html\" \"Mozilla/4.08 [en] (Win98; I ;Nav)\" - -",
		},
		{
			"10.1.2.254:4567",
			"",
			time.Date(2016, time.June, 13, 15, 19, 37, 0, cet),
			http.MethodGet,
			"/",
			"HTTP/1.1",
			http.StatusUnauthorized,
			22,
			80 * time.Millisecond,
			80 * time.Millisecond,
			"",
			"Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko)",
			0,
			"10.1.2.254 - - [13/Jun/2016:15:19:37 +0200] \"GET / HTTP/1.1\" 401 22 0.080/0.080 \"-\" \"Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko)\" - -",
		},
		{
			"10.1.2.254",
			"",
			time.Date(2016, time.June, 13, 15, 19, 37, 0, cet),
			http.MethodGet,
			"/somepage",
			"HTTP/1.1",
			http.StatusOK,
			950,
			50 * time.Millisecond,
			50 * time.Millisecond,
			"https://github.com/",
			"Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko)",
			3.02,
			"10.1.2.254 - - [13/Jun/2016:15:19:37 +0200] \"GET /somepage HTTP/1.1\" 200 950 0.050/0.050 \"https://github.com/\" \"Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko)\" 3.02 -",
		},
	}

	for _, tt := range tests {
		request, err := http.NewRequest(tt.method, tt.path, nil)
		if err != nil {
			t.Error("failed to create request")
		}

		request.Proto = tt.proto
		request.RemoteAddr = tt.remoteAddr
		request.SetBasicAuth(tt.username, "")
		if tt.referer != "" {
			request.Header["Referer"] = []string{tt.referer}
		}
		if tt.userAgent != "" {
			request.Header["UserAgent"] = []string{tt.userAgent}
		}
		actual := formatAccessLog(request, tt.dateTime, responseStats{tt.responseBodyBytes, tt.status}, tt.requestTime, tt.upstreamTime, tt.compressionRatio)
		if actual != tt.expected {
			t.Errorf("\nactual\n%s\nexpected\n%s", actual, tt.expected)
		}
	}
}
<commit_msg>add support for go1.4.2 which doesn't have http.MethodGet<commit_after>package httpaccesslog

import (
	"fmt"
	"log"
	"net/http"
	"testing"
	"time"
)

type ExpectationChecker struct {
	t        *testing.T
	Expected string
}

func (this ExpectationChecker) Write(p []byte) (n int, err error) {
	actual := string(p)
	expected := fmt.Sprintf(this.Expected, time.Now().Format("02/Jan/2006:15:04:05 -0700"))
	if actual != expected {
		this.t.Errorf("\nactual\n%s\nexpected\n%s", actual, expected)
	}

	return len(p), nil
}

type BlackHole struct {
}

func (this BlackHole) Write(p []byte) (n int, err error) {
	return len(p), nil
}

func (this BlackHole) WriteHeader(int) {
}

func (this BlackHole) Header() http.Header {
	return nil
}

var usageMessage = []byte(`
supported requests:
	/render/?target=
	/metrics/find/?query=
	/info/?target=
`)

func usageHandler(w http.ResponseWriter, r *http.Request) {
	w.Write(usageMessage)
}

func deniedHandler(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(401)
}

func delayedHandler(w http.ResponseWriter, r *http.Request) {
	time.Sleep(50 * time.Millisecond)
}

func TestServeMux(t *testing.T) {
	expectationChecker := &ExpectationChecker{t, ""}
	accessLogger := AccessLogger{*log.New(expectationChecker, "", 0)}
	http.HandleFunc("/usage", accessLogger.Handle(usageHandler))
	http.HandleFunc("/denied", accessLogger.Handle(deniedHandler))
	http.HandleFunc("/delayed", accessLogger.Handle(delayedHandler))
	go http.ListenAndServe(":5000", nil)
	expectationChecker.Expected = "127.0.0.1 - user [%s] \"GET /usage HTTP/1.1\" 200 78 0.000/0.000 \"-\" \"-\" - -\n"
	http.Get("http://user:pass@localhost:5000/usage")
	expectationChecker.Expected = "127.0.0.1 - - [%s] \"GET /denied HTTP/1.1\" 401 0 0.000/0.000 \"-\" \"-\" - -\n"
	http.Get("http://localhost:5000/denied")
	expectationChecker.Expected = "127.0.0.1 - - [%s] \"GET /delayed HTTP/1.1\" 200 0 0.050/0.050 \"-\" \"-\" - -\n"
	http.Get("http://localhost:5000/delayed")
}

func TestHandle(t *testing.T) {
	expectationChecker := &ExpectationChecker{t, ""}
	accessLogger := AccessLogger{*log.New(expectationChecker, "", 0)}
	log.SetFlags(0)
	log.SetOutput(expectationChecker)
	tests := []struct {
		remoteAddr string
		username   string
		method     string
		path       string
		proto      string
		referer    string
		userAgent  string
		handler    http.HandlerFunc
		expected   string
	}{
		{
			"127.0.0.1:1234",
			"frank",
			"GET",
			"/apache_pb.gif",
			"HTTP/1.0",
			"http://www.example.com/start.html",
			"Mozilla/4.08 [en] (Win98; I ;Nav)",
			usageHandler,
			"127.0.0.1 - frank [%s] \"GET /apache_pb.gif HTTP/1.0\" 200 78 0.000/0.000 \"http://www.example.com/start.html\" \"Mozilla/4.08 [en] (Win98; I ;Nav)\" - -\n",
		},
		{
			"10.1.2.254:4567",
			"",
			"GET",
			"/",
			"HTTP/1.1",
			"",
			"Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko)",
			deniedHandler,
			"10.1.2.254 - - [%s] \"GET / HTTP/1.1\" 401 0 0.000/0.000 \"-\" \"Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko)\" - -\n",
		},
		{
			"10.1.2.254",
			"",
			"GET",
			"/somepage",
			"HTTP/1.1",
			"https://github.com/",
			"Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko)",
			delayedHandler,
			"10.1.2.254 - - [%s] \"GET /somepage HTTP/1.1\" 200 0 0.050/0.050 \"https://github.com/\" \"Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko)\" - -\n",
		},
	}

	for _, tt := range tests {
		request, err := http.NewRequest(tt.method, tt.path, nil)
		if err != nil {
			t.Error("failed to create request")
		}

		request.Proto = tt.proto
		request.RemoteAddr = tt.remoteAddr
		request.SetBasicAuth(tt.username, "")
		if tt.referer != "" {
			request.Header["Referer"] = []string{tt.referer}
		}
		if tt.userAgent != "" {
			request.Header["UserAgent"] = []string{tt.userAgent}
		}
		expectationChecker.Expected = tt.expected
		accessLogger.Handle(tt.handler)(BlackHole{}, request)
	}
}

func TestFormatAccessLog(t *testing.T) {
	mst, err := time.LoadLocation("MST")
	if err != nil {
		t.Error("Error loading timezone MST")
	}

	cet, err := time.LoadLocation("CET")
	if err != nil {
		t.Error("Error loading timezone CET")
	}

	tests := []struct {
		remoteAddr        string
		username          string
		dateTime          time.Time
		method            string
		path              string
		proto             string
		status            int
		responseBodyBytes int
		requestTime       time.Duration
		upstreamTime      time.Duration
		referer           string
		userAgent         string
		compressionRatio  float64
		expected          string
	}{
		{
			"127.0.0.1:1234",
			"frank",
			time.Date(2000, time.October, 10, 13, 55, 36, 0, mst),
			"GET",
			"/apache_pb.gif",
			"HTTP/1.0",
			http.StatusOK,
			2326,
			0,
			0,
			"http://www.example.com/start.html",
			"Mozilla/4.08 [en] (Win98; I ;Nav)",
			0,
			"127.0.0.1 - frank [10/Oct/2000:13:55:36 -0700] \"GET /apache_pb.gif HTTP/1.0\" 200 2326 0.000/0.000 \"http://www.example.com/start.html\" \"Mozilla/4.08 [en] (Win98; I ;Nav)\" - -",
		},
		{
			"10.1.2.254:4567",
			"",
			time.Date(2016, time.June, 13, 15, 19, 37, 0, cet),
			"GET",
			"/",
			"HTTP/1.1",
			http.StatusUnauthorized,
			22,
			80 * time.Millisecond,
			80 * time.Millisecond,
			"",
			"Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko)",
			0,
			"10.1.2.254 - - [13/Jun/2016:15:19:37 +0200] \"GET / HTTP/1.1\" 401 22 0.080/0.080 \"-\" \"Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko)\" - -",
		},
		{
			"10.1.2.254",
			"",
			time.Date(2016, time.June, 13, 15, 19, 37, 0, cet),
			"GET",
			"/somepage",
			"HTTP/1.1",
			http.StatusOK,
			950,
			50 * time.Millisecond,
			50 * time.Millisecond,
			"https://github.com/",
			"Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko)",
			3.02,
			"10.1.2.254 - - [13/Jun/2016:15:19:37 +0200] \"GET /somepage HTTP/1.1\" 200 950 0.050/0.050 \"https://github.com/\" \"Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko)\" 3.02 -",
		},
	}

	for _, tt := range tests {
		request, err := http.NewRequest(tt.method, tt.path, nil)
		if err != nil {
			t.Error("failed to create request")
		}

		request.Proto = tt.proto
		request.RemoteAddr = tt.remoteAddr
		request.SetBasicAuth(tt.username, "")
		if tt.referer != "" {
			request.Header["Referer"] = []string{tt.referer}
		}
		if tt.userAgent != "" {
			request.Header["UserAgent"] = []string{tt.userAgent}
		}
		actual := formatAccessLog(request, tt.dateTime, responseStats{tt.responseBodyBytes, tt.status}, tt.requestTime, tt.upstreamTime, tt.compressionRatio)
		if actual != tt.expected {
			t.Errorf("\nactual\n%s\nexpected\n%s", actual, tt.expected)
		}
	}
}
<|endoftext|>


<commit_before>package changelog

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"os/exec"
	"path/filepath"
	"strings"
	"time"

	"github.com/pkg/errors"
)

type localQuerier struct {
	GitDir      string `toml:"git_dir"`
	GitWorkTree string `toml:"git_work_tree"`
	Format      string
}

func (l localQuerier) getWorkdir() string {
	if len(l.GitDir) > 0 {
		return filepath.Dir(l.GitDir)
	}
	if len(l.GitWorkTree) > 0 {
		return l.GitWorkTree
	}
	return "."
}

// NewLocalQuerier returns a querier that queries off of a local git repostiroy
func NewLocalQuerier(gitDir, workTree string) Querier {
	return localQuerier{
		gitDir,
		workTree,
		`%H%n%s%n%b%n==END==`,
	}
}

func (l *localQuerier) getGitWorkTree() string {
	// Check if user supplied a local git dir and working tree
	if l.GitDir != "" && l.GitWorkTree != "" {
		// user supplied both
		return fmt.Sprintf("--work-tree=%s", l.GitWorkTree)
	} else if l.GitWorkTree != "" && l.GitDir == "" {
		return fmt.Sprintf("--work-tree=%s", filepath.Dir(l.GitWorkTree))
	}
	return ""
}

func (l *localQuerier) getGitDir() string {
	if l.GitDir == "" && l.GitWorkTree == "" {
		return ""
	} else if l.GitDir != "" {
		return fmt.Sprintf("--git-dir=%s", l.GitDir)
	}
	return fmt.Sprintf("--git-dir=%s", filepath.Join(l.GitWorkTree, ".git"))
}

func (l localQuerier) gitCommandFactory(args ...string) *exec.Cmd {
	args = append([]string{l.getGitDir(), l.getGitWorkTree()}, args...)
	realArgs := []string{}
	for _, argument := range args {
		if argument != "" {
			realArgs = append(realArgs, argument)
		}
	}
	// fmt.Println(realArgs)
	return exec.Command("git", realArgs...)
}

func (l localQuerier) GetOrigin() (string, error) {
	args := []string{
		"remote",
		"get-url",
		"origin",
	}
	cmd := l.gitCommandFactory(args...)
	var out bytes.Buffer
	cmd.Stdout = &out
	err := cmd.Run()
	if err != nil {
		return "", errors.WithStack(err)
	}

	origin := strings.TrimSpace(out.String())
	if strings.HasPrefix(origin, "git@") {
		origin = fmt.Sprintf("https://%s", strings.Replace(strings.TrimSuffix(origin[4:], ".git"), ":", "/", -1))
	}
	return origin, nil
}

// GetLatestCommit returns the latest commit
func (l localQuerier) GetLatestCommit() (string, error) {
	args := []string{
		"rev-list",
		"HEAD",
	}
	cmd := l.gitCommandFactory(args...)

	var out bytes.Buffer
	cmd.Stdout = &out
	err := cmd.Run()
	if err != nil {
		return "", errors.WithStack(err)
	}
	return out.String(), nil
}

// GetLatestTag returns the latest tag
func (l localQuerier) GetLatestTag() (string, error) {
	args := []string{
		"rev-list",
		"--tags",
		"--max-count=1",
	}
	cmd := l.gitCommandFactory(args...)
	var out bytes.Buffer
	cmd.Stdout = &out
	err := cmd.Run()
	if err != nil {
		return "", errors.WithStack(err)
	}
	return out.String(), nil
}

// GetLatestTagVersion returns the latest tag version
func (l localQuerier) GetLatestTagVersion() (string, error) {
	args := []string{
		"describe",
		"--tags",
		"--abbrev=0",
	}
	cmd := l.gitCommandFactory(args...)
	var out bytes.Buffer
	cmd.Stdout = &out
	err := cmd.Run()
	if err != nil {
		return "", errors.WithStack(err)
	}
	return out.String(), nil
}

func (l localQuerier) parseRawCommit(repo, commitStr string) *Commit {
	lines := strings.Split(commitStr, "\n")
	if len(lines) < 2 {
		return nil
	}
	return NewCommit(lines[0], strings.Join(lines[1:], "\n"))

}

// GetCommits returns a slice of commits
func (l localQuerier) GetCommits(from, to string) (Commits, error) {
	repo, err := l.GetOrigin()
	if err != nil {
		return nil, err
	}

	if from != "" {
		from = fmt.Sprintf("%s..", from)
	}

	args := []string{
		"log",
		"-E",
		fmt.Sprintf(`--format=%s`, l.Format),
		fmt.Sprintf("%s%s", from, to),
	}
	cmd := l.gitCommandFactory(args...)

	var out bytes.Buffer
	cmd.Stdout = &out
	err = cmd.Run()
	if err != nil {
		return nil, errors.WithStack(err)
	}

	commitGroups := strings.Split(out.String(), "\n==END==\n")

	var commits Commits
	for _, com := range commitGroups {
		if len(com) == 0 {
			continue
		}
		commit := l.parseRawCommit(repo, com)
		if commit == nil {
			continue
		}
		commits = append(commits, *commit)

	}
	return commits, nil
}

// GetCommits returns a slice of commits
func (l localQuerier) GetCommitRange(since, until time.Time) (Commits, error) {
	repo, err := l.GetOrigin()
	if err != nil {
		return nil, err
	}

	args := []string{
		"log",
		"-E",
		fmt.Sprintf(`--format=%s`, l.Format),
		fmt.Sprintf("--since=%s", since.Format(time.RFC3339)),
		fmt.Sprintf("--until=%s", until.Format(time.RFC3339)),
	}
	cmd := l.gitCommandFactory(args...)

	var out bytes.Buffer
	cmd.Stdout = &out
	err = cmd.Run()
	if err != nil {
		return nil, errors.WithStack(err)
	}

	commitGroups := strings.Split(out.String(), "\n==END==\n")

	var commits Commits
	for _, com := range commitGroups {
		if len(com) == 0 {
			continue
		}
		commit := l.parseRawCommit(repo, com)
		if commit == nil {
			continue
		}
		commits = append(commits, *commit)

	}
	return commits, nil
}

// GetConfig returns a reader for the clog config
func (l localQuerier) GetConfig() (io.Reader, error) {
	dir := l.getWorkdir()
	content, err := ioutil.ReadFile(filepath.Join(dir, ".clog.toml"))
	if err != nil {
		return nil, err
	}
	return bytes.NewBuffer(content), nil
}
<commit_msg>fix(cmd): fix --from-latest-tag (#9)<commit_after>package changelog

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"os/exec"
	"path/filepath"
	"strings"
	"time"

	"github.com/pkg/errors"
)

type localQuerier struct {
	GitDir      string `toml:"git_dir"`
	GitWorkTree string `toml:"git_work_tree"`
	Format      string
}

func (l localQuerier) getWorkdir() string {
	if len(l.GitDir) > 0 {
		return filepath.Dir(l.GitDir)
	}
	if len(l.GitWorkTree) > 0 {
		return l.GitWorkTree
	}
	return "."
}

// NewLocalQuerier returns a querier that queries off of a local git repostiroy
func NewLocalQuerier(gitDir, workTree string) Querier {
	return localQuerier{
		gitDir,
		workTree,
		`%H%n%s%n%b%n==END==`,
	}
}

func (l *localQuerier) getGitWorkTree() string {
	// Check if user supplied a local git dir and working tree
	if l.GitDir != "" && l.GitWorkTree != "" {
		// user supplied both
		return fmt.Sprintf("--work-tree=%s", l.GitWorkTree)
	} else if l.GitWorkTree != "" && l.GitDir == "" {
		return fmt.Sprintf("--work-tree=%s", filepath.Dir(l.GitWorkTree))
	}
	return ""
}

func (l *localQuerier) getGitDir() string {
	if l.GitDir == "" && l.GitWorkTree == "" {
		return ""
	} else if l.GitDir != "" {
		return fmt.Sprintf("--git-dir=%s", l.GitDir)
	}
	return fmt.Sprintf("--git-dir=%s", filepath.Join(l.GitWorkTree, ".git"))
}

func (l localQuerier) gitCommandFactory(args ...string) *exec.Cmd {
	args = append([]string{l.getGitDir(), l.getGitWorkTree()}, args...)
	realArgs := []string{}
	for _, argument := range args {
		if argument != "" {
			realArgs = append(realArgs, argument)
		}
	}
	// fmt.Println(realArgs)
	return exec.Command("git", realArgs...)
}

func (l localQuerier) GetOrigin() (string, error) {
	args := []string{
		"remote",
		"get-url",
		"origin",
	}
	cmd := l.gitCommandFactory(args...)
	var out bytes.Buffer
	cmd.Stdout = &out
	err := cmd.Run()
	if err != nil {
		return "", errors.WithStack(err)
	}

	origin := strings.TrimSpace(out.String())
	if strings.HasPrefix(origin, "git@") {
		origin = fmt.Sprintf("https://%s", strings.Replace(strings.TrimSuffix(origin[4:], ".git"), ":", "/", -1))
	}
	return origin, nil
}

// GetLatestCommit returns the latest commit
func (l localQuerier) GetLatestCommit() (string, error) {
	args := []string{
		"rev-list",
		"HEAD",
	}
	cmd := l.gitCommandFactory(args...)

	var out bytes.Buffer
	cmd.Stdout = &out
	err := cmd.Run()
	if err != nil {
		return "", errors.WithStack(err)
	}
	return out.String(), nil
}

// GetLatestTag returns the latest tag
func (l localQuerier) GetLatestTag() (string, error) {
	args := []string{
		"rev-list",
		"--tags",
		"--max-count=1",
	}
	cmd := l.gitCommandFactory(args...)
	var out bytes.Buffer
	cmd.Stdout = &out
	err := cmd.Run()
	if err != nil {
		return "", errors.WithStack(err)
	}
	return strings.TrimSpace(out.String()), nil
}

// GetLatestTagVersion returns the latest tag version
func (l localQuerier) GetLatestTagVersion() (string, error) {
	args := []string{
		"describe",
		"--tags",
		"--abbrev=0",
	}
	cmd := l.gitCommandFactory(args...)
	var out bytes.Buffer
	cmd.Stdout = &out
	err := cmd.Run()
	if err != nil {
		return "", errors.WithStack(err)
	}
	return out.String(), nil
}

func (l localQuerier) parseRawCommit(repo, commitStr string) *Commit {
	lines := strings.Split(commitStr, "\n")
	if len(lines) < 2 {
		return nil
	}
	return NewCommit(lines[0], strings.Join(lines[1:], "\n"))

}

// GetCommits returns a slice of commits
func (l localQuerier) GetCommits(from, to string) (Commits, error) {
	repo, err := l.GetOrigin()
	if err != nil {
		return nil, err
	}

	if from != "" {
		from = fmt.Sprintf("%s..", from)
	}

	args := []string{
		"log",
		"-E",
		fmt.Sprintf(`--format=%s`, l.Format),
		fmt.Sprintf("%s%s", from, to),
	}
	cmd := l.gitCommandFactory(args...)

	var out bytes.Buffer
	cmd.Stdout = &out
	err = cmd.Run()
	if err != nil {
		return nil, errors.WithStack(err)
	}

	commitGroups := strings.Split(out.String(), "\n==END==\n")

	var commits Commits
	for _, com := range commitGroups {
		if len(com) == 0 {
			continue
		}
		commit := l.parseRawCommit(repo, com)
		if commit == nil {
			continue
		}
		commits = append(commits, *commit)

	}
	return commits, nil
}

// GetCommits returns a slice of commits
func (l localQuerier) GetCommitRange(since, until time.Time) (Commits, error) {
	repo, err := l.GetOrigin()
	if err != nil {
		return nil, err
	}

	args := []string{
		"log",
		"-E",
		fmt.Sprintf(`--format=%s`, l.Format),
		fmt.Sprintf("--since=%s", since.Format(time.RFC3339)),
		fmt.Sprintf("--until=%s", until.Format(time.RFC3339)),
	}
	cmd := l.gitCommandFactory(args...)

	var out bytes.Buffer
	cmd.Stdout = &out
	err = cmd.Run()
	if err != nil {
		return nil, errors.WithStack(err)
	}

	commitGroups := strings.Split(out.String(), "\n==END==\n")

	var commits Commits
	for _, com := range commitGroups {
		if len(com) == 0 {
			continue
		}
		commit := l.parseRawCommit(repo, com)
		if commit == nil {
			continue
		}
		commits = append(commits, *commit)

	}
	return commits, nil
}

// GetConfig returns a reader for the clog config
func (l localQuerier) GetConfig() (io.Reader, error) {
	dir := l.getWorkdir()
	content, err := ioutil.ReadFile(filepath.Join(dir, ".clog.toml"))
	if err != nil {
		return nil, err
	}
	return bytes.NewBuffer(content), nil
}
<|endoftext|>