<commit_before>// +build linux
//
// Use and distribution licensed under the Apache license version 2.
//
// See the COPYING file in the root project directory for full text.
//

package main

import (
	"archive/tar"
	"compress/gzip"
	"crypto/md5"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"
	"strings"

	"github.com/spf13/cobra"
)

var (
	// version of application at compile time (-X 'main.version=$(VERSION)').
	version = "(Unknown Version)"
	// buildHash GIT hash of application at compile time (-X 'main.buildHash=$(GITCOMMIT)').
	buildHash = "No Git-hash Provided."
	// buildDate of application at compile time (-X 'main.buildDate=$(BUILDDATE)').
	buildDate = "No Build Date Provided."
	// show debug output
	debug = false
	// output filepath to save snapshot to
	outPath string
)

var (
	createPseudofilePaths = []string{
		"/proc/cpuinfo",
		"/proc/meminfo",
	}
)

// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
	Use:   "ghw-snapshot",
	Short: "ghw-snapshot - Snapshot filesystem containing system information.",
	RunE:  execute,
}

func trace(msg string, args ...interface{}) {
	if !debug {
		return
	}
	fmt.Printf(msg, args...)
}

func systemFingerprint() string {
	hn, err := os.Hostname()
	if err != nil {
		return "unknown"
	}
	m := md5.New()
	io.WriteString(m, hn)
	return fmt.Sprintf("%x", m.Sum(nil))
}

func defaultOutPath() string {
	fp := systemFingerprint()
	return fmt.Sprintf("%s-%s-%s.tar.gz", runtime.GOOS, runtime.GOARCH, fp)
}

func execute(cmd *cobra.Command, args []string) error {
	scratchDir, err := ioutil.TempDir("", "ghw-snapshot")
	if err != nil {
		return err
	}
	defer os.RemoveAll(scratchDir)

	var createPaths = []string{
		"proc",
		"sys/block",
	}

	for _, path := range createPaths {
		if err = os.MkdirAll(filepath.Join(scratchDir, path), os.ModePerm); err != nil {
			return err
		}
	}

	if err = createPseudofiles(scratchDir); err != nil {
		return err
	}
	if err = createBlockDevices(scratchDir); err != nil {
		return err
	}
	return doSnapshot(scratchDir)
}

// Attempting to tar up pseudofiles like /proc/cpuinfo is an exercise in
// futility. Notably, the pseudofiles, when read by syscalls, do not return the
// number of bytes read. This causes the tar writer to write zero-length files.
//
// Instead, it is necessary to build a directory structure in a tmpdir and
// create actual files with copies of the pseudofile contents
func createPseudofiles(buildDir string) error {
	for _, path := range createPseudofilePaths {
		buf, err := ioutil.ReadFile(path)
		if err != nil {
			return err
		}
		targetPath := filepath.Join(buildDir, path)
		f, err := os.Create(targetPath)
		if err != nil {
			return err
		}
		if _, err = f.Write(buf); err != nil {
			return err
		}
		f.Close()
	}
	return nil
}

func createBlockDevices(buildDir string) error {
	// Grab all the block device pseudo-directories from /sys/block symlinks
	// (excluding loopback devices) and inject them into our build filesystem
	// with all but the circular symlink'd subsystem directories
	devLinks, err := ioutil.ReadDir("/sys/block")
	if err != nil {
		return err
	}
	for _, devLink := range devLinks {
		dname := devLink.Name()
		if strings.HasPrefix(dname, "loop") {
			continue
		}
		devPath := filepath.Join("/sys/block", dname)
		fi, err := os.Lstat(devPath)
		if err != nil {
			return err
		}
		var link string
		if fi.Mode()&os.ModeSymlink != 0 {
			link, err = os.Readlink(devPath)
			if err != nil {
				return err
			}
		}
		// Create a symlink in our build filesystem that is a directory
		// pointing to the actual device bus path where the block device's
		// information directory resides
		linkPath := filepath.Join(buildDir, "sys/block", dname)
		linkTargetPath := filepath.Join(
			buildDir,
			"sys/block",
			strings.TrimPrefix(link, string(os.PathSeparator)),
		)
		trace("creating device directory %s\n", linkTargetPath)
		if err = os.MkdirAll(linkTargetPath, os.ModePerm); err != nil {
			return err
		}
		trace("linking device directory %s to %s\n", linkPath, linkTargetPath)
		if err = os.Symlink(linkTargetPath, linkPath); err != nil {
			return err
		}
		// Now read the source block device directory and populate the
		// newly-created target link in the build directory with the
		// appropriate block device pseudofiles
		srcDeviceDir := filepath.Join(
			"/sys/block",
			strings.TrimPrefix(link, string(os.PathSeparator)),
		)
		if err = createBlockDeviceDir(linkTargetPath, srcDeviceDir); err != nil {
			return err
		}
	}
	return nil
}

func createBlockDeviceDir(buildDeviceDir string, srcDeviceDir string) error {
	// Populate the supplied directory (in our build filesystem) with all the
	// appropriate information pseudofile contents for the block device.
	devName := filepath.Base(srcDeviceDir)
	devFiles, err := ioutil.ReadDir(srcDeviceDir)
	if err != nil {
		return err
	}
	for _, f := range devFiles {
		fname := f.Name()
		fp := filepath.Join(srcDeviceDir, fname)
		fi, err := os.Lstat(fp)
		if err != nil {
			return err
		}
		// Ignore any symlinks in the deviceDir since they simply point to either
		// self-referential links or information we aren't interested in like
		// "subsystem"
		if fi.Mode()&os.ModeSymlink != 0 {
			continue
		}
		if fi.IsDir() {
			// The only directories we're interested in are the directories
			// that begin with the block device name. These are directories
			// with information about the partitions on the device
			if !strings.HasPrefix(fname, devName) {
				buildPartitionDir := filepath.Join(
					buildDeviceDir, fname,
				)
				srcPartitionDir := filepath.Join(
					srcDeviceDir, fname,
				)
				err = createPartitionDir(buildPartitionDir, srcPartitionDir)
				if err != nil {
					return err
				}
			}
		} else if fi.Mode().IsRegular() {
			// Regular files in the block device directory are both regular and
			// pseudofiles containing information such as the size (in sectors)
			// and whether the device is read-only
			buf, err := ioutil.ReadFile(fp)
			if err != nil {
				return err
			}
			targetPath := filepath.Join(buildDeviceDir, fname)
			f, err := os.Create(targetPath)
			if err != nil {
				return err
			}
			if _, err = f.Write(buf); err != nil {
				return err
			}
			f.Close()
		}
	}
	return nil
}

func createPartitionDir(buildPartitionDir string, srcPartitionDir string) error {
	return nil
}

func doSnapshot(buildDir string) error {
	if outPath == "" {
		outPath = defaultOutPath()
		trace("using default output filepath %s\n", outPath)
	}

	var f *os.File
	var err error

	if _, err = os.Stat(outPath); os.IsNotExist(err) {
		if f, err = os.Create(outPath); err != nil {
			return err
		}
	} else if err != nil {
		return err
	} else {
		f, err := os.OpenFile(outPath, os.O_WRONLY, 0600)
		if err != nil {
			return err
		}
		fs, err := f.Stat()
		if err != nil {
			return err
		}
		if fs.Size() > 0 {
			return fmt.Errorf("File %s already exists and is of size >0", outPath)
		}
	}
	defer f.Close()

	gzw := gzip.NewWriter(f)
	defer gzw.Close()

	tw := tar.NewWriter(gzw)
	defer tw.Close()

	return createSnapshot(tw, buildDir)
}

func main() {
	rootCmd.Execute()
}

func init() {
	rootCmd.PersistentFlags().StringVarP(
		&outPath,
		"out", "o",
		outPath,
		"Path to place snapshot. Defaults to file in current directory with name $OS-$ARCH-$HASHSYSTEMNAME.tar.gz",
	)
	rootCmd.PersistentFlags().BoolVarP(
		&debug, "debug", "d", false, "Enable or disable debug mode",
	)
}

func createSnapshot(tw *tar.Writer, buildDir string) error {
	return filepath.Walk(buildDir, func(path string, fi os.FileInfo, err error) error {
		if path == buildDir {
			return nil
		}
		var link string

		if fi.Mode()&os.ModeSymlink != 0 {
			trace("processing symlink %s\n", path)
			link, err = os.Readlink(path)
			if err != nil {
				return err
			}
		}

		hdr, err := tar.FileInfoHeader(fi, link)
		if err != nil {
			return err
		}
		hdr.Name = strings.TrimPrefix(strings.TrimPrefix(path, buildDir), string(os.PathSeparator))

		if err = tw.WriteHeader(hdr); err != nil {
			return err
		}

		switch hdr.Typeflag {
		case tar.TypeReg, tar.TypeRegA:
			f, err := os.Open(path)
			if err != nil {
				return err
			}
			if _, err = io.Copy(tw, f); err != nil {
				return err
			}
			f.Close()
		}
		return nil
	})
}
<commit_msg>Add mtab to list of snapshot pseudofiles<commit_after>// +build linux
//
// Use and distribution licensed under the Apache license version 2.
//
// See the COPYING file in the root project directory for full text.
//

package main

import (
	"archive/tar"
	"compress/gzip"
	"crypto/md5"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"
	"strings"

	"github.com/spf13/cobra"
)

var (
	// version of application at compile time (-X 'main.version=$(VERSION)').
	version = "(Unknown Version)"
	// buildHash GIT hash of application at compile time (-X 'main.buildHash=$(GITCOMMIT)').
	buildHash = "No Git-hash Provided."
	// buildDate of application at compile time (-X 'main.buildDate=$(BUILDDATE)').
	buildDate = "No Build Date Provided."
	// show debug output
	debug = false
	// output filepath to save snapshot to
	outPath string
)

var (
	createPseudofilePaths = []string{
		"/proc/cpuinfo",
		"/proc/meminfo",
		"/etc/mtab",
	}
)

// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
	Use:   "ghw-snapshot",
	Short: "ghw-snapshot - Snapshot filesystem containing system information.",
	RunE:  execute,
}

func trace(msg string, args ...interface{}) {
	if !debug {
		return
	}
	fmt.Printf(msg, args...)
}

func systemFingerprint() string {
	hn, err := os.Hostname()
	if err != nil {
		return "unknown"
	}
	m := md5.New()
	io.WriteString(m, hn)
	return fmt.Sprintf("%x", m.Sum(nil))
}

func defaultOutPath() string {
	fp := systemFingerprint()
	return fmt.Sprintf("%s-%s-%s.tar.gz", runtime.GOOS, runtime.GOARCH, fp)
}

func execute(cmd *cobra.Command, args []string) error {
	scratchDir, err := ioutil.TempDir("", "ghw-snapshot")
	if err != nil {
		return err
	}
	defer os.RemoveAll(scratchDir)

	var createPaths = []string{
		"proc",
		"etc",
		"sys/block",
	}

	for _, path := range createPaths {
		if err = os.MkdirAll(filepath.Join(scratchDir, path), os.ModePerm); err != nil {
			return err
		}
	}

	if err = createPseudofiles(scratchDir); err != nil {
		return err
	}
	if err = createBlockDevices(scratchDir); err != nil {
		return err
	}
	return doSnapshot(scratchDir)
}

// Attempting to tar up pseudofiles like /proc/cpuinfo is an exercise in
// futility. Notably, the pseudofiles, when read by syscalls, do not return the
// number of bytes read. This causes the tar writer to write zero-length files.
//
// Instead, it is necessary to build a directory structure in a tmpdir and
// create actual files with copies of the pseudofile contents
func createPseudofiles(buildDir string) error {
	for _, path := range createPseudofilePaths {
		buf, err := ioutil.ReadFile(path)
		if err != nil {
			return err
		}
		targetPath := filepath.Join(buildDir, path)
		f, err := os.Create(targetPath)
		if err != nil {
			return err
		}
		if _, err = f.Write(buf); err != nil {
			return err
		}
		f.Close()
	}
	return nil
}

func createBlockDevices(buildDir string) error {
	// Grab all the block device pseudo-directories from /sys/block symlinks
	// (excluding loopback devices) and inject them into our build filesystem
	// with all but the circular symlink'd subsystem directories
	devLinks, err := ioutil.ReadDir("/sys/block")
	if err != nil {
		return err
	}
	for _, devLink := range devLinks {
		dname := devLink.Name()
		if strings.HasPrefix(dname, "loop") {
			continue
		}
		devPath := filepath.Join("/sys/block", dname)
		fi, err := os.Lstat(devPath)
		if err != nil {
			return err
		}
		var link string
		if fi.Mode()&os.ModeSymlink != 0 {
			link, err = os.Readlink(devPath)
			if err != nil {
				return err
			}
		}
		// Create a symlink in our build filesystem that is a directory
		// pointing to the actual device bus path where the block device's
		// information directory resides
		linkPath := filepath.Join(buildDir, "sys/block", dname)
		linkTargetPath := filepath.Join(
			buildDir,
			"sys/block",
			strings.TrimPrefix(link, string(os.PathSeparator)),
		)
		trace("creating device directory %s\n", linkTargetPath)
		if err = os.MkdirAll(linkTargetPath, os.ModePerm); err != nil {
			return err
		}
		trace("linking device directory %s to %s\n", linkPath, linkTargetPath)
		if err = os.Symlink(linkTargetPath, linkPath); err != nil {
			return err
		}
		// Now read the source block device directory and populate the
		// newly-created target link in the build directory with the
		// appropriate block device pseudofiles
		srcDeviceDir := filepath.Join(
			"/sys/block",
			strings.TrimPrefix(link, string(os.PathSeparator)),
		)
		if err = createBlockDeviceDir(linkTargetPath, srcDeviceDir); err != nil {
			return err
		}
	}
	return nil
}

func createBlockDeviceDir(buildDeviceDir string, srcDeviceDir string) error {
	// Populate the supplied directory (in our build filesystem) with all the
	// appropriate information pseudofile contents for the block device.
	devName := filepath.Base(srcDeviceDir)
	devFiles, err := ioutil.ReadDir(srcDeviceDir)
	if err != nil {
		return err
	}
	for _, f := range devFiles {
		fname := f.Name()
		fp := filepath.Join(srcDeviceDir, fname)
		fi, err := os.Lstat(fp)
		if err != nil {
			return err
		}
		// Ignore any symlinks in the deviceDir since they simply point to either
		// self-referential links or information we aren't interested in like
		// "subsystem"
		if fi.Mode()&os.ModeSymlink != 0 {
			continue
		}
		if fi.IsDir() {
			// The only directories we're interested in are the directories
			// that begin with the block device name. These are directories
			// with information about the partitions on the device
			if !strings.HasPrefix(fname, devName) {
				buildPartitionDir := filepath.Join(
					buildDeviceDir, fname,
				)
				srcPartitionDir := filepath.Join(
					srcDeviceDir, fname,
				)
				err = createPartitionDir(buildPartitionDir, srcPartitionDir)
				if err != nil {
					return err
				}
			}
		} else if fi.Mode().IsRegular() {
			// Regular files in the block device directory are both regular and
			// pseudofiles containing information such as the size (in sectors)
			// and whether the device is read-only
			buf, err := ioutil.ReadFile(fp)
			if err != nil {
				return err
			}
			targetPath := filepath.Join(buildDeviceDir, fname)
			f, err := os.Create(targetPath)
			if err != nil {
				return err
			}
			if _, err = f.Write(buf); err != nil {
				return err
			}
			f.Close()
		}
	}
	return nil
}

func createPartitionDir(buildPartitionDir string, srcPartitionDir string) error {
	return nil
}

func doSnapshot(buildDir string) error {
	if outPath == "" {
		outPath = defaultOutPath()
		trace("using default output filepath %s\n", outPath)
	}

	var f *os.File
	var err error

	if _, err = os.Stat(outPath); os.IsNotExist(err) {
		if f, err = os.Create(outPath); err != nil {
			return err
		}
	} else if err != nil {
		return err
	} else {
		f, err := os.OpenFile(outPath, os.O_WRONLY, 0600)
		if err != nil {
			return err
		}
		fs, err := f.Stat()
		if err != nil {
			return err
		}
		if fs.Size() > 0 {
			return fmt.Errorf("File %s already exists and is of size >0", outPath)
		}
	}
	defer f.Close()

	gzw := gzip.NewWriter(f)
	defer gzw.Close()

	tw := tar.NewWriter(gzw)
	defer tw.Close()

	return createSnapshot(tw, buildDir)
}

func main() {
	rootCmd.Execute()
}

func init() {
	rootCmd.PersistentFlags().StringVarP(
		&outPath,
		"out", "o",
		outPath,
		"Path to place snapshot. Defaults to file in current directory with name $OS-$ARCH-$HASHSYSTEMNAME.tar.gz",
	)
	rootCmd.PersistentFlags().BoolVarP(
		&debug, "debug", "d", false, "Enable or disable debug mode",
	)
}

func createSnapshot(tw *tar.Writer, buildDir string) error {
	return filepath.Walk(buildDir, func(path string, fi os.FileInfo, err error) error {
		if path == buildDir {
			return nil
		}
		var link string

		if fi.Mode()&os.ModeSymlink != 0 {
			trace("processing symlink %s\n", path)
			link, err = os.Readlink(path)
			if err != nil {
				return err
			}
		}

		hdr, err := tar.FileInfoHeader(fi, link)
		if err != nil {
			return err
		}
		hdr.Name = strings.TrimPrefix(strings.TrimPrefix(path, buildDir), string(os.PathSeparator))

		if err = tw.WriteHeader(hdr); err != nil {
			return err
		}

		switch hdr.Typeflag {
		case tar.TypeReg, tar.TypeRegA:
			f, err := os.Open(path)
			if err != nil {
				return err
			}
			if _, err = io.Copy(tw, f); err != nil {
				return err
			}
			f.Close()
		}
		return nil
	})
}
<|endoftext|>


<commit_before>package main

import (
	"archive/tar"
	"archive/zip"
	"compress/gzip"
	"database/sql"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"runtime"
	"strings"
	"time"

	_ "github.com/lib/pq"
	"github.com/pkg/errors"
	"github.com/urfave/cli"
)

const (
	caddyfile = `
0.0.0.0:3000 {
    proxy / localhost:3010
    proxy /api localhost:3020 {
        without /api
    }
}
`
)

func devSetupAction(c *cli.Context) error {
	log.Println("Create ./dev/")
	if err := os.MkdirAll("./dev", 0755); err != nil {
		return errors.Wrap(err, "failed to create ./dev/ for development")
	}

	log.Println("Creating docker container: gitpods-cockroach")
	if err := setupCockroach(); err != nil {
		return err
	}

	log.Println("Running pub get...")
	if err := setupPub(); err != nil {
		return err
	}

	if err := setupCaddy(); err != nil {
		return err
	}

	return nil
}

func setupCockroach() error {
	docker, err := exec.LookPath("docker")
	if err != nil {
		return err
	}

	args := []string{
		"ps",
		"--filter", "name=gitpods-cockroach",
	}

	cmd := exec.Command(docker, args...)
	output, err := cmd.Output()
	if err != nil {
		return err
	}

	// If more than 2 lines, container exists
	lines := strings.Split(string(output), "\n")
	if len(lines) > 2 {
		return nil
	}

	args = []string{
		"run", "-d",
		"--name", "gitpods-cockroach",
		"--publish", "8080:8080",
		"--publish", "26257:26257",
		"--restart", "always",
		"cockroachdb/cockroach:v2.1.3",
		"start", "--insecure",
	}

	cmd = exec.Command(docker, args...)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	if err = cmd.Run(); err != nil {
		return err
	}

	log.Println("waiting for cockroach to start")

	db, err := sql.Open("postgres", "postgresql://root@localhost:26257?sslmode=disable")
	if err != nil {
		return err
	}
	defer db.Close()

	time.Sleep(15 * time.Second)

	if err = db.Ping(); err != nil {
		return err
	}

	log.Println("creating gitpods database if not exists")
	_, err = db.Exec("CREATE DATABASE IF NOT EXISTS gitpods;")
	if err != nil {
		return err
	}

	return nil
}

func setupPub() error {
	pub, err := exec.LookPath("pub")
	if err != nil {
		return err
	}

	cmd := exec.Command(pub, "get")
	cmd.Dir = "ui"
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	return cmd.Run()
}

func setupCaddy() error {
	url := fmt.Sprintf("https://caddyserver.com/download/%s/%s", runtime.GOOS, runtime.GOARCH)
	archive := ""

	switch runtime.GOOS {
	case "darwin":
		archive = "./dev/caddy.zip"
	default:
		archive = "./dev/caddy.tar.gz"
	}

	log.Printf("Download %s\n", url)
	if err := downloadCaddy(url, archive); err != nil {
		return errors.Wrap(err, "failed to download caddy")
	}
	log.Println("Downloaded ./dev/caddy.zip")

	if err := extractCaddy(archive); err != nil {
		return errors.Wrap(err, "failed to extract caddy")
	}
	log.Println("Extracted ./dev/caddy.zip to ./dev/caddy")

	// Create Caddyfile with contents if it not exist
	if err := createCaddyfile(); err != nil {
		return errors.Wrap(err, "failed to create ./dev/Caddyfile")
	}
	log.Println("Created ./dev/Caddyfile")

	return nil
}

func downloadCaddy(url, archive string) error {

	// Download & extract Caddy to ./dev/caddy if it not exist

	exist, err := exists("./dev/caddy")
	if err != nil {
		return err
	}
	if exist { // if it exist, don't do more
		return nil
	}

	exist, err = exists(archive)
	if err != nil {
		return err
	}
	if exist { // if it exist, don't do more
		return nil
	}

	out, err := os.Create(archive)
	if err != nil {
		return err
	}
	defer out.Close()

	log.Println("Downloading", url)
	resp, err := http.Get(url)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	_, err = io.Copy(out, resp.Body)
	if err != nil {
		return err
	}

	return nil
}

func extractCaddy(archive string) error {
	switch runtime.GOOS {
	case "darwin":
		r, err := zip.OpenReader(archive)
		if err != nil {
			return err
		}

		var zippedCaddy *zip.File
		for _, file := range r.File {
			if file.Name == "caddy" {
				zippedCaddy = file
			}
		}

		fileReader, err := zippedCaddy.Open()
		if err != nil {
			return err
		}
		defer fileReader.Close()

		targetFile, err := os.OpenFile("./dev/caddy", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, zippedCaddy.Mode())
		if err != nil {
			return err
		}
		defer targetFile.Close()

		if _, err := io.Copy(targetFile, fileReader); err != nil {
			return err
		}
	default:
		archiveFile, err := os.Open(archive)
		if err != nil {
			return err
		}
		defer archiveFile.Close()

		gzipREader, err := gzip.NewReader(archiveFile)
		if err != nil {
			return err
		}

		tarReader := tar.NewReader(gzipREader)
		for {
			header, err := tarReader.Next()

			if err == io.EOF {
				break
			}

			if err != nil {
				return err
			}

			if header.Name == "caddy" && header.Typeflag == tar.TypeReg {
				f, err := os.Create("./dev/caddy")
				if err != nil {
					return err
				}
				defer f.Close()

				if err := f.Chmod(0744); err != nil {
					return err
				}

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

func createCaddyfile() error {
	exist, err := exists("./dev/Caddyfile")
	if err != nil {
		return err
	}
	if !exist {
		if err := ioutil.WriteFile("./dev/Caddyfile", []byte(strings.TrimSpace(caddyfile)), 0644); err != nil {
			return err
		}
	}

	return nil
}

func exists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return true, err
}
<commit_msg>Update URL to download Caddy<commit_after>package main

import (
	"archive/tar"
	"archive/zip"
	"compress/gzip"
	"database/sql"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"runtime"
	"strings"
	"time"

	_ "github.com/lib/pq"
	"github.com/pkg/errors"
	"github.com/urfave/cli"
)

const (
	caddyfile = `
0.0.0.0:3000 {
    proxy / localhost:3010
    proxy /api localhost:3020 {
        without /api
    }
}
`
)

func devSetupAction(c *cli.Context) error {
	log.Println("Create ./dev/")
	if err := os.MkdirAll("./dev", 0755); err != nil {
		return errors.Wrap(err, "failed to create ./dev/ for development")
	}

	log.Println("Creating docker container: gitpods-cockroach")
	if err := setupCockroach(); err != nil {
		return err
	}

	log.Println("Running pub get...")
	if err := setupPub(); err != nil {
		return err
	}

	if err := setupCaddy(); err != nil {
		return err
	}

	return nil
}

func setupCockroach() error {
	docker, err := exec.LookPath("docker")
	if err != nil {
		return err
	}

	args := []string{
		"ps",
		"--filter", "name=gitpods-cockroach",
	}

	cmd := exec.Command(docker, args...)
	output, err := cmd.Output()
	if err != nil {
		return err
	}

	// If more than 2 lines, container exists
	lines := strings.Split(string(output), "\n")
	if len(lines) > 2 {
		return nil
	}

	args = []string{
		"run", "-d",
		"--name", "gitpods-cockroach",
		"--publish", "8080:8080",
		"--publish", "26257:26257",
		"--restart", "always",
		"cockroachdb/cockroach:v2.1.3",
		"start", "--insecure",
	}

	cmd = exec.Command(docker, args...)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	if err = cmd.Run(); err != nil {
		return err
	}

	log.Println("waiting for cockroach to start")

	db, err := sql.Open("postgres", "postgresql://root@localhost:26257?sslmode=disable")
	if err != nil {
		return err
	}
	defer db.Close()

	time.Sleep(15 * time.Second)

	if err = db.Ping(); err != nil {
		return err
	}

	log.Println("creating gitpods database if not exists")
	_, err = db.Exec("CREATE DATABASE IF NOT EXISTS gitpods;")
	if err != nil {
		return err
	}

	return nil
}

func setupPub() error {
	pub, err := exec.LookPath("pub")
	if err != nil {
		return err
	}

	cmd := exec.Command(pub, "get")
	cmd.Dir = "ui"
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	return cmd.Run()
}

func setupCaddy() error {
	url := fmt.Sprintf("https://caddyserver.com/download/%s/%s?license=personal&telemetry=off", runtime.GOOS, runtime.GOARCH)
	archive := ""

	switch runtime.GOOS {
	case "darwin":
		archive = "./dev/caddy.zip"
	default:
		archive = "./dev/caddy.tar.gz"
	}

	log.Printf("Download %s\n", url)
	if err := downloadCaddy(url, archive); err != nil {
		return errors.Wrap(err, "failed to download caddy")
	}
	log.Println("Downloaded ./dev/caddy.zip")

	if err := extractCaddy(archive); err != nil {
		return errors.Wrap(err, "failed to extract caddy")
	}
	log.Println("Extracted ./dev/caddy.zip to ./dev/caddy")

	// Create Caddyfile with contents if it not exist
	if err := createCaddyfile(); err != nil {
		return errors.Wrap(err, "failed to create ./dev/Caddyfile")
	}
	log.Println("Created ./dev/Caddyfile")

	return nil
}

func downloadCaddy(url, archive string) error {

	// Download & extract Caddy to ./dev/caddy if it not exist

	exist, err := exists("./dev/caddy")
	if err != nil {
		return err
	}
	if exist { // if it exist, don't do more
		return nil
	}

	exist, err = exists(archive)
	if err != nil {
		return err
	}
	if exist { // if it exist, don't do more
		return nil
	}

	out, err := os.Create(archive)
	if err != nil {
		return err
	}
	defer out.Close()

	log.Println("Downloading", url)
	resp, err := http.Get(url)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	_, err = io.Copy(out, resp.Body)
	if err != nil {
		return err
	}

	return nil
}

func extractCaddy(archive string) error {
	switch runtime.GOOS {
	case "darwin":
		r, err := zip.OpenReader(archive)
		if err != nil {
			return err
		}

		var zippedCaddy *zip.File
		for _, file := range r.File {
			if file.Name == "caddy" {
				zippedCaddy = file
			}
		}

		fileReader, err := zippedCaddy.Open()
		if err != nil {
			return err
		}
		defer fileReader.Close()

		targetFile, err := os.OpenFile("./dev/caddy", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, zippedCaddy.Mode())
		if err != nil {
			return err
		}
		defer targetFile.Close()

		if _, err := io.Copy(targetFile, fileReader); err != nil {
			return err
		}
	default:
		archiveFile, err := os.Open(archive)
		if err != nil {
			return err
		}
		defer archiveFile.Close()

		gzipREader, err := gzip.NewReader(archiveFile)
		if err != nil {
			return err
		}

		tarReader := tar.NewReader(gzipREader)
		for {
			header, err := tarReader.Next()

			if err == io.EOF {
				break
			}

			if err != nil {
				return err
			}

			if header.Name == "caddy" && header.Typeflag == tar.TypeReg {
				f, err := os.Create("./dev/caddy")
				if err != nil {
					return err
				}
				defer f.Close()

				if err := f.Chmod(0744); err != nil {
					return err
				}

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

func createCaddyfile() error {
	exist, err := exists("./dev/Caddyfile")
	if err != nil {
		return err
	}
	if !exist {
		if err := ioutil.WriteFile("./dev/Caddyfile", []byte(strings.TrimSpace(caddyfile)), 0644); err != nil {
			return err
		}
	}

	return nil
}

func exists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return true, err
}
<|endoftext|>


<commit_before>package jwtauthd

import (
    "github.com/spf13/cobra"
    "github.com/spf13/pflag"
    "github.com/spf13/viper"
    "github.com/BluePecker/JwtAuth/daemon"
)

type Args struct {
    PidFile string
    LogFile string
    Port    int
    Driver  string
    Conf    string
    Daemon  bool
}

type JwtAuthCommand struct {
    Args  Args
    Cmd   *cobra.Command
    Viper *viper.Viper
}

var JwtAuth *JwtAuthCommand = &JwtAuthCommand{}

func UsageTemplate() string {
    return `Usage:{{if .Runnable}}
  {{if .HasAvailableFlags}}{{appendIfNotPresent .UseLine "[OPTIONS] COMMAND [arg...]"}}{{else}}{{.UseLine}}{{end}}{{end}}{{if .HasAvailableSubCommands}}
  {{ .CommandPath}} [command]{{end}}{{if gt .Aliases 0}}
Aliases:
  {{.NameAndAliases}}
{{end}}{{if .HasExample}}
Examples:
{{ .Example }}{{end}}{{ if .HasAvailableSubCommands}}
Commands:{{range .Commands}}{{if .IsAvailableCommand}}
  {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{ if .HasAvailableLocalFlags}}
Options:
{{.LocalFlags.FlagUsages | trimRightSpace}}{{end}}{{ if .HasAvailableInheritedFlags}}
Global Flags:
{{.InheritedFlags.FlagUsages | trimRightSpace}}{{end}}{{if .HasHelpSubCommands}}
Additional help topics:{{range .Commands}}{{if .IsHelpCommand}}
  {{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{ if .HasAvailableSubCommands }}
Use "{{.CommandPath}} [command] --help" for more information about a command.{{end}}
`
}

func init() {
    JwtAuth.Viper = viper.GetViper()

    JwtAuth.Cmd = &cobra.Command{
        Use: "jwt-auth",
        Short: "Jwt auth server",
        Long: "User login information verification service",
        SilenceErrors: true,
        RunE: func(cmd *cobra.Command, args []string) error {
            JwtAuth.Viper.SetConfigFile(JwtAuth.Args.Conf)
            if err := JwtAuth.Viper.ReadInConfig(); err != nil {
                return err
            }
            JwtAuth.Args.Port = JwtAuth.Viper.GetInt("port")
            JwtAuth.Args.PidFile = JwtAuth.Viper.GetString("pidfile")
            JwtAuth.Args.LogFile = JwtAuth.Viper.GetString("logfile")
            JwtAuth.Args.Daemon = JwtAuth.Viper.GetBool("daemon")
            JwtAuth.Args.Driver = JwtAuth.Viper.GetString("driver")

            // 开启SERVER服务
            (&daemon.Daemon{}).Start(JwtAuth.Args)

            return nil
        },
    }
    JwtAuth.Cmd.SetUsageTemplate(UsageTemplate())

    var PFlags *pflag.FlagSet = JwtAuth.Cmd.Flags()

    PFlags.IntVarP(&JwtAuth.Args.Port, "port", "p", 6010, "set the server listening port")
    PFlags.StringVarP(&JwtAuth.Args.Driver, "driver", "", "redis", "specify the storage driver")
    PFlags.StringVarP(&JwtAuth.Args.Conf, "config", "c", "/etc/jwt_authd.json", "configuration file specifying")
    PFlags.BoolVarP(&JwtAuth.Args.Daemon, "daemon", "d", false, "enable daemon mode")
    PFlags.StringVarP(&JwtAuth.Args.PidFile, "pid", "", "/var/run/jwt-auth.pid", "path to use for daemon PID file")
    PFlags.StringVarP(&JwtAuth.Args.LogFile, "log", "", "/var/log/jwt-auth.log", "path to use for log file")

    JwtAuth.Viper.BindPFlag("port", PFlags.Lookup("port"));
    JwtAuth.Viper.BindPFlag("pid", PFlags.Lookup("pid"));
    JwtAuth.Viper.BindPFlag("log", PFlags.Lookup("log"));
    JwtAuth.Viper.BindPFlag("daemon", PFlags.Lookup("daemon"));
    JwtAuth.Viper.BindPFlag("driver", PFlags.Lookup("driver"));
}<commit_msg>fix bug<commit_after>package jwtauthd

import (
    "github.com/spf13/cobra"
    "github.com/spf13/pflag"
    "github.com/spf13/viper"
    "github.com/BluePecker/JwtAuth/daemon"
)

type Args struct {
    PidFile string
    LogFile string
    Port    int
    Driver  string
    Conf    string
    Daemon  bool
}

type JwtAuthCommand struct {
    Args  Args
    Cmd   *cobra.Command
    Viper *viper.Viper
}

var JwtAuth *JwtAuthCommand = &JwtAuthCommand{}

func UsageTemplate() string {
    return `Usage:{{if .Runnable}}
  {{if .HasAvailableFlags}}{{appendIfNotPresent .UseLine "[OPTIONS] COMMAND [arg...]"}}{{else}}{{.UseLine}}{{end}}{{end}}{{if .HasAvailableSubCommands}}
  {{ .CommandPath}} [command]{{end}}{{if gt .Aliases 0}}
Aliases:
  {{.NameAndAliases}}
{{end}}{{if .HasExample}}
Examples:
{{ .Example }}{{end}}{{ if .HasAvailableSubCommands}}
Commands:{{range .Commands}}{{if .IsAvailableCommand}}
  {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{ if .HasAvailableLocalFlags}}
Options:
{{.LocalFlags.FlagUsages | trimRightSpace}}{{end}}{{ if .HasAvailableInheritedFlags}}
Global Flags:
{{.InheritedFlags.FlagUsages | trimRightSpace}}{{end}}{{if .HasHelpSubCommands}}
Additional help topics:{{range .Commands}}{{if .IsHelpCommand}}
  {{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{ if .HasAvailableSubCommands }}
Use "{{.CommandPath}} [command] --help" for more information about a command.{{end}}
`
}

func init() {
    JwtAuth.Viper = viper.GetViper()

    JwtAuth.Cmd = &cobra.Command{
        Use: "jwt-auth",
        Short: "Jwt auth server",
        Long: "User login information verification service",
        SilenceErrors: true,
        RunE: func(cmd *cobra.Command, args []string) error {
            JwtAuth.Viper.SetConfigFile(JwtAuth.Args.Conf)
            if err := JwtAuth.Viper.ReadInConfig(); err != nil {
                return err
            }
            JwtAuth.Args.Port = JwtAuth.Viper.GetInt("port")
            JwtAuth.Args.PidFile = JwtAuth.Viper.GetString("pidfile")
            JwtAuth.Args.LogFile = JwtAuth.Viper.GetString("logfile")
            JwtAuth.Args.Daemon = JwtAuth.Viper.GetBool("daemon")
            JwtAuth.Args.Driver = JwtAuth.Viper.GetString("driver")

            // 开启SERVER服务
            (&daemon.Daemon{}).Start(daemon.Conf{
                PidFile: JwtAuth.Args.PidFile,
                LogFile: JwtAuth.Args.LogFile,
                Port: JwtAuth.Args.Port,
                Daemon: JwtAuth.Args.Daemon,
            })

            return nil
        },
    }
    JwtAuth.Cmd.SetUsageTemplate(UsageTemplate())

    var PFlags *pflag.FlagSet = JwtAuth.Cmd.Flags()

    PFlags.IntVarP(&JwtAuth.Args.Port, "port", "p", 6010, "set the server listening port")
    PFlags.StringVarP(&JwtAuth.Args.Driver, "driver", "", "redis", "specify the storage driver")
    PFlags.StringVarP(&JwtAuth.Args.Conf, "config", "c", "/etc/jwt_authd.json", "configuration file specifying")
    PFlags.BoolVarP(&JwtAuth.Args.Daemon, "daemon", "d", false, "enable daemon mode")
    PFlags.StringVarP(&JwtAuth.Args.PidFile, "pid", "", "/var/run/jwt-auth.pid", "path to use for daemon PID file")
    PFlags.StringVarP(&JwtAuth.Args.LogFile, "log", "", "/var/log/jwt-auth.log", "path to use for log file")

    JwtAuth.Viper.BindPFlag("port", PFlags.Lookup("port"));
    JwtAuth.Viper.BindPFlag("pid", PFlags.Lookup("pid"));
    JwtAuth.Viper.BindPFlag("log", PFlags.Lookup("log"));
    JwtAuth.Viper.BindPFlag("daemon", PFlags.Lookup("daemon"));
    JwtAuth.Viper.BindPFlag("driver", PFlags.Lookup("driver"));
}<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"time"

	"golang.org/x/crypto/openpgp"
	"golang.org/x/crypto/openpgp/armor"

	"github.com/Cloud-Foundations/golib/pkg/awsutil/metadata"
	"github.com/Cloud-Foundations/golib/pkg/awsutil/secretsmgr"
	"github.com/aws/aws-sdk-go/aws/ec2metadata"
)

func (config *autoUnseal) applyDefaults() {
	if config.AwsSecretKey == "" {
		config.AwsSecretKey = "UnsealPassword"
	}
}

func (state *RuntimeState) readyzHandler(w http.ResponseWriter,
	r *http.Request) {
	if state.Signer == nil {
		w.WriteHeader(http.StatusServiceUnavailable)
		fmt.Fprintf(w, "not ready\n")
	} else {
		w.WriteHeader(http.StatusOK)
		fmt.Fprintf(w, "OK\n")
	}
}

func (state *RuntimeState) secretInjectorHandler(w http.ResponseWriter,
	r *http.Request) {
	// checks this is only allowed when using TLS client certs.. all other authn
	// mechanisms are considered invalid... for now no authz mechanisms are in
	// place i.e. Any user with a valid cert can use this handler
	if r.TLS == nil {
		state.writeFailureResponse(w, r, http.StatusInternalServerError, "")
		logger.Printf("We require TLS\n")
		return
	}
	if len(r.TLS.VerifiedChains) < 1 {
		state.writeFailureResponse(w, r, http.StatusForbidden, "")
		logger.Printf("Forbidden\n")
		return
	}
	clientName := r.TLS.VerifiedChains[0][0].Subject.CommonName
	logger.Printf("Got connection from %s", clientName)
	r.ParseForm()
	sshCAPassword, ok := r.Form["ssh_ca_password"]
	if !ok {
		state.writeFailureResponse(w, r, http.StatusBadRequest,
			"Invalid Post, missing data")
		logger.Printf("missing ssh_ca_password")
		return
	}
	if err := state.unsealCA([]byte(sshCAPassword[0]), clientName); err != nil {
		state.writeFailureResponse(w, r, http.StatusBadRequest,
			"Invalid Post, "+err.Error())
		logger.Println(err)
		return
	}
	w.WriteHeader(200)
	fmt.Fprintf(w, "OK\n")
	//fmt.Fprintf(w, "%+v\n", r.TLS)
}

func (state *RuntimeState) beginAutoUnseal() {
	go state.autoUnsealAwsLoop()
}

func (state *RuntimeState) autoUnsealAwsLoop() {
	if state.Config.Base.AutoUnseal.AwsSecretId == "" {
		return
	}
	metadataClient, err := metadata.GetMetadataClient()
	if err != nil {
		state.logger.Println(err)
		return
	}
	for {
		if state.isUnsealed() {
			return
		}
		if err := state.tryAwsUnseal(metadataClient); err != nil {
			state.logger.Printf(
				"error unsealing with AWS Secrets Manager: %s\n", err)
			state.logger.Println("will try again")
			time.Sleep(time.Minute * 5)
		} else {
			return
		}
	}
}

func (state *RuntimeState) isUnsealed() bool {
	state.Mutex.Lock()
	defer state.Mutex.Unlock()
	return state.Signer != nil
}

func (state *RuntimeState) tryAwsUnseal(
	metadataClient *ec2metadata.EC2Metadata) error {
	config := state.Config.Base.AutoUnseal
	secrets, err := secretsmgr.GetAwsSecret(metadataClient, config.AwsSecretId,
		state.logger)
	if err != nil {
		return err
	}
	password, ok := secrets[config.AwsSecretKey]
	if !ok {
		return fmt.Errorf("key: %s not found in secret", config.AwsSecretKey)
	}
	return state.unsealCA([]byte(password), "AWS Secrets Manager")
}

func (state *RuntimeState) unsealCA(password []byte, clientName string) error {
	state.Mutex.Lock()
	defer state.Mutex.Unlock()
	// TODO.. make network error blocks to goroutines
	if state.Signer != nil {
		return errors.New("signer not null, already unlocked")
	}
	decbuf := bytes.NewBuffer(state.SSHCARawFileContent)
	armorBlock, err := armor.Decode(decbuf)
	if err != nil {
		return errors.New("cannot decode armored file")
	}
	failed := false
	prompt := func(keys []openpgp.Key, symmetric bool) ([]byte, error) {
		// If the given passphrase isn't correct, the function will be called
		// again, forever.
		// This method will fail fast.
		// Ref: https://godoc.org/golang.org/x/crypto/openpgp#PromptFunction
		if failed {
			return nil, errors.New("decryption failed")
		}
		failed = true
		return password, nil
	}
	md, err := openpgp.ReadMessage(armorBlock.Body, nil, prompt, nil)
	if err != nil {
		return fmt.Errorf("cannot decrypt key: %s", err)
	}
	plaintextBytes, err := ioutil.ReadAll(md.UnverifiedBody)
	if err != nil {
		return err
	}
	sendMessage := false
	if state.Signer == nil {
		sendMessage = true
	}
	err = state.loadSignersFromPemData(plaintextBytes, nil)
	if err != nil {
		return err
	}
	/*
		signer, err := getSignerFromPEMBytes(plaintextBytes)
		if err != nil {
			fmt.Errorf("cannot parse Private Key file: %s", err)
		}
		logger.Printf("About to generate CA DER %s", clientName)
		state.caCertDer, err = generateCADer(state, signer)
		if err != nil {
			return fmt.Errorf("cannot generate CA DER: %s", err)
		}
		sendMessage := false
		if state.Signer == nil {
			sendMessage = true
		}
		// Assignment of signer MUST be the last operation after all error checks.
		state.Signer = signer
	*/
	state.signerPublicKeyToKeymasterKeys()
	if sendMessage {
		state.SignerIsReady <- true
	}
	// TODO... make success a goroutine
	return nil
}
<commit_msg>unsealing of ed25519 added no tests yet<commit_after>package main

import (
	"bytes"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"time"

	"golang.org/x/crypto/openpgp"
	"golang.org/x/crypto/openpgp/armor"

	"github.com/Cloud-Foundations/golib/pkg/awsutil/metadata"
	"github.com/Cloud-Foundations/golib/pkg/awsutil/secretsmgr"
	"github.com/aws/aws-sdk-go/aws/ec2metadata"
)

func (config *autoUnseal) applyDefaults() {
	if config.AwsSecretKey == "" {
		config.AwsSecretKey = "UnsealPassword"
	}
}

func (state *RuntimeState) readyzHandler(w http.ResponseWriter,
	r *http.Request) {
	if state.Signer == nil {
		w.WriteHeader(http.StatusServiceUnavailable)
		fmt.Fprintf(w, "not ready\n")
	} else {
		w.WriteHeader(http.StatusOK)
		fmt.Fprintf(w, "OK\n")
	}
}

func (state *RuntimeState) secretInjectorHandler(w http.ResponseWriter,
	r *http.Request) {
	// checks this is only allowed when using TLS client certs.. all other authn
	// mechanisms are considered invalid... for now no authz mechanisms are in
	// place i.e. Any user with a valid cert can use this handler
	if r.TLS == nil {
		state.writeFailureResponse(w, r, http.StatusInternalServerError, "")
		logger.Printf("We require TLS\n")
		return
	}
	if len(r.TLS.VerifiedChains) < 1 {
		state.writeFailureResponse(w, r, http.StatusForbidden, "")
		logger.Printf("Forbidden\n")
		return
	}
	clientName := r.TLS.VerifiedChains[0][0].Subject.CommonName
	logger.Printf("Got connection from %s", clientName)
	r.ParseForm()
	sshCAPassword, ok := r.Form["ssh_ca_password"]
	if !ok {
		state.writeFailureResponse(w, r, http.StatusBadRequest,
			"Invalid Post, missing data")
		logger.Printf("missing ssh_ca_password")
		return
	}
	if err := state.unsealCA([]byte(sshCAPassword[0]), clientName); err != nil {
		state.writeFailureResponse(w, r, http.StatusBadRequest,
			"Invalid Post, "+err.Error())
		logger.Println(err)
		return
	}
	w.WriteHeader(200)
	fmt.Fprintf(w, "OK\n")
	//fmt.Fprintf(w, "%+v\n", r.TLS)
}

func (state *RuntimeState) beginAutoUnseal() {
	go state.autoUnsealAwsLoop()
}

func (state *RuntimeState) autoUnsealAwsLoop() {
	if state.Config.Base.AutoUnseal.AwsSecretId == "" {
		return
	}
	metadataClient, err := metadata.GetMetadataClient()
	if err != nil {
		state.logger.Println(err)
		return
	}
	for {
		if state.isUnsealed() {
			return
		}
		if err := state.tryAwsUnseal(metadataClient); err != nil {
			state.logger.Printf(
				"error unsealing with AWS Secrets Manager: %s\n", err)
			state.logger.Println("will try again")
			time.Sleep(time.Minute * 5)
		} else {
			return
		}
	}
}

func (state *RuntimeState) isUnsealed() bool {
	state.Mutex.Lock()
	defer state.Mutex.Unlock()
	return state.Signer != nil
}

func (state *RuntimeState) tryAwsUnseal(
	metadataClient *ec2metadata.EC2Metadata) error {
	config := state.Config.Base.AutoUnseal
	secrets, err := secretsmgr.GetAwsSecret(metadataClient, config.AwsSecretId,
		state.logger)
	if err != nil {
		return err
	}
	password, ok := secrets[config.AwsSecretKey]
	if !ok {
		return fmt.Errorf("key: %s not found in secret", config.AwsSecretKey)
	}
	return state.unsealCA([]byte(password), "AWS Secrets Manager")
}

func pgpDecryptFileData(cipherText []byte, password []byte) ([]byte, error) {
	decbuf := bytes.NewBuffer(cipherText)
	armorBlock, err := armor.Decode(decbuf)
	if err != nil {
		return nil, errors.New("cannot decode armored file")
	}
	failed := false
	prompt := func(keys []openpgp.Key, symmetric bool) ([]byte, error) {
		// If the given passphrase isn't correct, the function will be called
		// again, forever.
		// This method will fail fast.
		// Ref: https://godoc.org/golang.org/x/crypto/openpgp#PromptFunction
		if failed {
			return nil, errors.New("decryption failed")
		}
		failed = true
		return password, nil
	}
	md, err := openpgp.ReadMessage(armorBlock.Body, nil, prompt, nil)
	if err != nil {
		return nil, fmt.Errorf("cannot decrypt key: %s", err)
	}
	return ioutil.ReadAll(md.UnverifiedBody)
}

func (state *RuntimeState) unsealCA(password []byte, clientName string) error {
	state.Mutex.Lock()
	defer state.Mutex.Unlock()
	// TODO.. make network error blocks to goroutines
	if state.Signer != nil {
		return errors.New("signer not null, already unlocked")
	}
	signerPlaintextBytes, err := pgpDecryptFileData(state.SSHCARawFileContent, password)
	if err != nil {
		return err
	}
	var ed25519PlaintextBytes []byte
	if state.Ed25519CAFileContent != nil && len(state.Ed25519CAFileContent) > 0 {
		ed25519PlaintextBytes, err = pgpDecryptFileData(state.Ed25519CAFileContent, password)
	}

	sendMessage := false
	if state.Signer == nil {
		sendMessage = true
	}
	err = state.loadSignersFromPemData(signerPlaintextBytes, ed25519PlaintextBytes)
	if err != nil {
		return err
	}
	state.signerPublicKeyToKeymasterKeys()
	if sendMessage {
		state.SignerIsReady <- true
	}
	// TODO... make success a goroutine
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"path/filepath"
	"runtime"
	"strings"

	. "github.com/prabirshrestha/go-coreutils/Godeps/_workspace/src/github.com/timtadh/getopt"
)

func main() {
	args, optargs, err := GetOpt(os.Args[1:], "q:", nil)

	if err != nil {
		usage()
	}

	for _, value := range optargs {
		switch value.Opt() {
		case "-q":
		default:
			usage()
		}
	}

	if len(args) == 0 {
		args = []string{"."}
	}

	for _, value := range args {
		originalValue := value
		if value == "~" {
			value = userHomeDir()
		} else if strings.HasPrefix(value, "~/") {
			value = userHomeDir() + value[1:]
		}

		path, err := filepath.Abs(value)
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}

		if strings.HasSuffix(path, "/") || strings.HasSuffix(path, "\\") {
			path = path[0 : len(path)-1]
		}

		_, err = os.Stat(path)
		if err != nil {
			if os.IsNotExist(err) {
				fmt.Println("realpath: " + originalValue + ": No such file or directory")
				continue
			} else {
				fmt.Println(err)
				continue
			}
		}

		fmt.Println(path)
	}
}

func usage() {
	fmt.Println("usage: realpath [-q] [path ...]")
	os.Exit(1)
}

func userHomeDir() string {
	if runtime.GOOS == "windows" {
		home := os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
		if home == "" {
			home = os.Getenv("USERPROFILE")
		}
		return home
	}

	return os.Getenv("HOME")
}
<commit_msg>realpath support for quiet<commit_after>package main

import (
	"fmt"
	"os"
	"path/filepath"
	"runtime"
	"strings"

	. "github.com/prabirshrestha/go-coreutils/Godeps/_workspace/src/github.com/timtadh/getopt"
)

func main() {
	quiet := false

	args, optargs, err := GetOpt(os.Args[1:], "q:", nil)

	if err != nil {
		usage()
	}

	for _, value := range optargs {
		switch value.Opt() {
		case "-q":
			quiet = true
		default:
			usage()
		}
	}

	if len(args) == 0 {
		args = []string{"."}
	}

	for _, value := range args {
		originalValue := value
		if value == "~" {
			value = userHomeDir()
		} else if strings.HasPrefix(value, "~/") {
			value = userHomeDir() + value[1:]
		}

		path, err := filepath.Abs(value)
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}

		if strings.HasSuffix(path, "/") || strings.HasSuffix(path, "\\") {
			path = path[0 : len(path)-1]
		}

		_, err = os.Stat(path)
		if err != nil {
			if os.IsNotExist(err) {
				if !quiet {
					fmt.Println("realpath: " + originalValue + ": No such file or directory")
				}
				continue
			} else {
				fmt.Println(err)
				continue
			}
		}

		fmt.Println(path)
	}
}

func usage() {
	fmt.Println("usage: realpath [-q] [path ...]")
	os.Exit(1)
}

func userHomeDir() string {
	if runtime.GOOS == "windows" {
		home := os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
		if home == "" {
			home = os.Getenv("USERPROFILE")
		}
		return home
	}

	return os.Getenv("HOME")
}
<|endoftext|>


<commit_before>package reproducer

import (
	"fmt"
	"log"
	"path/filepath"
	"reflect"
	"sort"
	"strings"
	"time"

	"github.com/datawire/ambassador/pkg/kates"
	"github.com/pkg/errors"
	"github.com/spf13/cobra"
	"gopkg.in/yaml.v2"
)

var createCmd = &cobra.Command{
	Use:   "create ( <snapshot> | <extraction> | <archive> )",
	Short: "create produces a working set of manifests based on snapshots and/or extractions produce by the extract subcommand",
	Long: `The create subcommand is designed for creating high fidelity reproductions of a source cluster using edge-stack. All of the ambassador inputs are recreated exactly as they are in the source cluster. All the services in the source cluster are also recreated, but they are transformed to point to a single set of pods with a "service: reproducer" label. This allows for a high fidelity working reproduction of the source cluster without requiring access to any of the propriety deployments in the source cluster.

The output of the create command can be passed directly to kubectl, e.g.:

    reproducer create sanitized.tgz | kubectl apply -f -

You can also save the output and hand edit it should you need to tweak some of the details:

    reproducer create sanitized.tgz > repro.yaml
    vi repro.yaml
    kubectl apply -f repro.yaml
`,
	Args: cobra.ExactArgs(1),
	RunE: create,
}

func create(cmd *cobra.Command, args []string) error {
	filename := args[0]

	extensions := map[string]bool{
		".yml":  true,
		".yaml": true,
		".json": true,
	}

	repro := NewRepro()

	err := search(filename, func(path, contentType, encoding string, content []byte) error {
		base := filepath.Base(path)
		ext := filepath.Ext(base)
		name := base[:len(base)-len(ext)]

		if !extensions[ext] {
			log.Printf("skipping %s", path)
			return nil
		}

		if !(name == "snapshot" || name == "manifests") {
			log.Printf("skipping %s", path)
			return nil
		}

		log.Printf("found resources from %s", path)

		switch name {
		case "snapshot":
			var snapshot struct {
				Kubernetes map[string][]*kates.Unstructured
			}
			err := yaml.Unmarshal(content, &snapshot)
			if err != nil {
				return errors.Wrapf(err, "decoding snapshot at %s", path)
			}

			for _, values := range snapshot.Kubernetes {
				for _, resource := range values {
					err := repro.Add(resource)
					if err != nil {
						return errors.Wrapf(err, "adding resource")
					}
				}
			}
		case "manifests":
			resources, err := kates.ParseManifests(string(content))
			if err != nil {
				return errors.Wrapf(err, "decoding manifests at %s", path)
			}

			for _, resource := range resources {
				err := repro.Add(resource)
				if err != nil {
					return errors.Wrapf(err, "adding resource")
				}
			}
		}

		return breakSearch
	})

	if err == nil {
		return errors.Errorf("unable to find suitable snapshot in %s", filename)
	}

	if err != breakSearch {
		return err
	}

	// Process all the resources we found.
	err = repro.Process()
	if err != nil {
		return err
	}

	// Marshal all the transformed resources.
	marshalled, err := repro.Marshal()
	if err != nil {
		return err
	}

	fmt.Print(string(marshalled))

	return nil
}

type Repro struct {
	Resources  map[string][]*kates.Unstructured
	Namespaces map[string]bool
	Ports      map[string]bool
	Processed  []*kates.Unstructured
}

func NewRepro() *Repro {
	return &Repro{
		Resources:  map[string][]*kates.Unstructured{},
		Namespaces: map[string]bool{},
		Ports:      map[string]bool{},
	}
}

// Add an input resource from the source cluster.
func (r *Repro) Add(resource kates.Object) error {
	un, err := kates.NewUnstructuredFromObject(resource)
	if err != nil {
		return err
	}
	gvk := resource.GetObjectKind().GroupVersionKind()
	r.Resources[gvk.Kind] = append(r.Resources[gvk.Kind], un)
	return nil

}

func (r *Repro) Process() error {
	// Process resources in order.
	for _, key := range r.OrderedKinds() {
		values, ok := r.Resources[key]
		if ok {
			delete(r.Resources, key)
			for _, resource := range values {
				p := r.callProcess(resource)
				if p != nil {
					r.Processed = append(r.Processed, p)
				}
			}
		}
	}

	// Remove any included namespaces
	for _, p := range r.Processed {
		if p.GetObjectKind().GroupVersionKind().Kind == "Namespace" {
			delete(r.Namespaces, p.GetName())
		}
	}

	// Auto create any missing namespaces and prepend so they are defined before being used.
	ns := []*kates.Unstructured{}
	for _, k := range sortedKeys(r.Namespaces) {
		un, err := kates.NewUnstructuredFromObject(&kates.Namespace{
			TypeMeta:   kates.TypeMeta{APIVersion: "v1", Kind: "Namespace"},
			ObjectMeta: kates.ObjectMeta{Name: k},
		})
		if err != nil {
			return errors.Wrapf(err, "error creating namespace %s", k)
		}
		ns = append(ns, un)
	}

	r.Processed = append(ns, r.Processed...)

	return nil
}

// OrderedKinds returns all the k8s kinds in the proper order to avoid dangling references.
func (r *Repro) OrderedKinds() []string {
	return append([]string{
		"CustomResourceDefinition",
		"Namespace",
		"ServiceAccount",
		"ClusterRole",
		"ClusterRoleBinding",
		"Role",
		"RoleBinding",
		"Secret",
	},
		sortedKeys(r.Resources)...)
}

func (r *Repro) callProcess(resource *kates.Unstructured) *kates.Unstructured {
	if len(resource.GetOwnerReferences()) > 0 {
		return nil
	}
	if resource.GetNamespace() == "kube-system" {
		return nil
	}

	gvk := resource.GetObjectKind().GroupVersionKind()
	switch gvk.Kind {
	case "APIService":
		return nil
	case "ComponentStatus":
		return nil
	case "EndpointSlice":
		return nil
	case "Endpoints":
		return nil
	case "Event":
		return nil
	case "Lease":
		return nil
	case "Node":
		return nil
	case "NodeMetrics":
		return nil
	case "PodMetrics":
		return nil
	case "StorageClass":
		return nil
	case "PriorityClass":
		return nil
	}

	obj, err := kates.NewObjectFromUnstructured(resource)
	if err != nil {
		log.Printf("error processing object: %+v", err)
		return nil
	}

	obj = r.process(obj)

	// convert back to unstructured so we serialize prettier, e.g. no creationTimestamp: null
	result, err := kates.NewUnstructuredFromObject(obj)
	if err != nil {
		log.Printf("error making unstructured from object: %+v", err)
		return nil
	}

	return clean(result)
}

func (r *Repro) process(object kates.Object) kates.Object {
	r.Namespaces[object.GetNamespace()] = true

	rbac := false
	switch obj := object.(type) {
	case *kates.Service:
		obj.Spec.ClusterIP = ""
		if !isAmbassadorResource(object) {
			obj.Spec.Selector = map[string]string{
				"service": "reproducer",
			}
			for _, port := range obj.Spec.Ports {
				r.Ports[port.TargetPort.String()] = true
			}
		}
	case *kates.ClusterRole:
		rbac = true
	case *kates.ClusterRoleBinding:
		rbac = true
	case *kates.Role:
		rbac = true
	case *kates.RoleBinding:
		rbac = true
	case *kates.ServiceAccount:
		rbac = true
		if obj.GetName() == "default" {
			return nil
		}
	}

	if rbac && strings.Contains(object.GetName(), "system:") {
		return nil
	}

	return object
}

const lastApplied = "kubectl.kubernetes.io/last-applied-configuration"
const bootstrappingLabel = "kubernetes.io/bootstrapping"

// clean does generic cleanup of resources from the source cluster. Kubectl will
func clean(resource *kates.Unstructured) *kates.Unstructured {
	if resource == nil {
		return nil
	}

	ann := resource.GetAnnotations()
	if ann == nil {
		ann = map[string]string{}
	}
	delete(ann, lastApplied)

	labels := resource.GetLabels()
	_, ok := labels[bootstrappingLabel]
	if ok {
		return nil
	}

	if len(ann) > 0 {
		resource.SetAnnotations(ann)
	} else {
		resource.SetAnnotations(nil)
	}
	resource.SetManagedFields(nil)
	resource.SetCreationTimestamp(kates.Time{Time: time.Time{}})
	resource.SetUID("")
	resource.SetResourceVersion("")
	resource.SetSelfLink("")
	resource.SetGeneration(0)
	delete(resource.Object, "status")
	return resource
}

func (r *Repro) Marshal() ([]byte, error) {
	return marshalManifests(r.Processed)
}

func sortedKeys(m interface{}) (result []string) {
	mval := reflect.ValueOf(m)
	for _, v := range mval.MapKeys() {
		result = append(result, v.Interface().(string))
	}
	sort.Strings(result)
	return
}
<commit_msg>(from AES) yaml unmarshal doesn't seem to always work<commit_after>package reproducer

import (
	"encoding/json"
	"fmt"
	"log"
	"path/filepath"
	"reflect"
	"sort"
	"strings"
	"time"

	"github.com/datawire/ambassador/pkg/kates"
	"github.com/pkg/errors"
	"github.com/spf13/cobra"
)

var createCmd = &cobra.Command{
	Use:   "create ( <snapshot> | <extraction> | <archive> )",
	Short: "create produces a working set of manifests based on snapshots and/or extractions produce by the extract subcommand",
	Long: `The create subcommand is designed for creating high fidelity reproductions of a source cluster using edge-stack. All of the ambassador inputs are recreated exactly as they are in the source cluster. All the services in the source cluster are also recreated, but they are transformed to point to a single set of pods with a "service: reproducer" label. This allows for a high fidelity working reproduction of the source cluster without requiring access to any of the propriety deployments in the source cluster.

The output of the create command can be passed directly to kubectl, e.g.:

    reproducer create sanitized.tgz | kubectl apply -f -

You can also save the output and hand edit it should you need to tweak some of the details:

    reproducer create sanitized.tgz > repro.yaml
    vi repro.yaml
    kubectl apply -f repro.yaml
`,
	Args: cobra.ExactArgs(1),
	RunE: create,
}

func create(cmd *cobra.Command, args []string) error {
	filename := args[0]

	extensions := map[string]bool{
		".yml":  true,
		".yaml": true,
		".json": true,
	}

	repro := NewRepro()

	err := search(filename, func(path, contentType, encoding string, content []byte) error {
		base := filepath.Base(path)
		ext := filepath.Ext(base)
		name := base[:len(base)-len(ext)]

		if !extensions[ext] {
			log.Printf("skipping %s", path)
			return nil
		}

		if !(name == "snapshot" || name == "manifests") {
			log.Printf("skipping %s", path)
			return nil
		}

		log.Printf("found resources from %s", path)

		switch name {
		case "snapshot":
			var snapshot struct {
				Kubernetes map[string][]*kates.Unstructured
			}
			err := json.Unmarshal(content, &snapshot)
			if err != nil {
				return errors.Wrapf(err, "decoding snapshot at %s", path)
			}

			for _, values := range snapshot.Kubernetes {
				for _, resource := range values {
					err := repro.Add(resource)
					if err != nil {
						return errors.Wrapf(err, "adding resource")
					}
				}
			}
		case "manifests":
			resources, err := kates.ParseManifests(string(content))
			if err != nil {
				return errors.Wrapf(err, "decoding manifests at %s", path)
			}

			for _, resource := range resources {
				err := repro.Add(resource)
				if err != nil {
					return errors.Wrapf(err, "adding resource")
				}
			}
		}

		return breakSearch
	})

	if err == nil {
		return errors.Errorf("unable to find suitable snapshot in %s", filename)
	}

	if err != breakSearch {
		return err
	}

	// Process all the resources we found.
	err = repro.Process()
	if err != nil {
		return err
	}

	// Marshal all the transformed resources.
	marshalled, err := repro.Marshal()
	if err != nil {
		return err
	}

	fmt.Print(string(marshalled))

	return nil
}

type Repro struct {
	Resources  map[string][]*kates.Unstructured
	Namespaces map[string]bool
	Ports      map[string]bool
	Processed  []*kates.Unstructured
}

func NewRepro() *Repro {
	return &Repro{
		Resources:  map[string][]*kates.Unstructured{},
		Namespaces: map[string]bool{},
		Ports:      map[string]bool{},
	}
}

// Add an input resource from the source cluster.
func (r *Repro) Add(resource kates.Object) error {
	un, err := kates.NewUnstructuredFromObject(resource)
	if err != nil {
		return err
	}
	gvk := resource.GetObjectKind().GroupVersionKind()
	r.Resources[gvk.Kind] = append(r.Resources[gvk.Kind], un)
	return nil

}

func (r *Repro) Process() error {
	// Process resources in order.
	for _, key := range r.OrderedKinds() {
		values, ok := r.Resources[key]
		if ok {
			delete(r.Resources, key)
			for _, resource := range values {
				p := r.callProcess(resource)
				if p != nil {
					r.Processed = append(r.Processed, p)
				}
			}
		}
	}

	// Remove any included namespaces
	for _, p := range r.Processed {
		if p.GetObjectKind().GroupVersionKind().Kind == "Namespace" {
			delete(r.Namespaces, p.GetName())
		}
	}

	// Auto create any missing namespaces and prepend so they are defined before being used.
	ns := []*kates.Unstructured{}
	for _, k := range sortedKeys(r.Namespaces) {
		un, err := kates.NewUnstructuredFromObject(&kates.Namespace{
			TypeMeta:   kates.TypeMeta{APIVersion: "v1", Kind: "Namespace"},
			ObjectMeta: kates.ObjectMeta{Name: k},
		})
		if err != nil {
			return errors.Wrapf(err, "error creating namespace %s", k)
		}
		ns = append(ns, un)
	}

	r.Processed = append(ns, r.Processed...)

	return nil
}

// OrderedKinds returns all the k8s kinds in the proper order to avoid dangling references.
func (r *Repro) OrderedKinds() []string {
	return append([]string{
		"CustomResourceDefinition",
		"Namespace",
		"ServiceAccount",
		"ClusterRole",
		"ClusterRoleBinding",
		"Role",
		"RoleBinding",
		"Secret",
	},
		sortedKeys(r.Resources)...)
}

func (r *Repro) callProcess(resource *kates.Unstructured) *kates.Unstructured {
	if len(resource.GetOwnerReferences()) > 0 {
		return nil
	}
	if resource.GetNamespace() == "kube-system" {
		return nil
	}

	gvk := resource.GetObjectKind().GroupVersionKind()
	switch gvk.Kind {
	case "APIService":
		return nil
	case "ComponentStatus":
		return nil
	case "EndpointSlice":
		return nil
	case "Endpoints":
		return nil
	case "Event":
		return nil
	case "Lease":
		return nil
	case "Node":
		return nil
	case "NodeMetrics":
		return nil
	case "PodMetrics":
		return nil
	case "StorageClass":
		return nil
	case "PriorityClass":
		return nil
	}

	obj, err := kates.NewObjectFromUnstructured(resource)
	if err != nil {
		log.Printf("error processing object: %+v", err)
		return nil
	}

	obj = r.process(obj)

	// convert back to unstructured so we serialize prettier, e.g. no creationTimestamp: null
	result, err := kates.NewUnstructuredFromObject(obj)
	if err != nil {
		log.Printf("error making unstructured from object: %+v", err)
		return nil
	}

	return clean(result)
}

func (r *Repro) process(object kates.Object) kates.Object {
	r.Namespaces[object.GetNamespace()] = true

	rbac := false
	switch obj := object.(type) {
	case *kates.Service:
		obj.Spec.ClusterIP = ""
		if !isAmbassadorResource(object) {
			obj.Spec.Selector = map[string]string{
				"service": "reproducer",
			}
			for _, port := range obj.Spec.Ports {
				r.Ports[port.TargetPort.String()] = true
			}
		}
	case *kates.ClusterRole:
		rbac = true
	case *kates.ClusterRoleBinding:
		rbac = true
	case *kates.Role:
		rbac = true
	case *kates.RoleBinding:
		rbac = true
	case *kates.ServiceAccount:
		rbac = true
		if obj.GetName() == "default" {
			return nil
		}
	}

	if rbac && strings.Contains(object.GetName(), "system:") {
		return nil
	}

	return object
}

const lastApplied = "kubectl.kubernetes.io/last-applied-configuration"
const bootstrappingLabel = "kubernetes.io/bootstrapping"

// clean does generic cleanup of resources from the source cluster. Kubectl will
func clean(resource *kates.Unstructured) *kates.Unstructured {
	if resource == nil {
		return nil
	}

	ann := resource.GetAnnotations()
	if ann == nil {
		ann = map[string]string{}
	}
	delete(ann, lastApplied)

	labels := resource.GetLabels()
	_, ok := labels[bootstrappingLabel]
	if ok {
		return nil
	}

	if len(ann) > 0 {
		resource.SetAnnotations(ann)
	} else {
		resource.SetAnnotations(nil)
	}
	resource.SetManagedFields(nil)
	resource.SetCreationTimestamp(kates.Time{Time: time.Time{}})
	resource.SetUID("")
	resource.SetResourceVersion("")
	resource.SetSelfLink("")
	resource.SetGeneration(0)
	delete(resource.Object, "status")
	return resource
}

func (r *Repro) Marshal() ([]byte, error) {
	return marshalManifests(r.Processed)
}

func sortedKeys(m interface{}) (result []string) {
	mval := reflect.ValueOf(m)
	for _, v := range mval.MapKeys() {
		result = append(result, v.Interface().(string))
	}
	sort.Strings(result)
	return
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"github.com/kayex/sirius"
	"github.com/kayex/sirius/config"
	"github.com/kayex/sirius/extension"
	"context"
	"io/ioutil"
)

var extensions []string = []string{
	"geocode",
	"ip_lookup",
	"quotes",
	"replacer",
	"ripperino",
	"thumbs_up",
}

func main() {
	cfg := config.FromEnv()
	users := createUsers(getTokensFromJSON())

	l := extension.NewStaticLoader(cfg)
	s := sirius.NewService(l)

	s.Start(context.TODO(), users)
}

func createUsers(tokens []string) []sirius.User {
	var users []sirius.User

	for _, t := range tokens {
		u := sirius.NewUser(t)
		configure(u)

		users = append(users, *u)
	}

	return users
}

func configure(u *sirius.User) {
	for _, eid := range extensions {
		c := sirius.NewConfiguration(sirius.EID(eid))
		u.Configurations = append(u.Configurations, &c)
	}
}

func getTokensFromJSON() []string {
	file, err := ioutil.ReadFile("./users.json")
	if err != nil {
		fmt.Println(err.Error())
	}

	var tokens []string

	json.Unmarshal(file, &tokens)

	return tokens
}
<commit_msg>Go fmt<commit_after>package main

import (
	"context"
	"encoding/json"
	"fmt"
	"github.com/kayex/sirius"
	"github.com/kayex/sirius/config"
	"github.com/kayex/sirius/extension"
	"io/ioutil"
)

var extensions []string = []string{
	"geocode",
	"ip_lookup",
	"quotes",
	"replacer",
	"ripperino",
	"thumbs_up",
}

func main() {
	cfg := config.FromEnv()
	users := createUsers(getTokensFromJSON())

	l := extension.NewStaticLoader(cfg)
	s := sirius.NewService(l)

	s.Start(context.TODO(), users)
}

func createUsers(tokens []string) []sirius.User {
	var users []sirius.User

	for _, t := range tokens {
		u := sirius.NewUser(t)
		configure(u)

		users = append(users, *u)
	}

	return users
}

func configure(u *sirius.User) {
	for _, eid := range extensions {
		c := sirius.NewConfiguration(sirius.EID(eid))
		u.Configurations = append(u.Configurations, &c)
	}
}

func getTokensFromJSON() []string {
	file, err := ioutil.ReadFile("./users.json")
	if err != nil {
		fmt.Println(err.Error())
	}

	var tokens []string

	json.Unmarshal(file, &tokens)

	return tokens
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/gob"
	"errors"
	"fmt"
	"net"
	"os"

	"github.com/Symantec/Dominator/lib/log"
	"github.com/Symantec/Dominator/lib/srpc"
	hyper_proto "github.com/Symantec/Dominator/proto/hypervisor"
)

func copyVmSubcommand(args []string, logger log.DebugLogger) {
	if err := copyVm(args[0], logger); err != nil {
		fmt.Fprintf(os.Stderr, "Error copying VM: %s\n", err)
		os.Exit(1)
	}
	os.Exit(0)
}

func copyVm(vmHostname string, logger log.DebugLogger) error {
	if vmIP, hypervisor, err := searchVmAndHypervisor(vmHostname); err != nil {
		return err
	} else {
		return copyVmFromHypervisor(hypervisor, vmIP, logger)
	}
}

func callCopyVm(client *srpc.Client, request hyper_proto.CopyVmRequest,
	reply *hyper_proto.CopyVmResponse, logger log.DebugLogger) error {
	conn, err := client.Call("Hypervisor.CopyVm")
	if err != nil {
		return err
	}
	defer conn.Close()
	encoder := gob.NewEncoder(conn)
	decoder := gob.NewDecoder(conn)
	if err := encoder.Encode(request); err != nil {
		return err
	}
	if err := conn.Flush(); err != nil {
		return err
	}
	for {
		var response hyper_proto.CopyVmResponse
		if err := decoder.Decode(&response); err != nil {
			return err
		}
		if response.Error != "" {
			return errors.New(response.Error)
		}
		if response.ProgressMessage != "" {
			logger.Debugln(0, response.ProgressMessage)
		}
		if response.Final {
			*reply = response
			return nil
		}
	}
}

func copyVmFromHypervisor(sourceHypervisorAddress string, vmIP net.IP,
	logger log.DebugLogger) error {
	destHypervisorAddress, err := getHypervisorAddress()
	if err != nil {
		return err
	}
	sourceHypervisor, err := dialHypervisor(sourceHypervisorAddress)
	if err != nil {
		return err
	}
	defer sourceHypervisor.Close()
	accessToken, err := getVmAccessTokenClient(sourceHypervisor, vmIP)
	if err != nil {
		return err
	}
	defer discardAccessToken(sourceHypervisor, vmIP)
	destHypervisor, err := dialHypervisor(destHypervisorAddress)
	if err != nil {
		return err
	}
	defer destHypervisor.Close()
	request := hyper_proto.CopyVmRequest{
		AccessToken:      accessToken,
		DhcpTimeout:      *dhcpTimeout,
		IpAddress:        vmIP,
		SourceHypervisor: sourceHypervisorAddress,
	}
	var reply hyper_proto.CopyVmResponse
	logger.Debugf(0, "copying VM to %s\n", destHypervisorAddress)
	if err := callCopyVm(destHypervisor, request, &reply, logger); err != nil {
		return err
	}
	if err := acknowledgeVm(destHypervisor, reply.IpAddress); err != nil {
		return fmt.Errorf("error acknowledging VM: %s", err)
	}
	fmt.Println(reply.IpAddress)
	if reply.DhcpTimedOut {
		return errors.New("DHCP ACK timed out")
	}
	if *dhcpTimeout > 0 {
		logger.Debugln(0, "Received DHCP ACK")
	}
	return maybeWatchVm(destHypervisor, destHypervisorAddress, reply.IpAddress,
		logger)
}
<commit_msg>Remove obsolete DHCP checks and probes from vm-control copy-vm subcommand.<commit_after>package main

import (
	"encoding/gob"
	"errors"
	"fmt"
	"net"
	"os"

	"github.com/Symantec/Dominator/lib/log"
	"github.com/Symantec/Dominator/lib/srpc"
	hyper_proto "github.com/Symantec/Dominator/proto/hypervisor"
)

func copyVmSubcommand(args []string, logger log.DebugLogger) {
	if err := copyVm(args[0], logger); err != nil {
		fmt.Fprintf(os.Stderr, "Error copying VM: %s\n", err)
		os.Exit(1)
	}
	os.Exit(0)
}

func copyVm(vmHostname string, logger log.DebugLogger) error {
	if vmIP, hypervisor, err := searchVmAndHypervisor(vmHostname); err != nil {
		return err
	} else {
		return copyVmFromHypervisor(hypervisor, vmIP, logger)
	}
}

func callCopyVm(client *srpc.Client, request hyper_proto.CopyVmRequest,
	reply *hyper_proto.CopyVmResponse, logger log.DebugLogger) error {
	conn, err := client.Call("Hypervisor.CopyVm")
	if err != nil {
		return err
	}
	defer conn.Close()
	encoder := gob.NewEncoder(conn)
	decoder := gob.NewDecoder(conn)
	if err := encoder.Encode(request); err != nil {
		return err
	}
	if err := conn.Flush(); err != nil {
		return err
	}
	for {
		var response hyper_proto.CopyVmResponse
		if err := decoder.Decode(&response); err != nil {
			return err
		}
		if response.Error != "" {
			return errors.New(response.Error)
		}
		if response.ProgressMessage != "" {
			logger.Debugln(0, response.ProgressMessage)
		}
		if response.Final {
			*reply = response
			return nil
		}
	}
}

func copyVmFromHypervisor(sourceHypervisorAddress string, vmIP net.IP,
	logger log.DebugLogger) error {
	destHypervisorAddress, err := getHypervisorAddress()
	if err != nil {
		return err
	}
	sourceHypervisor, err := dialHypervisor(sourceHypervisorAddress)
	if err != nil {
		return err
	}
	defer sourceHypervisor.Close()
	accessToken, err := getVmAccessTokenClient(sourceHypervisor, vmIP)
	if err != nil {
		return err
	}
	defer discardAccessToken(sourceHypervisor, vmIP)
	destHypervisor, err := dialHypervisor(destHypervisorAddress)
	if err != nil {
		return err
	}
	defer destHypervisor.Close()
	request := hyper_proto.CopyVmRequest{
		AccessToken:      accessToken,
		IpAddress:        vmIP,
		SourceHypervisor: sourceHypervisorAddress,
	}
	var reply hyper_proto.CopyVmResponse
	logger.Debugf(0, "copying VM to %s\n", destHypervisorAddress)
	if err := callCopyVm(destHypervisor, request, &reply, logger); err != nil {
		return err
	}
	if err := acknowledgeVm(destHypervisor, reply.IpAddress); err != nil {
		return fmt.Errorf("error acknowledging VM: %s", err)
	}
	fmt.Println(reply.IpAddress)
	return nil
}
<|endoftext|>


<commit_before>package git

/*
#include <git2.h>
#include <git2/sys/repository.h>
*/
import "C"
import (
	"runtime"
	"unsafe"
)

// Repository
type Repository struct {
	ptr *C.git_repository
	// Remotes represents the collection of remotes and can be
	// used to add, remove and configure remotes for this
	// repository.
	Remotes RemoteCollection
	// Submodules represents the collection of submodules and can
	// be used to add, remove and configure submodules in this
	// repostiory.
	Submodules SubmoduleCollection
	// References represents the collection of references and can
	// be used to create, remove or update refernces for this repository.
	References ReferenceCollection
	// Notes represents the collection of notes and can be used to
	// read, write and delete notes from this repository.
	Notes NoteCollection
	// Tags represents the collection of tags and can be used to create,
	// list and iterate tags in this repository.
	Tags TagsCollection
	// Stashes represents the collection of stashes and can be used to
	// save, apply and iterate over stash states in this repository.
	Stashes StashCollection
}

func newRepositoryFromC(ptr *C.git_repository) *Repository {
	repo := &Repository{ptr: ptr}

	repo.Remotes.repo = repo
	repo.Submodules.repo = repo
	repo.References.repo = repo
	repo.Notes.repo = repo
	repo.Tags.repo = repo
	repo.Stashes.repo = repo

	runtime.SetFinalizer(repo, (*Repository).Free)

	return repo
}

func OpenRepository(path string) (*Repository, error) {
	cpath := C.CString(path)
	defer C.free(unsafe.Pointer(cpath))

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	var ptr *C.git_repository
	ret := C.git_repository_open(&ptr, cpath)
	if ret < 0 {
		return nil, MakeGitError(ret)
	}

	return newRepositoryFromC(ptr), nil
}

type RepositoryOpenFlag int

const (
	RepositoryOpenNoSearch RepositoryOpenFlag = C.GIT_REPOSITORY_OPEN_NO_SEARCH
	RepositoryOpenCrossFs  RepositoryOpenFlag = C.GIT_REPOSITORY_OPEN_CROSS_FS
	RepositoryOpenBare     RepositoryOpenFlag = C.GIT_REPOSITORY_OPEN_BARE
)

func OpenRepositoryExtended(path string, flags RepositoryOpenFlag, ceiling string) (*Repository, error) {
	cpath := C.CString(path)
	defer C.free(unsafe.Pointer(cpath))

	var cceiling *C.char = nil
	if len(ceiling) > 0 {
		cceiling = C.CString(ceiling)
		defer C.free(unsafe.Pointer(cceiling))
	}

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	var ptr *C.git_repository
	ret := C.git_repository_open_ext(&ptr, cpath, C.uint(flags), cceiling)
	if ret < 0 {
		return nil, MakeGitError(ret)
	}

	return newRepositoryFromC(ptr), nil
}

func InitRepository(path string, isbare bool) (*Repository, error) {
	cpath := C.CString(path)
	defer C.free(unsafe.Pointer(cpath))

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	var ptr *C.git_repository
	ret := C.git_repository_init(&ptr, cpath, ucbool(isbare))
	if ret < 0 {
		return nil, MakeGitError(ret)
	}

	return newRepositoryFromC(ptr), nil
}

func NewRepositoryWrapOdb(odb *Odb) (repo *Repository, err error) {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	var ptr *C.git_repository
	ret := C.git_repository_wrap_odb(&ptr, odb.ptr)
	if ret < 0 {
		return nil, MakeGitError(ret)
	}

	return newRepositoryFromC(ptr), nil
}

func (v *Repository) SetRefdb(refdb *Refdb) {
	C.git_repository_set_refdb(v.ptr, refdb.ptr)
}

func (v *Repository) Free() {
	runtime.SetFinalizer(v, nil)
	C.git_repository_free(v.ptr)
}

func (v *Repository) Config() (*Config, error) {
	config := new(Config)

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ret := C.git_repository_config(&config.ptr, v.ptr)
	if ret < 0 {
		return nil, MakeGitError(ret)
	}

	runtime.SetFinalizer(config, (*Config).Free)
	return config, nil
}

func (v *Repository) Index() (*Index, error) {
	var ptr *C.git_index

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ret := C.git_repository_index(&ptr, v.ptr)
	if ret < 0 {
		return nil, MakeGitError(ret)
	}

	return newIndexFromC(ptr), nil
}

func (v *Repository) lookupType(id *Oid, t ObjectType) (*Object, error) {
	var ptr *C.git_object

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ret := C.git_object_lookup(&ptr, v.ptr, id.toC(), C.git_otype(t))
	if ret < 0 {
		return nil, MakeGitError(ret)
	}

	return allocObject(ptr, v), nil
}

func (v *Repository) Lookup(id *Oid) (*Object, error) {
	return v.lookupType(id, ObjectAny)
}

func (v *Repository) LookupTree(id *Oid) (*Tree, error) {
	obj, err := v.lookupType(id, ObjectTree)
	if err != nil {
		return nil, err
	}

	return obj.AsTree()
}

func (v *Repository) LookupCommit(id *Oid) (*Commit, error) {
	obj, err := v.lookupType(id, ObjectCommit)
	if err != nil {
		return nil, err
	}

	return obj.AsCommit()
}

func (v *Repository) LookupBlob(id *Oid) (*Blob, error) {
	obj, err := v.lookupType(id, ObjectBlob)
	if err != nil {
		return nil, err
	}

	return obj.AsBlob()
}

func (v *Repository) LookupTag(id *Oid) (*Tag, error) {
	obj, err := v.lookupType(id, ObjectTag)
	if err != nil {
		return nil, err
	}

	return obj.AsTag()
}

func (v *Repository) Head() (*Reference, error) {
	var ptr *C.git_reference

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ecode := C.git_repository_head(&ptr, v.ptr)
	if ecode < 0 {
		return nil, MakeGitError(ecode)
	}

	return newReferenceFromC(ptr, v), nil
}

func (v *Repository) SetHead(refname string) error {
	cname := C.CString(refname)
	defer C.free(unsafe.Pointer(cname))

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ecode := C.git_repository_set_head(v.ptr, cname)
	if ecode != 0 {
		return MakeGitError(ecode)
	}
	return nil
}

func (v *Repository) SetHeadDetached(id *Oid) error {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ecode := C.git_repository_set_head_detached(v.ptr, id.toC())
	if ecode != 0 {
		return MakeGitError(ecode)
	}
	return nil
}

func (v *Repository) IsHeadDetached() (bool, error) {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ret := C.git_repository_head_detached(v.ptr)
	if ret < 0 {
		return false, MakeGitError(ret)
	}

	return ret != 0, nil
}

func (v *Repository) IsHeadUnborn() (bool, error) {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ret := C.git_repository_head_unborn(v.ptr)
	if ret < 0 {
		return false, MakeGitError(ret)
	}
	return ret != 0, nil
}

func (v *Repository) Walk() (*RevWalk, error) {

	var walkPtr *C.git_revwalk

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ecode := C.git_revwalk_new(&walkPtr, v.ptr)
	if ecode < 0 {
		return nil, MakeGitError(ecode)
	}

	return revWalkFromC(v, walkPtr), nil
}

func (v *Repository) CreateCommit(
	refname string, author, committer *Signature,
	message string, tree *Tree, parents ...*Commit) (*Oid, error) {

	oid := new(Oid)

	var cref *C.char
	if refname == "" {
		cref = nil
	} else {
		cref = C.CString(refname)
		defer C.free(unsafe.Pointer(cref))
	}

	cmsg := C.CString(message)
	defer C.free(unsafe.Pointer(cmsg))

	var cparents []*C.git_commit = nil
	var parentsarg **C.git_commit = nil

	nparents := len(parents)
	if nparents > 0 {
		cparents = make([]*C.git_commit, nparents)
		for i, v := range parents {
			cparents[i] = v.cast_ptr
		}
		parentsarg = &cparents[0]
	}

	authorSig, err := author.toC()
	if err != nil {
		return nil, err
	}
	defer C.git_signature_free(authorSig)

	committerSig, err := committer.toC()
	if err != nil {
		return nil, err
	}
	defer C.git_signature_free(committerSig)

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ret := C.git_commit_create(
		oid.toC(), v.ptr, cref,
		authorSig, committerSig,
		nil, cmsg, tree.cast_ptr, C.size_t(nparents), parentsarg)

	if ret < 0 {
		return nil, MakeGitError(ret)
	}

	return oid, nil
}

func (v *Odb) Free() {
	runtime.SetFinalizer(v, nil)
	C.git_odb_free(v.ptr)
}

func (v *Refdb) Free() {
	runtime.SetFinalizer(v, nil)
	C.git_refdb_free(v.ptr)
}

func (v *Repository) Odb() (odb *Odb, err error) {
	odb = new(Odb)

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	if ret := C.git_repository_odb(&odb.ptr, v.ptr); ret < 0 {
		return nil, MakeGitError(ret)
	}

	runtime.SetFinalizer(odb, (*Odb).Free)
	return odb, nil
}

func (repo *Repository) Path() string {
	return C.GoString(C.git_repository_path(repo.ptr))
}

func (repo *Repository) IsBare() bool {
	return C.git_repository_is_bare(repo.ptr) != 0
}

func (repo *Repository) Workdir() string {
	return C.GoString(C.git_repository_workdir(repo.ptr))
}

func (repo *Repository) SetWorkdir(workdir string, updateGitlink bool) error {
	cstr := C.CString(workdir)
	defer C.free(unsafe.Pointer(cstr))

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	if ret := C.git_repository_set_workdir(repo.ptr, cstr, cbool(updateGitlink)); ret < 0 {
		return MakeGitError(ret)
	}

	return nil
}

func (v *Repository) TreeBuilder() (*TreeBuilder, error) {
	bld := new(TreeBuilder)

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	if ret := C.git_treebuilder_new(&bld.ptr, v.ptr, nil); ret < 0 {
		return nil, MakeGitError(ret)
	}
	runtime.SetFinalizer(bld, (*TreeBuilder).Free)

	bld.repo = v
	return bld, nil
}

func (v *Repository) TreeBuilderFromTree(tree *Tree) (*TreeBuilder, error) {
	bld := new(TreeBuilder)

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	if ret := C.git_treebuilder_new(&bld.ptr, v.ptr, tree.cast_ptr); ret < 0 {
		return nil, MakeGitError(ret)
	}
	runtime.SetFinalizer(bld, (*TreeBuilder).Free)

	bld.repo = v
	return bld, nil
}

type RepositoryState int

const (
	RepositoryStateNone                 RepositoryState = C.GIT_REPOSITORY_STATE_NONE
	RepositoryStateMerge                RepositoryState = C.GIT_REPOSITORY_STATE_MERGE
	RepositoryStateRevert               RepositoryState = C.GIT_REPOSITORY_STATE_REVERT
	RepositoryStateCherrypick           RepositoryState = C.GIT_REPOSITORY_STATE_CHERRYPICK
	RepositoryStateBisect               RepositoryState = C.GIT_REPOSITORY_STATE_BISECT
	RepositoryStateRebase               RepositoryState = C.GIT_REPOSITORY_STATE_REBASE
	RepositoryStateRebaseInteractive    RepositoryState = C.GIT_REPOSITORY_STATE_REBASE_INTERACTIVE
	RepositoryStateRebaseMerge          RepositoryState = C.GIT_REPOSITORY_STATE_REBASE_MERGE
	RepositoryStateApplyMailbox         RepositoryState = C.GIT_REPOSITORY_STATE_APPLY_MAILBOX
	RepositoryStateApplyMailboxOrRebase RepositoryState = C.GIT_REPOSITORY_STATE_APPLY_MAILBOX_OR_REBASE
)

func (r *Repository) State() RepositoryState {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	return RepositoryState(C.git_repository_state(r.ptr))
}

func (r *Repository) StateCleanup() error {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	cErr := C.git_repository_state_cleanup(r.ptr)
	if cErr < 0 {
		return MakeGitError(cErr)
	}
	return nil
}
func (r *Repository) AddGitIgnoreRules(rules string) error {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	crules := C.CString(rules)
	defer C.free(unsafe.Pointer(crules))
	if ret := C.git_ignore_add_rule(r.ptr, crules); ret < 0 {
		return MakeGitError(ret)
	}
	return nil
}

func (r *Repository) ClearGitIgnoreRules() error {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	if ret := C.git_ignore_clear_internal_rules(r.ptr); ret < 0 {
		return MakeGitError(ret)
	}
	return nil
}
<commit_msg>Add Repository.IsEmpty<commit_after>package git

/*
#include <git2.h>
#include <git2/sys/repository.h>
*/
import "C"
import (
	"runtime"
	"unsafe"
)

// Repository
type Repository struct {
	ptr *C.git_repository
	// Remotes represents the collection of remotes and can be
	// used to add, remove and configure remotes for this
	// repository.
	Remotes RemoteCollection
	// Submodules represents the collection of submodules and can
	// be used to add, remove and configure submodules in this
	// repostiory.
	Submodules SubmoduleCollection
	// References represents the collection of references and can
	// be used to create, remove or update refernces for this repository.
	References ReferenceCollection
	// Notes represents the collection of notes and can be used to
	// read, write and delete notes from this repository.
	Notes NoteCollection
	// Tags represents the collection of tags and can be used to create,
	// list and iterate tags in this repository.
	Tags TagsCollection
	// Stashes represents the collection of stashes and can be used to
	// save, apply and iterate over stash states in this repository.
	Stashes StashCollection
}

func newRepositoryFromC(ptr *C.git_repository) *Repository {
	repo := &Repository{ptr: ptr}

	repo.Remotes.repo = repo
	repo.Submodules.repo = repo
	repo.References.repo = repo
	repo.Notes.repo = repo
	repo.Tags.repo = repo
	repo.Stashes.repo = repo

	runtime.SetFinalizer(repo, (*Repository).Free)

	return repo
}

func OpenRepository(path string) (*Repository, error) {
	cpath := C.CString(path)
	defer C.free(unsafe.Pointer(cpath))

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	var ptr *C.git_repository
	ret := C.git_repository_open(&ptr, cpath)
	if ret < 0 {
		return nil, MakeGitError(ret)
	}

	return newRepositoryFromC(ptr), nil
}

type RepositoryOpenFlag int

const (
	RepositoryOpenNoSearch RepositoryOpenFlag = C.GIT_REPOSITORY_OPEN_NO_SEARCH
	RepositoryOpenCrossFs  RepositoryOpenFlag = C.GIT_REPOSITORY_OPEN_CROSS_FS
	RepositoryOpenBare     RepositoryOpenFlag = C.GIT_REPOSITORY_OPEN_BARE
)

func OpenRepositoryExtended(path string, flags RepositoryOpenFlag, ceiling string) (*Repository, error) {
	cpath := C.CString(path)
	defer C.free(unsafe.Pointer(cpath))

	var cceiling *C.char = nil
	if len(ceiling) > 0 {
		cceiling = C.CString(ceiling)
		defer C.free(unsafe.Pointer(cceiling))
	}

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	var ptr *C.git_repository
	ret := C.git_repository_open_ext(&ptr, cpath, C.uint(flags), cceiling)
	if ret < 0 {
		return nil, MakeGitError(ret)
	}

	return newRepositoryFromC(ptr), nil
}

func InitRepository(path string, isbare bool) (*Repository, error) {
	cpath := C.CString(path)
	defer C.free(unsafe.Pointer(cpath))

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	var ptr *C.git_repository
	ret := C.git_repository_init(&ptr, cpath, ucbool(isbare))
	if ret < 0 {
		return nil, MakeGitError(ret)
	}

	return newRepositoryFromC(ptr), nil
}

func NewRepositoryWrapOdb(odb *Odb) (repo *Repository, err error) {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	var ptr *C.git_repository
	ret := C.git_repository_wrap_odb(&ptr, odb.ptr)
	if ret < 0 {
		return nil, MakeGitError(ret)
	}

	return newRepositoryFromC(ptr), nil
}

func (v *Repository) SetRefdb(refdb *Refdb) {
	C.git_repository_set_refdb(v.ptr, refdb.ptr)
}

func (v *Repository) Free() {
	runtime.SetFinalizer(v, nil)
	C.git_repository_free(v.ptr)
}

func (v *Repository) Config() (*Config, error) {
	config := new(Config)

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ret := C.git_repository_config(&config.ptr, v.ptr)
	if ret < 0 {
		return nil, MakeGitError(ret)
	}

	runtime.SetFinalizer(config, (*Config).Free)
	return config, nil
}

func (v *Repository) Index() (*Index, error) {
	var ptr *C.git_index

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ret := C.git_repository_index(&ptr, v.ptr)
	if ret < 0 {
		return nil, MakeGitError(ret)
	}

	return newIndexFromC(ptr), nil
}

func (v *Repository) lookupType(id *Oid, t ObjectType) (*Object, error) {
	var ptr *C.git_object

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ret := C.git_object_lookup(&ptr, v.ptr, id.toC(), C.git_otype(t))
	if ret < 0 {
		return nil, MakeGitError(ret)
	}

	return allocObject(ptr, v), nil
}

func (v *Repository) Lookup(id *Oid) (*Object, error) {
	return v.lookupType(id, ObjectAny)
}

func (v *Repository) LookupTree(id *Oid) (*Tree, error) {
	obj, err := v.lookupType(id, ObjectTree)
	if err != nil {
		return nil, err
	}

	return obj.AsTree()
}

func (v *Repository) LookupCommit(id *Oid) (*Commit, error) {
	obj, err := v.lookupType(id, ObjectCommit)
	if err != nil {
		return nil, err
	}

	return obj.AsCommit()
}

func (v *Repository) LookupBlob(id *Oid) (*Blob, error) {
	obj, err := v.lookupType(id, ObjectBlob)
	if err != nil {
		return nil, err
	}

	return obj.AsBlob()
}

func (v *Repository) LookupTag(id *Oid) (*Tag, error) {
	obj, err := v.lookupType(id, ObjectTag)
	if err != nil {
		return nil, err
	}

	return obj.AsTag()
}

func (v *Repository) Head() (*Reference, error) {
	var ptr *C.git_reference

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ecode := C.git_repository_head(&ptr, v.ptr)
	if ecode < 0 {
		return nil, MakeGitError(ecode)
	}

	return newReferenceFromC(ptr, v), nil
}

func (v *Repository) SetHead(refname string) error {
	cname := C.CString(refname)
	defer C.free(unsafe.Pointer(cname))

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ecode := C.git_repository_set_head(v.ptr, cname)
	if ecode != 0 {
		return MakeGitError(ecode)
	}
	return nil
}

func (v *Repository) SetHeadDetached(id *Oid) error {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ecode := C.git_repository_set_head_detached(v.ptr, id.toC())
	if ecode != 0 {
		return MakeGitError(ecode)
	}
	return nil
}

func (v *Repository) IsHeadDetached() (bool, error) {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ret := C.git_repository_head_detached(v.ptr)
	if ret < 0 {
		return false, MakeGitError(ret)
	}

	return ret != 0, nil
}

func (v *Repository) IsHeadUnborn() (bool, error) {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ret := C.git_repository_head_unborn(v.ptr)
	if ret < 0 {
		return false, MakeGitError(ret)
	}
	return ret != 0, nil
}

func (v *Repository) IsEmpty() (bool, error) {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ret := C.git_repository_is_empty(v.ptr)
	if ret < 0 {
		return false, MakeGitError(ret)
	}

	return ret != 0, nil
}

func (v *Repository) Walk() (*RevWalk, error) {

	var walkPtr *C.git_revwalk

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ecode := C.git_revwalk_new(&walkPtr, v.ptr)
	if ecode < 0 {
		return nil, MakeGitError(ecode)
	}

	return revWalkFromC(v, walkPtr), nil
}

func (v *Repository) CreateCommit(
	refname string, author, committer *Signature,
	message string, tree *Tree, parents ...*Commit) (*Oid, error) {

	oid := new(Oid)

	var cref *C.char
	if refname == "" {
		cref = nil
	} else {
		cref = C.CString(refname)
		defer C.free(unsafe.Pointer(cref))
	}

	cmsg := C.CString(message)
	defer C.free(unsafe.Pointer(cmsg))

	var cparents []*C.git_commit = nil
	var parentsarg **C.git_commit = nil

	nparents := len(parents)
	if nparents > 0 {
		cparents = make([]*C.git_commit, nparents)
		for i, v := range parents {
			cparents[i] = v.cast_ptr
		}
		parentsarg = &cparents[0]
	}

	authorSig, err := author.toC()
	if err != nil {
		return nil, err
	}
	defer C.git_signature_free(authorSig)

	committerSig, err := committer.toC()
	if err != nil {
		return nil, err
	}
	defer C.git_signature_free(committerSig)

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ret := C.git_commit_create(
		oid.toC(), v.ptr, cref,
		authorSig, committerSig,
		nil, cmsg, tree.cast_ptr, C.size_t(nparents), parentsarg)

	if ret < 0 {
		return nil, MakeGitError(ret)
	}

	return oid, nil
}

func (v *Odb) Free() {
	runtime.SetFinalizer(v, nil)
	C.git_odb_free(v.ptr)
}

func (v *Refdb) Free() {
	runtime.SetFinalizer(v, nil)
	C.git_refdb_free(v.ptr)
}

func (v *Repository) Odb() (odb *Odb, err error) {
	odb = new(Odb)

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	if ret := C.git_repository_odb(&odb.ptr, v.ptr); ret < 0 {
		return nil, MakeGitError(ret)
	}

	runtime.SetFinalizer(odb, (*Odb).Free)
	return odb, nil
}

func (repo *Repository) Path() string {
	return C.GoString(C.git_repository_path(repo.ptr))
}

func (repo *Repository) IsBare() bool {
	return C.git_repository_is_bare(repo.ptr) != 0
}

func (repo *Repository) Workdir() string {
	return C.GoString(C.git_repository_workdir(repo.ptr))
}

func (repo *Repository) SetWorkdir(workdir string, updateGitlink bool) error {
	cstr := C.CString(workdir)
	defer C.free(unsafe.Pointer(cstr))

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	if ret := C.git_repository_set_workdir(repo.ptr, cstr, cbool(updateGitlink)); ret < 0 {
		return MakeGitError(ret)
	}

	return nil
}

func (v *Repository) TreeBuilder() (*TreeBuilder, error) {
	bld := new(TreeBuilder)

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	if ret := C.git_treebuilder_new(&bld.ptr, v.ptr, nil); ret < 0 {
		return nil, MakeGitError(ret)
	}
	runtime.SetFinalizer(bld, (*TreeBuilder).Free)

	bld.repo = v
	return bld, nil
}

func (v *Repository) TreeBuilderFromTree(tree *Tree) (*TreeBuilder, error) {
	bld := new(TreeBuilder)

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	if ret := C.git_treebuilder_new(&bld.ptr, v.ptr, tree.cast_ptr); ret < 0 {
		return nil, MakeGitError(ret)
	}
	runtime.SetFinalizer(bld, (*TreeBuilder).Free)

	bld.repo = v
	return bld, nil
}

type RepositoryState int

const (
	RepositoryStateNone                 RepositoryState = C.GIT_REPOSITORY_STATE_NONE
	RepositoryStateMerge                RepositoryState = C.GIT_REPOSITORY_STATE_MERGE
	RepositoryStateRevert               RepositoryState = C.GIT_REPOSITORY_STATE_REVERT
	RepositoryStateCherrypick           RepositoryState = C.GIT_REPOSITORY_STATE_CHERRYPICK
	RepositoryStateBisect               RepositoryState = C.GIT_REPOSITORY_STATE_BISECT
	RepositoryStateRebase               RepositoryState = C.GIT_REPOSITORY_STATE_REBASE
	RepositoryStateRebaseInteractive    RepositoryState = C.GIT_REPOSITORY_STATE_REBASE_INTERACTIVE
	RepositoryStateRebaseMerge          RepositoryState = C.GIT_REPOSITORY_STATE_REBASE_MERGE
	RepositoryStateApplyMailbox         RepositoryState = C.GIT_REPOSITORY_STATE_APPLY_MAILBOX
	RepositoryStateApplyMailboxOrRebase RepositoryState = C.GIT_REPOSITORY_STATE_APPLY_MAILBOX_OR_REBASE
)

func (r *Repository) State() RepositoryState {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	return RepositoryState(C.git_repository_state(r.ptr))
}

func (r *Repository) StateCleanup() error {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	cErr := C.git_repository_state_cleanup(r.ptr)
	if cErr < 0 {
		return MakeGitError(cErr)
	}
	return nil
}
func (r *Repository) AddGitIgnoreRules(rules string) error {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	crules := C.CString(rules)
	defer C.free(unsafe.Pointer(crules))
	if ret := C.git_ignore_add_rule(r.ptr, crules); ret < 0 {
		return MakeGitError(ret)
	}
	return nil
}

func (r *Repository) ClearGitIgnoreRules() error {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	if ret := C.git_ignore_clear_internal_rules(r.ptr); ret < 0 {
		return MakeGitError(ret)
	}
	return nil
}
<|endoftext|>