<commit_before>// Copyright 2015 Marc-Antoine Ruel. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.

// pre-commit-go: runs pre-commit checks on Go projects.
package main

import (
	"bytes"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"sort"
	"sync"
	"text/template"
	"time"

	"github.com/maruel/pre-commit-go/checks"
	"gopkg.in/yaml.v2"
)

// Globals

// TODO(maruel): Reimplement this in go instead of processing it in bash.
var preCommitHook = []byte(`#!/bin/sh
# Copyright 2015 Marc-Antoine Ruel. All rights reserved.
# Use of this source code is governed under the Apache License, Version 2.0
# that can be found in the LICENSE file.

# pre-commit git hook to runs presubmit.py on the tree with unstaged changes
# removed.
#
# WARNING: This file was generated by tool "pre-commit-go"

# Redirect output to stderr.
exec 1>&2

run_checks() {
  # Ensure everything is either tracked or ignored. This is because git stash
  # doesn't stash untracked files.
  untracked="$(git ls-files --others --exclude-standard)"
  if [ "$untracked" != "" ]; then
    echo "This check refuses to run if there is an untracked file. Either track"
    echo "it or put it in the .gitignore or your global exclusion list:"
    echo "$untracked"
    return 1
  fi

  # Run the presubmit check.
  pre-commit-go run
  result=$?
  if [ $result != 0 ]; then
    return $result
  fi
}

if git rev-parse --verify HEAD >/dev/null 2>&1
then
  against=HEAD
else
  # Initial commit: diff against an empty tree object
  against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi

# Use a precise "stash, run checks, unstash" to ensure that the check is
# properly run on the data in the index.
# Inspired from
# http://stackoverflow.com/questions/20479794/how-do-i-properly-git-stash-pop-in-pre-commit-hooks-to-get-a-clean-working-tree
# First, stash index and work dir, keeping only the to-be-committed changes in
# the working directory.
old_stash=$(git rev-parse -q --verify refs/stash)
git stash save -q --keep-index
new_stash=$(git rev-parse -q --verify refs/stash)

# If there were no changes (e.g., '--amend' or '--allow-empty') then nothing was
# stashed, and we should skip everything, including the tests themselves.
# (Presumably the tests passed on the previous commit, so there is no need to
# re-run them.)
if [ "$old_stash" = "$new_stash" ]; then
  exit 0
fi

run_checks
result=$?

# Restore changes.
git reset --hard -q && git stash apply --index -q && git stash drop -q
exit $result
`)

var helpText = template.Must(template.New("help").Parse(`pre-commit-go: runs pre-commit checks on Go projects, fast.

Supported commands are:
  help        - this page
  install     - runs 'prereq' then installs the git commit hook as
                .git/hooks/pre-commit
  prereq      - installs prerequisites, e.g.: errcheck, golint, goimports,
                govet, etc as applicable for the enabled checks
  installrun  - runs 'prereq', 'install' then 'run'
  run         - runs all enabled checks
  writeconfig - writes (or rewrite) a pre-commit-go.yml

When executed without command, it does the equivalent of 'installrun'.
Supported flags are:
{{.Usage}}
Supported checks and their runlevel:
  Native checks that only depends on the stdlib:{{range .NativeChecks}}
    - {{printf "%-*s" $.Max .GetName}} : {{.GetDescription}}{{end}}

  Checks that have prerequisites (which will be automatically installed):{{range .OtherChecks}}
    - {{printf "%-*s" $.Max .GetName}} : {{.GetDescription}}{{end}}

No check ever modify any file.
`))

// Commands.

func help(config *checks.Config, usage string) error {
	s := &struct {
		Usage        string
		Max          int
		NativeChecks []checks.Check
		OtherChecks  []checks.Check
	}{
		usage,
		0,
		[]checks.Check{},
		[]checks.Check{},
	}
	for name, c := range checks.KnownChecks {
		if v := len(name); v > s.Max {
			s.Max = v
		}
		if len(c.GetPrerequisites()) == 0 {
			s.NativeChecks = append(s.NativeChecks, c)
		} else {
			s.OtherChecks = append(s.OtherChecks, c)
		}
	}
	return helpText.Execute(os.Stdout, s)
}

// installPrereq installs all the packages needed to run the enabled checks.
func installPrereq(config *checks.Config, r checks.RunLevel) error {
	var wg sync.WaitGroup
	enabledChecks := config.EnabledChecks(r)
	c := make(chan string, len(enabledChecks))
	for _, check := range enabledChecks {
		for _, p := range check.GetPrerequisites() {
			wg.Add(1)
			go func(prereq checks.CheckPrerequisite) {
				defer wg.Done()
				if !prereq.IsPresent() {
					c <- prereq.URL
				}
			}(p)
		}
	}
	wg.Wait()
	loop := true
	// Use a map to remove duplicates.
	m := map[string]bool{}
	for loop {
		select {
		case url := <-c:
			m[url] = true
		default:
			loop = false
		}
	}
	urls := make([]string, 0, len(m))
	for url := range m {
		urls = append(urls, url)
	}
	sort.Strings(urls)
	if len(urls) != 0 {
		fmt.Printf("Installing:\n")
		for _, url := range urls {
			fmt.Printf("  %s\n", url)
		}

		// First try without -u, then with -u. The main reason is golint, which
		// changed its API around go1.3~1.4 time frame. -u slows things down
		// significantly so it's worth trying out without, and people will
		// generally do not like to have things upgraded behind them.
		out, _, err := capture(append([]string{"go", "get"}, urls...)...)
		if len(out) != 0 || err != nil {
			out, _, err = capture(append([]string{"go", "get", "-u"}, urls...)...)
		}
		if len(out) != 0 {
			return fmt.Errorf("prerequisites installation failed: %s", out)
		}
		if err != nil {
			return fmt.Errorf("prerequisites installation failed: %s", err)
		}
	}
	return nil
}

// install first calls installPrereq() then install the .git/hooks/pre-commit hook.
func install(config *checks.Config, r checks.RunLevel) error {
	if err := installPrereq(config, r); err != nil {
		return err
	}
	gitDir, err := getGitDir()
	if err != nil {
		return fmt.Errorf("failed to find .git dir: %s", err)
	}
	// Always remove "pre-commit" first if it exists, in case it's a symlink.
	p := filepath.Join(gitDir, "hooks", "pre-commit")
	_ = os.Remove(p)
	err = ioutil.WriteFile(p, preCommitHook, 0766)
	log.Printf("installation done")
	return err
}

func callRun(check checks.Check) (error, time.Duration) {
	if l, ok := check.(sync.Locker); ok {
		l.Lock()
		defer l.Unlock()
	}
	start := time.Now()
	err := check.Run()
	return err, time.Now().Sub(start)
}

// run runs all the enabled checks.
func run(config *checks.Config, r checks.RunLevel) error {
	start := time.Now()
	enabledChecks := config.EnabledChecks(r)
	var wg sync.WaitGroup
	errs := make(chan error, len(enabledChecks))
	for _, c := range enabledChecks {
		wg.Add(1)
		go func(check checks.Check) {
			defer wg.Done()
			log.Printf("%s...", check.GetName())
			err, duration := callRun(check)
			log.Printf("... %s in %1.2fs", check.GetName(), duration.Seconds())
			if err != nil {
				errs <- err
			}
			// A check that took too long is a check that failed.
			max := config.MaxDuration
			if duration > time.Duration(max)*time.Second {
				errs <- fmt.Errorf("check %s took %1.2fs", check.GetName(), duration.Seconds())
			}
		}(c)
	}
	wg.Wait()

	var err error
	for {
		select {
		case err = <-errs:
			fmt.Printf("%s\n", err)
		default:
			if err != nil {
				duration := time.Now().Sub(start)
				return fmt.Errorf("checks failed in %1.2fs", duration.Seconds())
			}
			return err
		}
	}
}

func writeConfig(config *checks.Config, configPath string) error {
	content, err := yaml.Marshal(config)
	if err != nil {
		return fmt.Errorf("internal error when marshaling config: %s", err)
	}
	_ = os.Remove(configPath)
	out := []byte("# https://github.com/maruel/pre-commit-go configuration file to run checks\n# automatically on commit and pull requests.\n#\n# See https://godoc.org/github.com/maruel/pre-commit-go/checks for more\n# information.\n\n")
	out = append(out, content...)
	return ioutil.WriteFile(configPath, out, 0666)
}

func mainImpl() error {
	cmd := ""
	if len(os.Args) == 1 {
		cmd = "installrun"
	} else {
		cmd = os.Args[1]
		copy(os.Args[1:], os.Args[2:])
		os.Args = os.Args[:len(os.Args)-1]
	}
	verbose := flag.Bool("verbose", false, "enables verbose logging output")
	configPath := flag.String("config", "pre-commit-go.yml", "file name of the config to load")
	runLevelFlag := flag.Int("level", 1, "runlevel, between 0 and 3; the higher, the more tests are run")
	flag.Parse()

	log.SetFlags(log.Lmicroseconds)
	if !*verbose {
		log.SetOutput(ioutil.Discard)
	}

	if *runLevelFlag < 0 || *runLevelFlag > 3 {
		return fmt.Errorf("-level %d is invalid, must be between 0 and 3", *runLevelFlag)
	}
	runLevel := checks.RunLevel(*runLevelFlag)

	// Make the config path relative to the current directory, not the git
	// repository root.
	var err error
	if *configPath, err = filepath.Abs(*configPath); err != nil {
		return err
	}
	if err = chdirToGitRoot(); err != nil {
		return err
	}
	config := checks.GetConfig(*configPath)

	switch cmd {
	case "help", "-help", "-h":
		b := &bytes.Buffer{}
		flag.CommandLine.SetOutput(b)
		flag.CommandLine.PrintDefaults()
		return help(config, b.String())
	case "install", "i":
		return install(config, runLevel)
	case "installrun":
		if err := install(config, runLevel); err != nil {
			return err
		}
		return run(config, runLevel)
	case "prereq", "p":
		return installPrereq(config, runLevel)
	case "run", "r":
		return run(config, runLevel)
	case "writeconfig", "w":
		return writeConfig(config, *configPath)
	default:
		return errors.New("unknown command, try 'help'")
	}
}

func main() {
	if err := mainImpl(); err != nil {
		fmt.Fprintf(os.Stderr, "pre-commit-go: %s\n", err)
		os.Exit(1)
	}
}
<commit_msg>Migrate run() guts into runChecks().<commit_after>// Copyright 2015 Marc-Antoine Ruel. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.

// pre-commit-go: runs pre-commit checks on Go projects.
package main

import (
	"bytes"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"sort"
	"sync"
	"text/template"
	"time"

	"github.com/maruel/pre-commit-go/checks"
	"gopkg.in/yaml.v2"
)

// Globals

// TODO(maruel): Reimplement this in go instead of processing it in bash.
var preCommitHook = []byte(`#!/bin/sh
# Copyright 2015 Marc-Antoine Ruel. All rights reserved.
# Use of this source code is governed under the Apache License, Version 2.0
# that can be found in the LICENSE file.

# pre-commit git hook to runs presubmit.py on the tree with unstaged changes
# removed.
#
# WARNING: This file was generated by tool "pre-commit-go"

# Redirect output to stderr.
exec 1>&2

run_checks() {
  # Ensure everything is either tracked or ignored. This is because git stash
  # doesn't stash untracked files.
  untracked="$(git ls-files --others --exclude-standard)"
  if [ "$untracked" != "" ]; then
    echo "This check refuses to run if there is an untracked file. Either track"
    echo "it or put it in the .gitignore or your global exclusion list:"
    echo "$untracked"
    return 1
  fi

  # Run the presubmit check.
  pre-commit-go run
  result=$?
  if [ $result != 0 ]; then
    return $result
  fi
}

if git rev-parse --verify HEAD >/dev/null 2>&1
then
  against=HEAD
else
  # Initial commit: diff against an empty tree object
  against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi

# Use a precise "stash, run checks, unstash" to ensure that the check is
# properly run on the data in the index.
# Inspired from
# http://stackoverflow.com/questions/20479794/how-do-i-properly-git-stash-pop-in-pre-commit-hooks-to-get-a-clean-working-tree
# First, stash index and work dir, keeping only the to-be-committed changes in
# the working directory.
old_stash=$(git rev-parse -q --verify refs/stash)
git stash save -q --keep-index
new_stash=$(git rev-parse -q --verify refs/stash)

# If there were no changes (e.g., '--amend' or '--allow-empty') then nothing was
# stashed, and we should skip everything, including the tests themselves.
# (Presumably the tests passed on the previous commit, so there is no need to
# re-run them.)
if [ "$old_stash" = "$new_stash" ]; then
  exit 0
fi

run_checks
result=$?

# Restore changes.
git reset --hard -q && git stash apply --index -q && git stash drop -q
exit $result
`)

var helpText = template.Must(template.New("help").Parse(`pre-commit-go: runs pre-commit checks on Go projects, fast.

Supported commands are:
  help        - this page
  install     - runs 'prereq' then installs the git commit hook as
                .git/hooks/pre-commit
  prereq      - installs prerequisites, e.g.: errcheck, golint, goimports,
                govet, etc as applicable for the enabled checks
  installrun  - runs 'prereq', 'install' then 'run'
  run         - runs all enabled checks
  writeconfig - writes (or rewrite) a pre-commit-go.yml

When executed without command, it does the equivalent of 'installrun'.
Supported flags are:
{{.Usage}}
Supported checks and their runlevel:
  Native checks that only depends on the stdlib:{{range .NativeChecks}}
    - {{printf "%-*s" $.Max .GetName}} : {{.GetDescription}}{{end}}

  Checks that have prerequisites (which will be automatically installed):{{range .OtherChecks}}
    - {{printf "%-*s" $.Max .GetName}} : {{.GetDescription}}{{end}}

No check ever modify any file.
`))

// Utils.

func callRun(check checks.Check) (error, time.Duration) {
	if l, ok := check.(sync.Locker); ok {
		l.Lock()
		defer l.Unlock()
	}
	start := time.Now()
	err := check.Run()
	return err, time.Now().Sub(start)
}

func runChecks(config *checks.Config, r checks.RunLevel) error {
	// TODO(maruel): Run checks selectively based on the actual files modified.
	// This should affect checks.goDirs() results by calculating all packages
	// affected via the package import graphs.
	start := time.Now()
	enabledChecks := config.EnabledChecks(r)
	var wg sync.WaitGroup
	errs := make(chan error, len(enabledChecks))
	for _, c := range enabledChecks {
		wg.Add(1)
		go func(check checks.Check) {
			defer wg.Done()
			log.Printf("%s...", check.GetName())
			err, duration := callRun(check)
			log.Printf("... %s in %1.2fs", check.GetName(), duration.Seconds())
			if err != nil {
				errs <- err
			}
			// A check that took too long is a check that failed.
			max := config.MaxDuration
			if duration > time.Duration(max)*time.Second {
				errs <- fmt.Errorf("check %s took %1.2fs", check.GetName(), duration.Seconds())
			}
		}(c)
	}
	wg.Wait()

	var err error
	for {
		select {
		case err = <-errs:
			fmt.Printf("%s\n", err)
		default:
			if err != nil {
				duration := time.Now().Sub(start)
				return fmt.Errorf("checks failed in %1.2fs", duration.Seconds())
			}
			return err
		}
	}
}

// Commands.

func help(config *checks.Config, usage string) error {
	s := &struct {
		Usage        string
		Max          int
		NativeChecks []checks.Check
		OtherChecks  []checks.Check
	}{
		usage,
		0,
		[]checks.Check{},
		[]checks.Check{},
	}
	for name, c := range checks.KnownChecks {
		if v := len(name); v > s.Max {
			s.Max = v
		}
		if len(c.GetPrerequisites()) == 0 {
			s.NativeChecks = append(s.NativeChecks, c)
		} else {
			s.OtherChecks = append(s.OtherChecks, c)
		}
	}
	return helpText.Execute(os.Stdout, s)
}

// installPrereq installs all the packages needed to run the enabled checks.
func installPrereq(config *checks.Config, r checks.RunLevel) error {
	var wg sync.WaitGroup
	enabledChecks := config.EnabledChecks(r)
	c := make(chan string, len(enabledChecks))
	for _, check := range enabledChecks {
		for _, p := range check.GetPrerequisites() {
			wg.Add(1)
			go func(prereq checks.CheckPrerequisite) {
				defer wg.Done()
				if !prereq.IsPresent() {
					c <- prereq.URL
				}
			}(p)
		}
	}
	wg.Wait()
	loop := true
	// Use a map to remove duplicates.
	m := map[string]bool{}
	for loop {
		select {
		case url := <-c:
			m[url] = true
		default:
			loop = false
		}
	}
	urls := make([]string, 0, len(m))
	for url := range m {
		urls = append(urls, url)
	}
	sort.Strings(urls)
	if len(urls) != 0 {
		fmt.Printf("Installing:\n")
		for _, url := range urls {
			fmt.Printf("  %s\n", url)
		}

		// First try without -u, then with -u. The main reason is golint, which
		// changed its API around go1.3~1.4 time frame. -u slows things down
		// significantly so it's worth trying out without, and people will
		// generally do not like to have things upgraded behind them.
		out, _, err := capture(append([]string{"go", "get"}, urls...)...)
		if len(out) != 0 || err != nil {
			out, _, err = capture(append([]string{"go", "get", "-u"}, urls...)...)
		}
		if len(out) != 0 {
			return fmt.Errorf("prerequisites installation failed: %s", out)
		}
		if err != nil {
			return fmt.Errorf("prerequisites installation failed: %s", err)
		}
	}
	return nil
}

// install first calls installPrereq() then install the .git/hooks/pre-commit hook.
func install(config *checks.Config, r checks.RunLevel) error {
	if err := installPrereq(config, r); err != nil {
		return err
	}
	gitDir, err := getGitDir()
	if err != nil {
		return fmt.Errorf("failed to find .git dir: %s", err)
	}
	// Always remove "pre-commit" first if it exists, in case it's a symlink.
	p := filepath.Join(gitDir, "hooks", "pre-commit")
	_ = os.Remove(p)
	err = ioutil.WriteFile(p, preCommitHook, 0766)
	log.Printf("installation done")
	return err
}

// run runs all the enabled checks.
func run(config *checks.Config, r checks.RunLevel) error {
	return runChecks(config, r)
}

func writeConfig(config *checks.Config, configPath string) error {
	content, err := yaml.Marshal(config)
	if err != nil {
		return fmt.Errorf("internal error when marshaling config: %s", err)
	}
	_ = os.Remove(configPath)
	out := []byte("# https://github.com/maruel/pre-commit-go configuration file to run checks\n# automatically on commit and pull requests.\n#\n# See https://godoc.org/github.com/maruel/pre-commit-go/checks for more\n# information.\n\n")
	out = append(out, content...)
	return ioutil.WriteFile(configPath, out, 0666)
}

func mainImpl() error {
	cmd := ""
	if len(os.Args) == 1 {
		cmd = "installrun"
	} else {
		cmd = os.Args[1]
		copy(os.Args[1:], os.Args[2:])
		os.Args = os.Args[:len(os.Args)-1]
	}
	verbose := flag.Bool("verbose", false, "enables verbose logging output")
	configPath := flag.String("config", "pre-commit-go.yml", "file name of the config to load")
	runLevelFlag := flag.Int("level", 1, "runlevel, between 0 and 3; the higher, the more tests are run")
	flag.Parse()

	log.SetFlags(log.Lmicroseconds)
	if !*verbose {
		log.SetOutput(ioutil.Discard)
	}

	if *runLevelFlag < 0 || *runLevelFlag > 3 {
		return fmt.Errorf("-level %d is invalid, must be between 0 and 3", *runLevelFlag)
	}
	runLevel := checks.RunLevel(*runLevelFlag)

	// Make the config path relative to the current directory, not the git
	// repository root.
	var err error
	if *configPath, err = filepath.Abs(*configPath); err != nil {
		return err
	}
	if err = chdirToGitRoot(); err != nil {
		return err
	}
	config := checks.GetConfig(*configPath)

	switch cmd {
	case "help", "-help", "-h":
		b := &bytes.Buffer{}
		flag.CommandLine.SetOutput(b)
		flag.CommandLine.PrintDefaults()
		return help(config, b.String())
	case "install", "i":
		return install(config, runLevel)
	case "installrun":
		if err := install(config, runLevel); err != nil {
			return err
		}
		return run(config, runLevel)
	case "prereq", "p":
		return installPrereq(config, runLevel)
	case "run", "r":
		return run(config, runLevel)
	case "writeconfig", "w":
		return writeConfig(config, *configPath)
	default:
		return errors.New("unknown command, try 'help'")
	}
}

func main() {
	if err := mainImpl(); err != nil {
		fmt.Fprintf(os.Stderr, "pre-commit-go: %s\n", err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/sha256"
	"encoding/hex"
	"flag"
	"fmt"
	"io"
	"log"
	"math/rand"
	"os"
	"path/filepath"
	"syscall"
)

const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"

// FileData type stores information about path, stats and hashsum of a file
type FileData struct {
	name  string // Full path
	hash  []byte // SHA256 checksum
	dev   uint64 // Device ID
	inode uint64 // Inode number
	nlink uint64 // Number of hard links
	mode  uint32 // File permissions
	uid   uint32 // User ID
	gid   uint32 // Group ID
	size  int64  // File size in bytes
}

type FileGroup []*FileData

//var ofg = make(map[string][]*FileData)
var ofg = make(map[string]FileGroup)

func (fg FileGroup) Len() int {
	return len(fg)
}

func (fg FileGroup) Less(i, j int) bool {
	if fg[i].size < fg[j].size {
		return true
	}
	return false
}

func (fg FileGroup) Swap(i, j int) {
	fg[i], fg[j] = fg[j], fg[i]
}

func (fg FileGroup) CalcAllHashes() {
	for _, f := range fg {
		h, err := getFileHash(f.name)
		if err != nil {
			log.Fatal(err)
		}
		f.hash = h
	}
}

func (fg FileGroup) IndexesPerSameHash() map[string][]int {
	imap := make(map[string][]int)
	for i, f := range fg {
		fh := hex.EncodeToString(f.hash)
		imap[fh] = append(imap[fh], i)
	}
	return imap
}

func (fg FileGroup) HardLink(i, j int) error {
	// Make sure new file does not exist
	suffix, _ := getRandStringBytes(8, 16)
	for _, err := os.Stat(fg[j].name + suffix); ; os.IsExist(err) {
		fmt.Println(fg[j].name + suffix)
		suffix, _ = getRandStringBytes(8, 16)
	}
	os.Rename(fg[j].name, fg[j].name+suffix)
	err := os.Link(fg[i].name, fg[j].name)
	if err != nil {
		os.Rename(fg[j].name+suffix, fg[j].name)
		return err
	}
	os.Remove(fg[j].name + suffix)
	return nil
}

// Returns hash sum of a file
func getFileHash(filePath string) ([]byte, error) {
	var result []byte
	file, err := os.Open(filePath)
	if err != nil {
		return result, err
	}
	defer file.Close()

	hash := sha256.New()
	if _, err := io.Copy(hash, file); err != nil {
		return result, err
	}

	return hash.Sum(result), nil
}

func compareFileData(a, b FileData) bool {
	if &a == &b {
		return true
	}
	if a.dev != b.dev || a.uid != b.uid || a.gid != b.gid || a.mode != b.mode {
		return false
	}
	return true
}

func walker(path string, f os.FileInfo, err error) error {
	knownInodes := make(map[uint64]bool)
	if !f.IsDir() {
		fd := FileData{
			name:  path,
			dev:   f.Sys().(*syscall.Stat_t).Dev,
			inode: f.Sys().(*syscall.Stat_t).Ino,
			nlink: f.Sys().(*syscall.Stat_t).Nlink,
			mode:  f.Sys().(*syscall.Stat_t).Mode,
			uid:   f.Sys().(*syscall.Stat_t).Uid,
			gid:   f.Sys().(*syscall.Stat_t).Gid,
			size:  f.Size(),
		}
		//FIXME:Make sure inode and dev are same
		if !knownInodes[fd.inode] {
			knownInodes[fd.inode] = true
			//FIXME: Better key? Concat int?
			key := fmt.Sprintf("%v_%v_%v_%v_%v", fd.dev, fd.mode, fd.uid, fd.gid, fd.size)
			ofg[key] = append(ofg[key], &fd)
		}
	}
	return err
}

// Returns random string with length between min and max
func getRandStringBytes(min, max int) (string, error) {
	if min <= 0 {
		return "", fmt.Errorf("min (%d) <= 0", min)
	}
	if max < min {
		return "", fmt.Errorf("max (%d) < min (%d)", max, min)
	}
	b := make([]byte, rand.Intn(max-min)+min)
	for i := range b {
		b[i] = letterBytes[rand.Intn(len(letterBytes))]
	}
	return string(b), nil
}

func main() {
	flag.Usage = func() {
		log.Printf("Usage: %s [options] DIR\n\n", os.Args[0])
		flag.PrintDefaults()
	}
	log.SetFlags(0)
	flag.Parse()
	if len(flag.Args()) != 1 {
		flag.Usage()
		os.Exit(1)
	}
	dir := flag.Arg(0)
	src, err := os.Stat(dir)
	if err != nil {
		log.Fatal(err)
	}

	if !src.IsDir() {
		log.Fatal("Source is not a directory")
	}

	err = filepath.Walk(dir, walker)
	if err != nil {
		log.Fatal(err)
	}

	// ofg has been grouped by dev, mode, uid, gid and size by walker func
	for key, fg := range ofg {
		fmt.Println(key, fg)
		if fg.Len() > 1 {
			fg.CalcAllHashes()
			for _, hlable := range fg.IndexesPerSameHash() {
				fi := hlable[0]
				test := append(hlable[:0], hlable[1:]...)
				for _, i := range test {
					fg.HardLink(fi, i)
				}
			}
		}
	}
}
<commit_msg>Commented endless loop<commit_after>package main

import (
	"crypto/sha256"
	"encoding/hex"
	"flag"
	"fmt"
	"io"
	"log"
	"math/rand"
	"os"
	"path/filepath"
	"syscall"
)

const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"

// FileData type stores information about path, stats and hashsum of a file
type FileData struct {
	name  string // Full path
	hash  []byte // SHA256 checksum
	dev   uint64 // Device ID
	inode uint64 // Inode number
	nlink uint64 // Number of hard links
	mode  uint32 // File permissions
	uid   uint32 // User ID
	gid   uint32 // Group ID
	size  int64  // File size in bytes
}

type FileGroup []*FileData

//var ofg = make(map[string][]*FileData)
var ofg = make(map[string]FileGroup)

func (fg FileGroup) Len() int {
	return len(fg)
}

func (fg FileGroup) Less(i, j int) bool {
	if fg[i].size < fg[j].size {
		return true
	}
	return false
}

func (fg FileGroup) Swap(i, j int) {
	fg[i], fg[j] = fg[j], fg[i]
}

func (fg FileGroup) CalcAllHashes() {
	for _, f := range fg {
		h, err := getFileHash(f.name)
		if err != nil {
			log.Fatal(err)
		}
		f.hash = h
	}
}

func (fg FileGroup) IndexesPerSameHash() map[string][]int {
	imap := make(map[string][]int)
	for i, f := range fg {
		fh := hex.EncodeToString(f.hash)
		imap[fh] = append(imap[fh], i)
	}
	return imap
}

func (fg FileGroup) HardLink(i, j int) error {
	// Make sure new file does not exist
	suffix, _ := getRandStringBytes(8, 16)
	// FIXME: Endless loop
	// for _, err := os.Stat(fg[j].name + suffix); ; os.IsExist(err) {
	// 	fmt.Println(fg[j].name + suffix)
	// 	suffix, _ = getRandStringBytes(8, 16)
	// }
	os.Rename(fg[j].name, fg[j].name+suffix)
	err := os.Link(fg[i].name, fg[j].name)
	if err != nil {
		os.Rename(fg[j].name+suffix, fg[j].name)
		return err
	}
	os.Remove(fg[j].name + suffix)
	return nil
}

// Returns hash sum of a file
func getFileHash(filePath string) ([]byte, error) {
	var result []byte
	file, err := os.Open(filePath)
	if err != nil {
		return result, err
	}
	defer file.Close()

	hash := sha256.New()
	if _, err := io.Copy(hash, file); err != nil {
		return result, err
	}

	return hash.Sum(result), nil
}

func compareFileData(a, b FileData) bool {
	if &a == &b {
		return true
	}
	if a.dev != b.dev || a.uid != b.uid || a.gid != b.gid || a.mode != b.mode {
		return false
	}
	return true
}

func walker(path string, f os.FileInfo, err error) error {
	knownInodes := make(map[uint64]bool)
	if !f.IsDir() {
		fd := FileData{
			name:  path,
			dev:   f.Sys().(*syscall.Stat_t).Dev,
			inode: f.Sys().(*syscall.Stat_t).Ino,
			nlink: f.Sys().(*syscall.Stat_t).Nlink,
			mode:  f.Sys().(*syscall.Stat_t).Mode,
			uid:   f.Sys().(*syscall.Stat_t).Uid,
			gid:   f.Sys().(*syscall.Stat_t).Gid,
			size:  f.Size(),
		}
		//FIXME:Make sure inode and dev are same
		if !knownInodes[fd.inode] {
			knownInodes[fd.inode] = true
			//FIXME: Better key? Concat int?
			key := fmt.Sprintf("%v_%v_%v_%v_%v", fd.dev, fd.mode, fd.uid, fd.gid, fd.size)
			ofg[key] = append(ofg[key], &fd)
		}
	}
	return err
}

// Returns random string with length between min and max
func getRandStringBytes(min, max int) (string, error) {
	if min <= 0 {
		return "", fmt.Errorf("min (%d) <= 0", min)
	}
	if max < min {
		return "", fmt.Errorf("max (%d) < min (%d)", max, min)
	}
	b := make([]byte, rand.Intn(max-min)+min)
	for i := range b {
		b[i] = letterBytes[rand.Intn(len(letterBytes))]
	}
	return string(b), nil
}

func main() {
	flag.Usage = func() {
		log.Printf("Usage: %s [options] DIR\n\n", os.Args[0])
		flag.PrintDefaults()
	}
	log.SetFlags(0)
	flag.Parse()
	if len(flag.Args()) != 1 {
		flag.Usage()
		os.Exit(1)
	}
	dir := flag.Arg(0)
	src, err := os.Stat(dir)
	if err != nil {
		log.Fatal(err)
	}

	if !src.IsDir() {
		log.Fatal("Source is not a directory")
	}

	err = filepath.Walk(dir, walker)
	if err != nil {
		log.Fatal(err)
	}

	// ofg has been grouped by dev, mode, uid, gid and size by walker func
	for key, fg := range ofg {
		fmt.Println(key, fg)
		if fg.Len() > 1 {
			fg.CalcAllHashes()
			for _, hlable := range fg.IndexesPerSameHash() {
				fi := hlable[0]
				test := append(hlable[:0], hlable[1:]...)
				for _, i := range test {
					fg.HardLink(fi, i)
				}
			}
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"log"
	"os"
	"strings"
	"time"

	"github.com/garyburd/redigo/redis"
)

var c = `{
	"interval": 1,
	"addresses": [
		"redis:6379"
	],
	"metrics": [
		"used_memory"
	]
}`

type configuration struct {
	Interval  int64    `json:"interval"`
	Addresses []string `json:"addresses"`
	Metrics   []string `json:"metrics"`
}

func main() {
	conf := readConfigurations("config.json")
	tickerChannel := time.NewTicker(time.Second * time.Duration(conf.Interval)).C

	for {
		select {
		case <-tickerChannel:
			go info(conf)
		}
	}
}

func ReadConfigurations(fileName string) configuration {
	var conf configuration
	file, _ := os.Open(fileName)
	decoder := json.NewDecoder(file)
	err := decoder.Decode(&conf)
	if err != nil {
		log.Fatalf("Failed to load configuration: %s", err)
	}
	return conf
}

func info(c configuration) {
	// TODO make it multiple addresses
	address := c.Addresses[0]

	connection, err := redis.Dial("tcp", address)
	if err != nil {
		log.Fatalf("Error dialing redis on address %s: %s", address, err)
		return
	}

	reply, err := connection.Do("INFO")
	if err != nil {
		log.Fatalf("Error doing INFO command: %s", err)
		return
	}

	content := fmt.Sprintf("%s", reply)

	for _, line := range strings.Split(content, "\n") {
		if strings.Contains(line, ":") {
			parts := strings.Split(line, ":")
			fmt.Println(parts[0], parts[1])
		}
	}

	fmt.Println(c)
}
<commit_msg>Change visibility of readConfigurations<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"log"
	"os"
	"strings"
	"time"

	"github.com/garyburd/redigo/redis"
)

var c = `{
	"interval": 1,
	"addresses": [
		"redis:6379"
	],
	"metrics": [
		"used_memory"
	]
}`

type configuration struct {
	Interval  int64    `json:"interval"`
	Addresses []string `json:"addresses"`
	Metrics   []string `json:"metrics"`
}

func main() {
	conf := readConfigurations("config.json")
	tickerChannel := time.NewTicker(time.Second * time.Duration(conf.Interval)).C

	for {
		select {
		case <-tickerChannel:
			go info(conf)
		}
	}
}

func readConfigurations(fileName string) configuration {
	var conf configuration
	file, _ := os.Open(fileName)
	decoder := json.NewDecoder(file)
	err := decoder.Decode(&conf)
	if err != nil {
		log.Fatalf("Failed to load configuration: %s", err)
	}
	return conf
}

func info(c configuration) {
	// TODO make it multiple addresses
	address := c.Addresses[0]

	connection, err := redis.Dial("tcp", address)
	if err != nil {
		log.Fatalf("Error dialing redis on address %s: %s", address, err)
		return
	}

	reply, err := connection.Do("INFO")
	if err != nil {
		log.Fatalf("Error doing INFO command: %s", err)
		return
	}

	content := fmt.Sprintf("%s", reply)

	for _, line := range strings.Split(content, "\n") {
		if strings.Contains(line, ":") {
			parts := strings.Split(line, ":")
			fmt.Println(parts[0], parts[1])
		}
	}

	fmt.Println(c)
}
<|endoftext|>


<commit_before>// Copyright 2017 Gavin Chun Jin. All rights reserved.
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.
package main

import (
	"fmt"
	"github.com/erriapo/goping/core"
	"github.com/erriapo/goping/thirdparty"
	"github.com/erriapo/stats"
	"golang.org/x/net/icmp"
	"golang.org/x/net/ipv4"
	"log"
	"net"
	"os"
	"os/signal"
	"time"
)

// A quote by Epictetus
const payload = "First learn the meaning of what you say, and then speak."
const payloadLen = len(payload)
const ipheader = 20
const icmpheader = 8
const payloadAndHeader = payloadLen + ipheader + icmpheader

// milliseconds to pause between sending each ICMP request
const pause = 1

var accountant = stats.NewSink()
var cache = core.NewCache()
var counter = core.NewCounter()
var pingHeading bool

// return the first non empty arg or "unknown"
func choose(option1 string, option2 net.Addr) string {
	if len(option1) != 0 {
		return option1
	}
	if option2 != nil {
		return option2.String()
	}
	return "unknown"
}

func heading(node string) string {
	return fmt.Sprintf("\n--- %[1]s ping statistics ---", node)
}

func nanoToMilli(d time.Duration) float64 {
	return float64(d.Nanoseconds()) / float64(1000000)
}

func main() {
	help, verbose, count, host, cname, iface, err := core.ParseOption(os.Args[1:])
	if help {
		fmt.Fprintf(os.Stderr, "%s", core.Usage)
		os.Exit(2)
	}

	if err != nil {
		fmt.Fprintf(os.Stderr, "Aborted: %v\n", err)
		fmt.Fprintf(os.Stderr, "%s", core.Usage)
		os.Exit(2)
	}

	// It is safe to ignore the error as we will fallback
	// to the supplied Host
	peerHost, _ := cache.Reverse(host)
	if verbose {
		fmt.Printf("Reversed lookup of supplied host = %v\n", peerHost)
		fmt.Printf("CNAME = %v\n", cname)
	}

	// trap CTRL+C
	exitchan := make(chan os.Signal, 1)
	signal.Notify(exitchan, os.Interrupt) // SIGINT
	go func() {
		<-exitchan
		counter.Render(os.Stdout, heading(choose(cname, host)))
		if counter.NeedStatistics() {
			fmt.Printf("%s\n", thirdparty.Format(accountant))
		}
		os.Exit(1)
	}()

	var ifacetarget = net.IPv4zero
	allinterfaces, ifaceerr := core.ScanInterfaces()
	if ifaceerr == nil {
		if verbose {
			fmt.Printf("Scanning interfaces: %v\n", allinterfaces)
		}
		if iface != "0.0.0.0" {
			ip, ok := allinterfaces[iface]
			if ok {
				ifacetarget = ip
			}
		}
	}

	c, err := icmp.ListenPacket("ip4:icmp", ifacetarget.String())
	if err != nil {
		log.Fatal(err)
	}
	defer c.Close()

	var wm icmp.Message
	var wb []byte

	rb := make([]byte, 1500)

	var t1 time.Time
	var peer2 net.Addr
nn:
	for i := 1; i <= int(count); i++ {
		wm = core.NewEcho(payload, i)
		wb, err = wm.Marshal(nil)
		if err != nil {
			log.Fatal(err)
		}
		//t1, _ := time.Parse(time.RFC3339, "2017-06-28T19:55:50+00:00")
		t1 = time.Now().Add(time.Second * 6)
		if err := c.SetDeadline(t1); err != nil {
			fmt.Fprintf(os.Stderr, "Unable to set read & write Deadline.")
			log.Fatal("Unable to continue. Halted")
		}
		time.Sleep(pause * time.Second)
		start := time.Now()
		if _, err := c.WriteTo(wb, host); err != nil {
			fmt.Fprintf(os.Stderr, "%d connect: Network is unreachable\n", i)
			continue nn
		}
		counter.OnSent()

		// TODO we need to loop until we receive an echo reply
		//hh := c.IPv4PacketConn()
		//k, cm, _, errgg := hh.ReadFrom(rb2)
		//fmt.Printf("!!! %v --- %v %v\n", cm, errgg, k)

		n, peer, err := c.ReadFrom(rb)
		if verbose {
			fmt.Printf("peer %v vs host %v\n", peer, host)
		}
		if peer != nil {
			peer2 = peer
		}

		if !pingHeading {
			fmt.Printf("PING %v (%v) %v(%v) bytes of data.\n", choose(cname, peer), host, payloadLen, payloadAndHeader)
			pingHeading = true
		}

		if err != nil {
			fmt.Printf("%v bytes from %v (%v): icmp_seq=%v No response\n", 0, choose(peerHost, host), host, i)
			if verbose {
				fmt.Fprintf(os.Stderr, "\t%+v\n", err)
			}
			continue nn
		}
		elapsed := time.Since(start)

		fmt.Printf("%v bytes from %v (%v): icmp_seq=%v time=%v\n", n, choose(peerHost, host), host.IP, i, elapsed)
		if verbose {
			fmt.Printf("RTT %d ns\n", elapsed.Nanoseconds())
		}

		rm, err := icmp.ParseMessage(1, rb[:n])
		//hder, _ := icmp.ParseIPv4Header(rb[:n])
		//fmt.Printf("REPLY %v -> %v\n", rm, hder)
		if err != nil {
			log.Fatal(err)
		}
		switch rm.Type {
		case ipv4.ICMPTypeEcho:
			if verbose {
				log.Printf("\t%+v; echo", rm)
			}
		case ipv4.ICMPTypeEchoReply:
			counter.OnReception()
			accountant.Push(nanoToMilli(elapsed))
			if verbose {
				log.Printf("\t%+v; echo reply", rm)
			}
		case ipv4.ICMPTypeDestinationUnreachable:
			counter.NoteAnError()
			fmt.Fprintf(os.Stderr, "\tDestination unreachable.\n")
			if verbose {
				log.Printf("%+v;", rm)
			}
		case ipv4.ICMPTypeTimeExceeded:
			counter.NoteAnError()
			fmt.Fprintf(os.Stderr, "\tTime to live exceeded.\n")
			if verbose {
				log.Printf("%+v;", rm)
			}
		default:
			if verbose {
				log.Printf("\tunexpected %+v;", rm)
			}
		}
	}
	counter.Render(os.Stdout, heading(choose(cname, peer2)))
	if counter.NeedStatistics() {
		fmt.Printf("%s\n", thirdparty.Format(accountant))
	}
	os.Exit(0)
}
<commit_msg>Work on #17<commit_after>// Copyright 2017 Gavin Chun Jin. All rights reserved.
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.
package main

import (
	"fmt"
	"github.com/erriapo/goping/core"
	"github.com/erriapo/goping/thirdparty"
	"github.com/erriapo/stats"
	"golang.org/x/net/icmp"
	"golang.org/x/net/ipv4"
	"log"
	"net"
	"os"
	"os/signal"
	"time"
)

// A quote by Epictetus
const payload = "First learn the meaning of what you say, and then speak."
const payloadLen = len(payload)
const ipheader = 20
const icmpheader = 8
const payloadAndHeader = payloadLen + ipheader + icmpheader

// milliseconds to pause between sending each ICMP request
const pause = 1

var accountant = stats.NewSink()
var cache = core.NewCache()
var counter = core.NewCounter()
var pingHeading bool

type Peer struct {
	FQDN string
	IP   string
}

func choosePeer(hostFQDN string, host *net.IPAddr, hostErr error, peerFQDN string, peer net.Addr, peerErr error) Peer {
	if peer != nil {
		if peerErr != nil {
			return Peer{FQDN: peer.String(), IP: peer.String()}
		} else {
			return Peer{FQDN: peerFQDN, IP: peer.String()}
		}
	}

	if host != nil {
		if hostErr != nil {
			return Peer{FQDN: host.String(), IP: host.String()}
		} else {
			return Peer{FQDN: hostFQDN, IP: host.IP.String()}
		}
	}

	return Peer{FQDN: "Unknown", IP: "?.?.?.?"}
}

// return the first non empty arg or "unknown"
func choose(option1 string, option2 net.Addr) string {
	if len(option1) != 0 {
		return option1
	}
	if option2 != nil {
		return option2.String()
	}
	return "Unknown"
}

func heading(node string) string {
	return fmt.Sprintf("\n--- %[1]s ping statistics ---", node)
}

func nanoToMilli(d time.Duration) float64 {
	return float64(d.Nanoseconds()) / float64(1000000)
}

func main() {
	help, verbose, count, host, cname, iface, err := core.ParseOption(os.Args[1:])
	if help {
		fmt.Fprintf(os.Stderr, "%s", core.Usage)
		os.Exit(2)
	}

	if err != nil {
		fmt.Fprintf(os.Stderr, "Aborted: %v\n", err)
		fmt.Fprintf(os.Stderr, "%s", core.Usage)
		os.Exit(2)
	}

	// It is safe to ignore the error as we will fallback
	// to the supplied Host
	suppliedFQDN, suppliedErr := cache.Reverse(host)
	if verbose {
		fmt.Printf("Reversed lookup of supplied host = %v\n", suppliedFQDN)
		fmt.Printf("CNAME = %v\n", cname)
	}

	// trap CTRL+C
	exitchan := make(chan os.Signal, 1)
	signal.Notify(exitchan, os.Interrupt) // SIGINT
	go func() {
		<-exitchan
		counter.Render(os.Stdout, heading(choose(cname, host)))
		if counter.NeedStatistics() {
			fmt.Printf("%s\n", thirdparty.Format(accountant))
		}
		os.Exit(1)
	}()

	var ifacetarget = net.IPv4zero
	allinterfaces, ifaceerr := core.ScanInterfaces()
	if ifaceerr == nil {
		if verbose {
			fmt.Printf("Scanning interfaces: %v\n", allinterfaces)
		}
		if iface != "0.0.0.0" {
			ip, ok := allinterfaces[iface]
			if ok {
				ifacetarget = ip
			}
		}
	}

	c, err := icmp.ListenPacket("ip4:icmp", ifacetarget.String())
	if err != nil {
		log.Fatal(err)
	}
	defer c.Close()

	var wm icmp.Message
	var wb []byte

	rb := make([]byte, 1500)

	var t1 time.Time
	var peer2 net.Addr
	var peer2FQDN string
	var peer2err error

	//g := choosePeer("", nil, nil, "", nil, nil)
	//fmt.Printf("g: %v %T\n", g, g)

nn:
	for i := 1; i <= int(count); i++ {
		wm = core.NewEcho(payload, i)
		wb, err = wm.Marshal(nil)
		if err != nil {
			log.Fatal(err)
		}
		//t1, _ := time.Parse(time.RFC3339, "2017-06-28T19:55:50+00:00")
		t1 = time.Now().Add(time.Second * 6)
		if err := c.SetDeadline(t1); err != nil {
			fmt.Fprintf(os.Stderr, "Unable to set read & write Deadline.")
			log.Fatal("Unable to continue. Halted")
		}
		time.Sleep(pause * time.Second)
		start := time.Now()
		if _, err := c.WriteTo(wb, host); err != nil {
			fmt.Fprintf(os.Stderr, "%d connect: Network is unreachable\n", i)
			continue nn
		}
		counter.OnSent()

		// TODO we need to loop until we receive an echo reply
		//hh := c.IPv4PacketConn()
		//k, cm, _, errgg := hh.ReadFrom(rb2)
		//fmt.Printf("!!! %v --- %v %v\n", cm, errgg, k)

		n, peer, err := c.ReadFrom(rb)
		if verbose {
			fmt.Printf("peer %v vs host %v\n", peer, host)
		}
		if peer != nil {
			peer2 = peer
		}

		if !pingHeading {
			fmt.Printf("PING %v (%v) %v(%v) bytes of data.\n", choose(cname, peer), host, payloadLen, payloadAndHeader)
			pingHeading = true
		}

		if err != nil {
			fmt.Printf("%v bytes from %v (%v): icmp_seq=%v No response\n", 0, choose(suppliedFQDN, host), host, i)
			if verbose {
				fmt.Fprintf(os.Stderr, "\t%+v\n", err)
			}
			continue nn
		}
		elapsed := time.Since(start)

		peer2FQDN, peer2err = cache.Reverse(peer2)
		h := choosePeer(suppliedFQDN, host, suppliedErr, peer2FQDN, peer2, peer2err)
		if verbose {
			fmt.Printf("choosePeer() returned %v\n", h)
		}
		fmt.Printf("%v bytes from %v (%v): icmp_seq=%v time=%v\n", n, h.FQDN, h.IP, i, elapsed)
		if verbose {
			fmt.Printf("RTT %d ns\n", elapsed.Nanoseconds())
		}

		rm, err := icmp.ParseMessage(1, rb[:n])
		//hder, _ := icmp.ParseIPv4Header(rb[:n])
		//fmt.Printf("REPLY %v -> %v\n", rm, hder)
		if err != nil {
			log.Fatal(err)
		}
		switch rm.Type {
		case ipv4.ICMPTypeEcho:
			if verbose {
				log.Printf("\t%+v; echo", rm)
			}
		case ipv4.ICMPTypeEchoReply:
			counter.OnReception()
			accountant.Push(nanoToMilli(elapsed))
			if verbose {
				log.Printf("\t%+v; echo reply", rm)
			}
		case ipv4.ICMPTypeDestinationUnreachable:
			counter.NoteAnError()
			fmt.Fprintf(os.Stderr, "\tDestination unreachable.\n")
			if verbose {
				log.Printf("%+v;", rm)
			}
		case ipv4.ICMPTypeTimeExceeded:
			counter.NoteAnError()
			fmt.Fprintf(os.Stderr, "\tTime to live exceeded.\n")
			if verbose {
				log.Printf("%+v;", rm)
			}
		default:
			if verbose {
				log.Printf("\tunexpected %+v;", rm)
			}
		}
	}
	counter.Render(os.Stdout, heading(choose(cname, peer2)))
	if counter.NeedStatistics() {
		fmt.Printf("%s\n", thirdparty.Format(accountant))
	}
	os.Exit(0)
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"os/exec"
	"strings"
)

var (
	minWeight = flag.Int("min_occurence", 3, "minimum concurrent edit occurence")
)

func main() {
	flag.Parse()

	lstree, err := exec.Command("git", "ls-tree", "-r", "HEAD", "--name-only").Output()
	if err != nil {
		panic(err)
	}

	tree := make(map[string]bool)
	for _, v := range strings.Split(strings.TrimSpace(string(lstree)), "\n") {
		tree[v] = true
	}

	log := exec.Command("git", "log", "--name-only")

	out, err := log.StdoutPipe()
	if err != nil {
		panic(err)
	}

	br := bufio.NewReader(out)

	var (
		commitID  string
		inHeaders bool
	)

	commits := make(map[string][]string)

	go func() {
		for {
			l, err := br.ReadString('\n')

			if err == io.EOF {
				break
			} else if err != nil {
				panic(err)
			}

			l = strings.TrimRight(l, "\r\n")

			if strings.HasPrefix(l, "commit ") {
				commitID = strings.TrimPrefix(l, "commit ")
				inHeaders = true

				continue
			}

			if l == "" {
				inHeaders = false

				continue
			}

			if !strings.HasPrefix(l, "    ") && !inHeaders {
				if tree[l] {
					commits[commitID] = append(commits[commitID], l)
				}
			}
		}
	}()

	if err := log.Run(); err != nil {
		panic(err)
	}

	files := make(map[string]map[string]int)

	max := 0

	for _, v := range commits {
		for _, f1 := range v {
			if _, ok := files[f1]; !ok {
				files[f1] = make(map[string]int)
			}

			for _, f2 := range v {
				if f1 == f2 {
					continue
				}

				files[f1][f2] = files[f1][f2] + 1

				if files[f1][f2] > max {
					max = files[f1][f2]
				}
			}
		}
	}

	fmt.Printf("graph G {\n")

	done := make(map[[2]string]bool)

	for f1, v := range files {
		for f2, c := range v {
			if done[[2]string{f2, f1}] {
				continue
			}

			done[[2]string{f1, f2}] = true

			if c >= *minWeight {
				fmt.Printf("  %q -- %q [weight=%d penwidth=%f]\n", f1, f2, c, float32(c)/float32(max)*10)
			}
		}
	}

	fmt.Printf("}\n")
}
<commit_msg>add flag for maximum edge width<commit_after>package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"os/exec"
	"strings"
)

var (
	minOccurence = flag.Int("min_occurence", 3, "minimum concurrent edit occurence")
	maxWidth     = flag.Int("max_width", 10, "maximum line width for edges")
)

func main() {
	flag.Parse()

	lstree, err := exec.Command("git", "ls-tree", "-r", "HEAD", "--name-only").Output()
	if err != nil {
		panic(err)
	}

	tree := make(map[string]bool)
	for _, v := range strings.Split(strings.TrimSpace(string(lstree)), "\n") {
		tree[v] = true
	}

	log := exec.Command("git", "log", "--name-only")

	out, err := log.StdoutPipe()
	if err != nil {
		panic(err)
	}

	br := bufio.NewReader(out)

	var (
		commitID  string
		inHeaders bool
	)

	commits := make(map[string][]string)

	go func() {
		for {
			l, err := br.ReadString('\n')

			if err == io.EOF {
				break
			} else if err != nil {
				panic(err)
			}

			l = strings.TrimRight(l, "\r\n")

			if strings.HasPrefix(l, "commit ") {
				commitID = strings.TrimPrefix(l, "commit ")
				inHeaders = true

				continue
			}

			if l == "" {
				inHeaders = false

				continue
			}

			if !strings.HasPrefix(l, "    ") && !inHeaders {
				if tree[l] {
					commits[commitID] = append(commits[commitID], l)
				}
			}
		}
	}()

	if err := log.Run(); err != nil {
		panic(err)
	}

	files := make(map[string]map[string]int)

	max := 0

	for _, v := range commits {
		for _, f1 := range v {
			if _, ok := files[f1]; !ok {
				files[f1] = make(map[string]int)
			}

			for _, f2 := range v {
				if f1 == f2 {
					continue
				}

				files[f1][f2] = files[f1][f2] + 1

				if files[f1][f2] > max {
					max = files[f1][f2]
				}
			}
		}
	}

	fmt.Printf("graph G {\n")

	done := make(map[[2]string]bool)

	for f1, v := range files {
		for f2, c := range v {
			if done[[2]string{f2, f1}] {
				continue
			}

			done[[2]string{f1, f2}] = true

			if c >= *minOccurence {
				fmt.Printf("  %q -- %q [weight=%d penwidth=%f]\n", f1, f2, c, float32(c)/float32(max)*float32(*maxWidth))
			}
		}
	}

	fmt.Printf("}\n")
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"net/http"
	_ "net/http/pprof"
	"time"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"github.com/prometheus/common/log"
	"github.com/prometheus/common/version"

	"github.com/prometheus/snmp_exporter/config"
)

var (
	configFile = flag.String(
		"config.file", "snmp.yml",
		"Path to configuration file.",
	)
	listenAddress = flag.String(
		"web.listen-address", ":9116",
		"Address to listen on for web interface and telemetry.",
	)

	// Metrics about the SNMP exporter itself.
	snmpDuration = prometheus.NewSummaryVec(
		prometheus.SummaryOpts{
			Name: "snmp_collection_duration_seconds",
			Help: "Duration of collections by the SNMP exporter",
		},
		[]string{"module"},
	)
	snmpRequestErrors = prometheus.NewCounter(
		prometheus.CounterOpts{
			Name: "snmp_request_errors_total",
			Help: "Errors in requests to the SNMP exporter",
		},
	)
)

func init() {
	prometheus.MustRegister(snmpDuration)
	prometheus.MustRegister(snmpRequestErrors)
	prometheus.MustRegister(version.NewCollector("snmp_exporter"))
}

func handler(w http.ResponseWriter, r *http.Request) {
	cfg, err := config.LoadFile(*configFile)
	if err != nil {
		msg := fmt.Sprintf("Error parsing config file: %s", err)
		http.Error(w, msg, 400)
		log.Errorf(msg)
		return
	}

	target := r.URL.Query().Get("target")
	if target == "" {
		http.Error(w, "'target' parameter must be specified", 400)
		snmpRequestErrors.Inc()
		return
	}
	moduleName := r.URL.Query().Get("module")
	if moduleName == "" {
		moduleName = "default"
	}
	module, ok := (*cfg)[moduleName]
	if !ok {
		http.Error(w, fmt.Sprintf("Unkown module '%s'", moduleName), 400)
		snmpRequestErrors.Inc()
		return
	}
	log.Debugf("Scraping target '%s' with module '%s'", target, moduleName)

	start := time.Now()
	registry := prometheus.NewRegistry()
	collector := collector{target: target, module: module}
	registry.MustRegister(collector)
	// Delegate http serving to Promethues client library, which will call collector.Collect.
	h := promhttp.HandlerFor(registry, promhttp.HandlerOpts{})
	h.ServeHTTP(w, r)
	duration := float64(time.Since(start).Seconds())
	snmpDuration.WithLabelValues(moduleName).Observe(duration)
	log.Debugf("Scrape of target '%s' with module '%s' took %f seconds", target, moduleName, duration)
}

func main() {
	flag.Parse()

	log.Infoln("Starting snmp exporter", version.Info())
	log.Infoln("Build context", version.BuildContext())

	// Bail early if the config is bad.
	c, err := config.LoadFile(*configFile)
	if err != nil {
		log.Fatalf("Error parsing config file: %s", err)
	}
	// Initilise metrics.
	for module, _ := range *c {
		snmpDuration.WithLabelValues(module)
	}

	http.Handle("/metrics", promhttp.Handler()) // Normal metrics endpoint for SNMP exporter itself.
	http.HandleFunc("/snmp", handler)           // Endpoint to do SNMP scrapes.
	log.Infof("Listening on %s", *listenAddress)
	log.Fatal(http.ListenAndServe(*listenAddress, nil))
}
<commit_msg>Add -version argument to the CLI (#110)<commit_after>package main

import (
	"flag"
	"fmt"
	"net/http"
	_ "net/http/pprof"
	"os"
	"time"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"github.com/prometheus/common/log"
	"github.com/prometheus/common/version"

	"github.com/prometheus/snmp_exporter/config"
)

var (
	showVersion = flag.Bool("version", false, "Print version information.")
	configFile  = flag.String(
		"config.file", "snmp.yml",
		"Path to configuration file.",
	)
	listenAddress = flag.String(
		"web.listen-address", ":9116",
		"Address to listen on for web interface and telemetry.",
	)

	// Metrics about the SNMP exporter itself.
	snmpDuration = prometheus.NewSummaryVec(
		prometheus.SummaryOpts{
			Name: "snmp_collection_duration_seconds",
			Help: "Duration of collections by the SNMP exporter",
		},
		[]string{"module"},
	)
	snmpRequestErrors = prometheus.NewCounter(
		prometheus.CounterOpts{
			Name: "snmp_request_errors_total",
			Help: "Errors in requests to the SNMP exporter",
		},
	)
)

func init() {
	prometheus.MustRegister(snmpDuration)
	prometheus.MustRegister(snmpRequestErrors)
	prometheus.MustRegister(version.NewCollector("snmp_exporter"))
}

func handler(w http.ResponseWriter, r *http.Request) {
	cfg, err := config.LoadFile(*configFile)
	if err != nil {
		msg := fmt.Sprintf("Error parsing config file: %s", err)
		http.Error(w, msg, 400)
		log.Errorf(msg)
		return
	}

	target := r.URL.Query().Get("target")
	if target == "" {
		http.Error(w, "'target' parameter must be specified", 400)
		snmpRequestErrors.Inc()
		return
	}
	moduleName := r.URL.Query().Get("module")
	if moduleName == "" {
		moduleName = "default"
	}
	module, ok := (*cfg)[moduleName]
	if !ok {
		http.Error(w, fmt.Sprintf("Unkown module '%s'", moduleName), 400)
		snmpRequestErrors.Inc()
		return
	}
	log.Debugf("Scraping target '%s' with module '%s'", target, moduleName)

	start := time.Now()
	registry := prometheus.NewRegistry()
	collector := collector{target: target, module: module}
	registry.MustRegister(collector)
	// Delegate http serving to Promethues client library, which will call collector.Collect.
	h := promhttp.HandlerFor(registry, promhttp.HandlerOpts{})
	h.ServeHTTP(w, r)
	duration := float64(time.Since(start).Seconds())
	snmpDuration.WithLabelValues(moduleName).Observe(duration)
	log.Debugf("Scrape of target '%s' with module '%s' took %f seconds", target, moduleName, duration)
}

func main() {
	flag.Parse()

	if *showVersion {
		fmt.Fprintln(os.Stdout, version.Print("snmp_exporter"))
		os.Exit(0)
	}

	log.Infoln("Starting snmp exporter", version.Info())
	log.Infoln("Build context", version.BuildContext())

	// Bail early if the config is bad.
	c, err := config.LoadFile(*configFile)
	if err != nil {
		log.Fatalf("Error parsing config file: %s", err)
	}
	// Initilise metrics.
	for module, _ := range *c {
		snmpDuration.WithLabelValues(module)
	}

	http.Handle("/metrics", promhttp.Handler()) // Normal metrics endpoint for SNMP exporter itself.
	http.HandleFunc("/snmp", handler)           // Endpoint to do SNMP scrapes.
	log.Infof("Listening on %s", *listenAddress)
	log.Fatal(http.ListenAndServe(*listenAddress, nil))
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"os"

	"github.com/scriptnull/badgeit/common"
	"github.com/scriptnull/badgeit/contracts"
	"github.com/scriptnull/badgeit/formatters"
)

func main() {
	// Parse Flags
	fFlag := flag.String("f", "all", "Format for arranging the badges.")
	dFlag := flag.String("d", " ", "Delimiter to be used.")
	flag.Parse()

	// Obtain destination path, if not found, it will be cwd
	args := flag.Args()
	path, err := os.Getwd()
	if len(args) != 0 && len(args[0]) > 0 {
		path = args[0]
	}

	// Check Contract aggreement and obtain eligible badges
	var badges []common.Badge

	npmBadges, err := contracts.NewNpmBadgeContract(path).Badges()
	if err == nil {
		badges = append(badges, npmBadges...)
	}

	// Get Suitable Formatter
	formatter, err := formatters.NewFormatter(
		formatters.FormatterOption{
			Badges:    badges,
			Delimiter: *dFlag,
			Type:      *fFlag,
		},
	)
	if err != nil {
		fmt.Fprint(os.Stderr, "Invalid -f option.")
	}

	result := formatter.Format()
	fmt.Fprintf(os.Stdout, "%s\n", result)
	os.Exit(0)
}
<commit_msg>adds version flag<commit_after>package main

import (
	"flag"
	"fmt"
	"os"

	"github.com/scriptnull/badgeit/common"
	"github.com/scriptnull/badgeit/contracts"
	"github.com/scriptnull/badgeit/formatters"
)

const VERSION = "0.1.0"

func main() {
	// Parse Flags
	fFlag := flag.String("f", "all", "Format for arranging the badges.")
	dFlag := flag.String("d", " ", "Delimiter to be used.")
	vFlag := flag.Bool("v", false, "Version information.")
	flag.Parse()

	if *vFlag {
		fmt.Println("badgeit version: " + VERSION)
		os.Exit(0)
	}
	// Obtain destination path, if not found, it will be cwd
	args := flag.Args()
	path, err := os.Getwd()
	if len(args) != 0 && len(args[0]) > 0 {
		path = args[0]
	}

	// Check Contract aggreement and obtain eligible badges
	var badges []common.Badge

	npmBadges, err := contracts.NewNpmBadgeContract(path).Badges()
	if err == nil {
		badges = append(badges, npmBadges...)
	}

	// Get Suitable Formatter
	formatter, err := formatters.NewFormatter(
		formatters.FormatterOption{
			Badges:    badges,
			Delimiter: *dFlag,
			Type:      *fFlag,
		},
	)
	if err != nil {
		fmt.Fprint(os.Stderr, "Invalid -f option.")
	}

	result := formatter.Format()
	fmt.Fprintf(os.Stdout, "%s\n", result)
	os.Exit(0)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"os"

	"gopkg.in/yaml.v2"
)

func readConfig(path string) (Config, error) {
	b, err := ioutil.ReadFile(path)
	if err != nil {
		return Config{}, err
	}

	var res Config
	err = yaml.Unmarshal(b, &res)
	return res, err

}

func main() {
	cfg, err := readConfig("example.yaml")
	if err != nil {
		panic(err)
	}
	fmt.Printf("%+v\n", cfg) // DEBUG

	rules, err := GenerateRules(cfg)
	if err != nil {
		panic(err)
	}

	err = DefaultXMLExporter().MarshalEntries(cfg.Author, rules, os.Stdout)
	if err != nil {
		panic(err)
	}
}
<commit_msg>polish main<commit_after>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"strings"

	"gopkg.in/yaml.v2"
)

func readConfig(path string) (Config, error) {
	b, err := ioutil.ReadFile(path)
	if err != nil {
		return Config{}, err
	}

	var res Config
	err = yaml.Unmarshal(b, &res)
	return res, err

}

func fatal(format string, a ...interface{}) {
	fmt.Fprintf(os.Stderr, format, a...)
	if !strings.HasSuffix(format, "\n") {
		// Add newline
		fmt.Fprintln(os.Stderr, "")
	}
	os.Exit(1)
}

func main() {
	flag.Parse()
	if flag.NArg() < 1 {
		fatal("usage: %s <config-file>", os.Args[0])
	}
	cfg, err := readConfig("example.yaml")
	if err != nil {
		fatal("error in config parse: %s", err)
	}

	rules, err := GenerateRules(cfg)
	if err != nil {
		fatal("error generating rules: %s", err)
	}

	err = DefaultXMLExporter().MarshalEntries(cfg.Author, rules, os.Stdout)
	if err != nil {
		fatal("error exporting to XML: %s", err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"

	"github.com/FiloSottile/zcash-mini/zcash"
)

var logo = `

             :88SX@888@@X8:
          %%Xt%tt%SSSSS:XXXt@@
        @S;;tt%%%t    ;;::XXXXSX
      .t:::;;%8888    88888tXXXX8;
     .%...:::8             8::XXX%;
     8888...:t888888X     8t;;::XX8
    %888888...:::;:8    :Xttt;;;::X@
    888888888...:St    8:%%tttt;;;:X
    88888888888S8    :%;ttt%%tttt;;X
    %888888888%t    8S:;;;tt%%%ttt;8
     8t8888888     S8888888Stt%%%t@
     .@tt888@              8;;ttt@;
      .8ttt8@SSSSS    SXXXX%:;;;X;
        X8ttt8888%    %88...::X8
          %8@tt88;8888%8888%8X
             :@888@XXX@888:

                    _       _
          _ __ ___ (_)_ __ (_)
         | '_ \ _ \| | '_ \| |
         | | | | | | | | | | |
         |_| |_| |_|_|_| |_|_|
`

var template = `%s

###############################################################
#
#  Here is your new z-address
#
#      %s
#
#  and here is the secret key
#
#      %s
#
#  and here is the viewing key (not yet supported by the full node)
#
#      %s
#
#  KEEP IT SAFE, IT HAS NOT BEEN SAVED ANYWHERE
#
#  To spend, import it with
#
#      zcash-cli z_importkey KEY rescan
#
###############################################################

`

func main() {
	simpleMode := flag.Bool("simple", false, "output only address and key")
	flag.Parse()

	rawKey := zcash.GenerateKey()
	rawAddr, err := zcash.KeyToAddress(rawKey)
	if err != nil {
		log.Fatal(err)
	}
	rawViewKey, err := zcash.KeyToViewingKey(rawKey)
	if err != nil {
		log.Fatal(err)
	}
	key := zcash.Base58Encode(rawKey, zcash.ProdSpendingKey)
	addr := zcash.Base58Encode(rawAddr, zcash.ProdAddress)
	viewKey := zcash.Base58Encode(rawViewKey, zcash.ProdViewingKey)

	if *simpleMode {
		fmt.Printf("%s\n%s\n", addr, key)
	} else {
		fmt.Printf(template, logo, addr, key, viewKey)
	}
}
<commit_msg>Adding vanity prefix searches<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"strings"

	"github.com/FiloSottile/zcash-mini/zcash"
)

var logo = `

             :88SX@888@@X8:
          %%Xt%tt%SSSSS:XXXt@@
        @S;;tt%%%t    ;;::XXXXSX
      .t:::;;%8888    88888tXXXX8;
     .%...:::8             8::XXX%;
     8888...:t888888X     8t;;::XX8
    %888888...:::;:8    :Xttt;;;::X@
    888888888...:St    8:%%tttt;;;:X
    88888888888S8    :%;ttt%%tttt;;X
    %888888888%t    8S:;;;tt%%%ttt;8
     8t8888888     S8888888Stt%%%t@
     .@tt888@              8;;ttt@;
      .8ttt8@SSSSS    SXXXX%:;;;X;
        X8ttt8888%    %88...::X8
          %8@tt88;8888%8888%8X
             :@888@XXX@888:

                    _       _
          _ __ ___ (_)_ __ (_)
         | '_ \ _ \| | '_ \| |
         | | | | | | | | | | |
         |_| |_| |_|_|_| |_|_|
`

var template = `%s

###############################################################
#
#  Here is your new z-address
#
#      %s
#
#  and here is the secret key
#
#      %s
#
#  and here is the viewing key (not yet supported by the full node)
#
#      %s
#
#  KEEP IT SAFE, IT HAS NOT BEEN SAVED ANYWHERE
#
#  To spend, import it with
#
#      zcash-cli z_importkey KEY rescan
#
###############################################################

`

func main() {
	simpleMode   := flag.Bool("simple", false, "output only address and key")
	vanityPrefix := flag.String("prefix", "", "search for an address with a given prefix")
	flag.Parse()

	var key, addr, viewKey string

	for {
		rawKey := zcash.GenerateKey()
		rawAddr, err := zcash.KeyToAddress(rawKey)
		if err != nil {
			log.Fatal(err)
		}
		rawViewKey, err := zcash.KeyToViewingKey(rawKey)
		if err != nil {
			log.Fatal(err)
		}
		key = zcash.Base58Encode(rawKey, zcash.ProdSpendingKey)
		addr = zcash.Base58Encode(rawAddr, zcash.ProdAddress)
		viewKey = zcash.Base58Encode(rawViewKey, zcash.ProdViewingKey)

		if *vanityPrefix != "" {
			if strings.HasPrefix(addr, *vanityPrefix) {
				break
			}

			continue
		}

		break
	}

	if *simpleMode {
		fmt.Printf("%s\n%s\n", addr, key)
	} else {
		fmt.Printf(template, logo, addr, key, viewKey)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"
	"strings"

	"github.com/bradfitz/http2"
	"github.com/xyproto/textgui"
)

const version_string = "http2check 0.2"

func msg(o *textgui.TextOutput, subject, msg string, extra ...string) {
	if len(extra) == 0 {
		o.Println(fmt.Sprintf("%s%s%s %s", o.DarkGray("["), o.LightBlue(subject), o.DarkGray("]"), msg))
	} else {
		o.Println(fmt.Sprintf("%s%s%s %s (%s)", o.DarkGray("["), o.LightBlue(subject), o.DarkGray("]"), msg, extra[0]))
	}
}

func main() {
	o := textgui.NewTextOutput(true, true)

	// Silence the http2 logging
	devnull, err := os.OpenFile("/dev/null", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
	if err != nil {
		o.ErrExit("Could not open /dev/null for writing")
	}
	defer devnull.Close()
	log.SetOutput(devnull)

	// Flags

	version_help := "Show application name and version"
	quiet_help := "Don't write to standard out"

	version := flag.Bool("version", false, version_help)
	quiet := flag.Bool("q", false, quiet_help)

	flag.Usage = func() {
		fmt.Println()
		fmt.Println(version_string)
		fmt.Println("Check if a given webserver is using HTTP/2")
		fmt.Println()
		fmt.Println("Syntax: http2check [URI]")
		fmt.Println()
		fmt.Println("Possible flags:")
		fmt.Println("    --version                  " + version_help)
		fmt.Println("    --q                        " + quiet_help)
		fmt.Println("    --help                     This text")
		fmt.Println()
	}

	flag.Parse()

	// Use the flags and arguments

	o = textgui.NewTextOutput(true, !*quiet)

	args := flag.Args()

	if *version {
		o.Println(version_string)
		os.Exit(0)
	}

	// Default URL

	url := "https://http2.golang.org"
	if len(args) > 0 {
		url = args[0]
	}
	if !strings.Contains(url, "://") {
		url = "https://" + url
	}

	// Display the URL that is to be checked

	o.Println(o.DarkGray("GET") + " " + o.LightCyan(url))

	// GET over HTTP/2

	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		o.ErrExit(err.Error())
	}
	rt := &http2.Transport{
		InsecureTLSDial: true,
	}
	res, err := rt.RoundTrip(req)
	if err != nil {
		errorMessage := strings.TrimSpace(err.Error())
		if errorMessage == "bad protocol:" {
			msg(o, "protocol", o.DarkRed("Not HTTP/2"), errorMessage)
		} else if errorMessage == "http2: unsupported scheme and no Fallback" {
			msg(o, "HTTP/2", o.DarkRed("Not supported"))
		} else if strings.HasPrefix(errorMessage, "dial tcp") && strings.HasSuffix(errorMessage, ": connection refused") {
			msg(o, "host", o.DarkRed("Down"), errorMessage)
		} else if strings.HasPrefix(errorMessage, "tls: oversized record received with length ") {
			msg(o, "protocol", o.DarkRed("No HTTPS support"), errorMessage)
		} else {
			o.ErrExit(errorMessage)
		}
		os.Exit(1)
	}

	// Final output

	msg(o, "protocol", o.White(res.Proto))
	msg(o, "status", o.White(res.Status))
}
<commit_msg>Minor changes<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"
	"strings"

	"github.com/bradfitz/http2"
	"github.com/xyproto/textgui"
)

const version_string = "http2check 0.3"

// Message with an optional additional string that will appear in paranthesis
func msg(o *textgui.TextOutput, subject, msg string, extra ...string) {
	if len(extra) == 0 {
		o.Println(fmt.Sprintf("%s%s%s %s", o.DarkGray("["), o.LightBlue(subject), o.DarkGray("]"), msg))
	} else {
		o.Println(fmt.Sprintf("%s%s%s %s (%s)", o.DarkGray("["), o.LightBlue(subject), o.DarkGray("]"), msg, extra[0]))
	}
}

func main() {
	o := textgui.NewTextOutput(true, true)

	// Silence the http2 logging
	devnull, err := os.OpenFile("/dev/null", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
	if err != nil {
		o.ErrExit("Could not open /dev/null for writing")
	}
	defer devnull.Close()
	log.SetOutput(devnull)

	// Flags

	version_help := "Show application name and version"
	quiet_help := "Don't write to standard out"

	version := flag.Bool("version", false, version_help)
	quiet := flag.Bool("q", false, quiet_help)

	flag.Usage = func() {
		fmt.Println()
		fmt.Println(version_string)
		fmt.Println("Check if a given webserver is using HTTP/2")
		fmt.Println()
		fmt.Println("Syntax: http2check [URI]")
		fmt.Println()
		fmt.Println("Possible flags:")
		fmt.Println("    --version                  " + version_help)
		fmt.Println("    --q                        " + quiet_help)
		fmt.Println("    --help                     This text")
		fmt.Println()
	}

	flag.Parse()

	// Use the flags and arguments

	o = textgui.NewTextOutput(true, !*quiet)

	args := flag.Args()

	if *version {
		o.Println(version_string)
		os.Exit(0)
	}

	// Default URL

	url := "https://http2.golang.org"
	if len(args) > 0 {
		url = args[0]
	}
	if !strings.Contains(url, "://") {
		url = "https://" + url
	}

	// Display the URL that is to be checked

	o.Println(o.DarkGray("GET") + " " + o.LightCyan(url))

	// GET over HTTP/2

	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		o.ErrExit(err.Error())
	}
	rt := &http2.Transport{
		InsecureTLSDial: true,
	}
	res, err := rt.RoundTrip(req)
	if err != nil {
		// Better looking error messages
		errorMessage := strings.TrimSpace(err.Error())
		if errorMessage == "bad protocol:" {
			msg(o, "protocol", o.DarkRed("Not HTTP/2"))
		} else if errorMessage == "http2: unsupported scheme and no Fallback" {
			msg(o, "HTTP/2", o.DarkRed("Not supported"))
		} else if strings.HasPrefix(errorMessage, "dial tcp") && strings.HasSuffix(errorMessage, ": connection refused") {
			msg(o, "host", o.DarkRed("Down"), errorMessage)
		} else if strings.HasPrefix(errorMessage, "tls: oversized record received with length ") {
			msg(o, "protocol", o.DarkRed("No HTTPS support"), errorMessage)
		} else {
			o.ErrExit(errorMessage)
		}
		os.Exit(1)
	}

	// Final output

	msg(o, "protocol", o.White(res.Proto))
	msg(o, "status", o.White(res.Status))
}
<|endoftext|>


<commit_before>package main

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

func main() {

	fmt.Println("Started server on port 3009 ...")

	//http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
	//	w.Write([]byte("Server is up!"))
	//})
	//
	//log.Fatal(http.ListenAndServe(":3009", nil))
}
<commit_msg>Fixed the encoding.<commit_after>package main

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

func main() {

	fmt.Println("Started server on port 3009 ...")

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("Server is up!"))
	})

	log.Fatal(http.ListenAndServe(":3009", nil))
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"strings"

	"github.com/cloudfoundry/cli/cf/terminal"
	"github.com/cloudfoundry/cli/cf/trace"
	"github.com/cloudfoundry/cli/plugin"
	"github.com/kkellner/cloudfoundry-top-plugin/top"
	"github.com/kkellner/cloudfoundry-top-plugin/util"
	"github.com/simonleung8/flags"
)

type TopCmd struct {
	ui terminal.UI
}

func (c *TopCmd) GetMetadata() plugin.PluginMetadata {
	return plugin.PluginMetadata{
		Name: "top",
		Version: plugin.VersionType{
			Major: 0,
			Minor: 6,
			Build: 6,
		},
		MinCliVersion: plugin.VersionType{
			Major: 6,
			Minor: 17,
			Build: 0,
		},
		Commands: []plugin.Command{
			{
				Name:     "top",
				HelpText: "Displays top stats - by Kurt Kellner of ECS Team",
				UsageDetails: plugin.Usage{
					Usage: "cf top",
					Options: map[string]string{
						"debug":   "-d, enable debugging",
						"cygwin":  "-c, force run under cygwin (Use this to run: 'cmd /c start cf top -cygwin' )",
						"nozzles": "-n, specify the number of nozzle instances (default: 2)",
					},
				},
			},
		},
	}
}

func main() {
	plugin.Start(new(TopCmd))
}

func (c *TopCmd) Run(cliConnection plugin.CliConnection, args []string) {
	var options *top.ClientOptions

	traceLogger := trace.NewLogger(os.Stdout, true, os.Getenv("CF_TRACE"), "")
	c.ui = terminal.NewUI(os.Stdin, os.Stdout, terminal.NewTeePrinter(os.Stdout), traceLogger)

	switch args[0] {
	case "top":
		options = c.buildClientOptions(args)
	case "app-top":
		options = c.buildClientOptions(args)
		appModel, err := cliConnection.GetApp(args[1])
		if err != nil {
			c.ui.Warn(err.Error())
			return
		}
		options.AppGUID = appModel.Guid
	default:
		return
	}

	cfTrace := os.Getenv("CF_TRACE")
	if strings.ToLower(cfTrace) == "true" {
		c.ui.Failed("The cf top plugin will not run with CF_TRACE environment variable set to true")
		return
	}

	if !options.Cygwin && util.IsCygwin() {
		c.ui.Failed("The cf top plugin will not run under cygwin.  Use this to run: 'cmd /c start cf top -cygwin'")
		return
	}

	/***********************************************************
	Trying to find a way to detect cygwin but not detect cygwin if cmd.exe is spawned from cygwin

	values := os.Environ()
	for _, v := range values  {
		fmt.Printf("value: [%v]\n", v)
	}

	fmt.Printf("Separator: [%v]\n", os.PathSeparator)
	fmt.Printf("PathListSeparator: [%v]\n", os.PathListSeparator)
	fmt.Printf("Geteuid: %v\n", os.Geteuid())
	fmt.Printf("Getppid: %v\n", os.Getppid())
	p, e := os.FindProcess(os.Getppid())
	fmt.Printf("Getppid: %+v [Err:%v]\n", p, e)

	if strings.Contains(strings.ToLower(os.Getenv("OS")), "windows") {
		shell := os.Getenv("SHELL")
		if len(shell) > 0 {
			c.ui.Failed("The cf top plugin will not run under cygwin.  Use this to run: 'cmd /c start cf top'")
			return
		}
	}
	fmt.Printf("runtime.GOOS: [%v]\n", runtime.GOOS)
	*/

	/*
		if strings.ToLower(osType) == "cygwin" {
			c.ui.Failed("The cf top plugin will not run under cygwin.  Use this to run: 'cmd /c start cf top'")
			return
		}
	*/

	client := top.NewClient(cliConnection, options, c.ui)
	client.Start()
}

func (c *TopCmd) buildClientOptions(args []string) *top.ClientOptions {
	var debug bool
	var cygwin bool
	var nozzles int

	fc := flags.New()
	fc.NewBoolFlag("debug", "d", "used for debugging")
	fc.NewBoolFlag("cygwin", "c", "force run under cygwin (Use this to run: 'cmd /c start cf top -cygwin' )")
	fc.NewIntFlagWithDefault("nozzles", "n", "number of nozzles", 2)
	//fc.NewStringFlag("filter", "f", "specify message filter such as LogMessage, ValueMetric, CounterEvent, HttpStartStop")
	err := fc.Parse(args[1:]...)

	if err != nil {
		c.ui.Failed(err.Error())
	}
	if fc.IsSet("debug") {
		debug = fc.Bool("debug")
	}
	if fc.IsSet("cygwin") {
		cygwin = fc.Bool("cygwin")
	}

	nozzles = fc.Int("nozzles")

	/*
		if fc.IsSet("filter") {
			filter = fc.String("filter")
		}
	*/
	return &top.ClientOptions{
		Debug:   debug,
		Cygwin:  cygwin,
		Nozzles: nozzles,
	}
}
<commit_msg>Build version v0.6.7<commit_after>package main

import (
	"os"
	"strings"

	"github.com/cloudfoundry/cli/cf/terminal"
	"github.com/cloudfoundry/cli/cf/trace"
	"github.com/cloudfoundry/cli/plugin"
	"github.com/kkellner/cloudfoundry-top-plugin/top"
	"github.com/kkellner/cloudfoundry-top-plugin/util"
	"github.com/simonleung8/flags"
)

type TopCmd struct {
	ui terminal.UI
}

func (c *TopCmd) GetMetadata() plugin.PluginMetadata {
	return plugin.PluginMetadata{
		Name: "top",
		Version: plugin.VersionType{
			Major: 0,
			Minor: 6,
			Build: 7,
		},
		MinCliVersion: plugin.VersionType{
			Major: 6,
			Minor: 17,
			Build: 0,
		},
		Commands: []plugin.Command{
			{
				Name:     "top",
				HelpText: "Displays top stats - by Kurt Kellner of ECS Team",
				UsageDetails: plugin.Usage{
					Usage: "cf top",
					Options: map[string]string{
						"debug":   "-d, enable debugging",
						"cygwin":  "-c, force run under cygwin (Use this to run: 'cmd /c start cf top -cygwin' )",
						"nozzles": "-n, specify the number of nozzle instances (default: 2)",
					},
				},
			},
		},
	}
}

func main() {
	plugin.Start(new(TopCmd))
}

func (c *TopCmd) Run(cliConnection plugin.CliConnection, args []string) {
	var options *top.ClientOptions

	traceLogger := trace.NewLogger(os.Stdout, true, os.Getenv("CF_TRACE"), "")
	c.ui = terminal.NewUI(os.Stdin, os.Stdout, terminal.NewTeePrinter(os.Stdout), traceLogger)

	switch args[0] {
	case "top":
		options = c.buildClientOptions(args)
	case "app-top":
		options = c.buildClientOptions(args)
		appModel, err := cliConnection.GetApp(args[1])
		if err != nil {
			c.ui.Warn(err.Error())
			return
		}
		options.AppGUID = appModel.Guid
	default:
		return
	}

	cfTrace := os.Getenv("CF_TRACE")
	if strings.ToLower(cfTrace) == "true" {
		c.ui.Failed("The cf top plugin will not run with CF_TRACE environment variable set to true")
		return
	}

	if !options.Cygwin && util.IsCygwin() {
		c.ui.Failed("The cf top plugin will not run under cygwin.  Use this to run: 'cmd /c start cf top -cygwin'")
		return
	}

	/***********************************************************
	Trying to find a way to detect cygwin but not detect cygwin if cmd.exe is spawned from cygwin

	values := os.Environ()
	for _, v := range values  {
		fmt.Printf("value: [%v]\n", v)
	}

	fmt.Printf("Separator: [%v]\n", os.PathSeparator)
	fmt.Printf("PathListSeparator: [%v]\n", os.PathListSeparator)
	fmt.Printf("Geteuid: %v\n", os.Geteuid())
	fmt.Printf("Getppid: %v\n", os.Getppid())
	p, e := os.FindProcess(os.Getppid())
	fmt.Printf("Getppid: %+v [Err:%v]\n", p, e)

	if strings.Contains(strings.ToLower(os.Getenv("OS")), "windows") {
		shell := os.Getenv("SHELL")
		if len(shell) > 0 {
			c.ui.Failed("The cf top plugin will not run under cygwin.  Use this to run: 'cmd /c start cf top'")
			return
		}
	}
	fmt.Printf("runtime.GOOS: [%v]\n", runtime.GOOS)
	*/

	/*
		if strings.ToLower(osType) == "cygwin" {
			c.ui.Failed("The cf top plugin will not run under cygwin.  Use this to run: 'cmd /c start cf top'")
			return
		}
	*/

	client := top.NewClient(cliConnection, options, c.ui)
	client.Start()
}

func (c *TopCmd) buildClientOptions(args []string) *top.ClientOptions {
	var debug bool
	var cygwin bool
	var nozzles int

	fc := flags.New()
	fc.NewBoolFlag("debug", "d", "used for debugging")
	fc.NewBoolFlag("cygwin", "c", "force run under cygwin (Use this to run: 'cmd /c start cf top -cygwin' )")
	fc.NewIntFlagWithDefault("nozzles", "n", "number of nozzles", 2)
	//fc.NewStringFlag("filter", "f", "specify message filter such as LogMessage, ValueMetric, CounterEvent, HttpStartStop")
	err := fc.Parse(args[1:]...)

	if err != nil {
		c.ui.Failed(err.Error())
	}
	if fc.IsSet("debug") {
		debug = fc.Bool("debug")
	}
	if fc.IsSet("cygwin") {
		cygwin = fc.Bool("cygwin")
	}

	nozzles = fc.Int("nozzles")

	/*
		if fc.IsSet("filter") {
			filter = fc.String("filter")
		}
	*/
	return &top.ClientOptions{
		Debug:   debug,
		Cygwin:  cygwin,
		Nozzles: nozzles,
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
)

const (
	filePath string = "./sample.txt"
)

func main() {

	// Read the file and get a byte slice.
	b, _ := ioutil.ReadFile(filePath)

	// Re-slice the byte slice.
	s := b[:10]

	// Length of the slice is short but Capacity of the slice is long.
	print("Before", s)

	// Create a new slice.
	s = append([]byte{}, s...)

	// Both length and capaticy of the slice are short.
	print("After ", s)
}

func print(label string, s []byte) {
	fmt.Printf("[%s] content: %s, len: %d, cap: %d\n", label, s, len(s), cap(s))
}
<commit_msg>Updated main.go<commit_after>package main

import (
	"fmt"
	"io/ioutil"
)

const (
	filePath string = "./sample.txt"
)

func main() {

	// Read the file and get a byte slice.
	b, _ := ioutil.ReadFile(filePath)

	// Re-slice the byte slice.
	s := b[:10]

	// Length of the slice is short but capacity of the slice is long.
	print("Before", s)

	// Create a new slice.
	s = append([]byte{}, s...)

	// Both length and capacity of the slice are short.
	print("After ", s)
}

func print(label string, s []byte) {
	fmt.Printf("[%s] content: %s, len: %d, cap: %d\n", label, s, len(s), cap(s))
}
<|endoftext|>


<commit_before>// Edit is a "fuzzy" file finder/plumber for Acme.
//
// Usage:
//
// 	edit query [dirs...]
//
// Edit executes a query against a set of directories (default: .). If there
// are two or fewer results, edit will automatically plumb the files,
// similar to Plan 9's B command.
//
// Edit traverses each given directory, skipping common database paths
// (.git, .svn), and matches each entry against the query.
//
// A candidate path is admitted if all the characters in the query appear
// in the same order in the path. If the query contains the path separator
// '/' then the characters in the query delimited by that separator must
// appear within a single path element in the candidate path.
package main // import "marius.ae/edit"

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

var ignoreDirs = map[string]bool{
	".git": true,
	".svn": true,
}

var printOnly = flag.Bool("n", false, "Don't plumb results, just print them.")
var editOnly = flag.Bool("e", false, "Force edit, regardless of number of hits.")

func usage() {
	fmt.Fprintf(os.Stderr, "usage: edit query [dir...]\n")
	fmt.Fprint(os.Stderr, "options:\n")
	flag.PrintDefaults()
	os.Exit(2)
}

func match1(query, path string) bool {
	for _, c := range query {
		i := strings.IndexRune(path, c)
		if i < 0 {
			return false
		}
		path = path[i:]
	}

	return true
}

func match(query, path string) bool {
	ps := strings.Split(path, "/")
	qs := strings.Split(query, "/")
	i := 0

	for _, q := range qs {
		found := false
		for !found && i < len(ps) {
			found = match1(q, ps[i])
			i++
		}
		if !found {
			return false
		}
	}

	return true
}

func plumb(path string) {
	out, err := exec.Command("plumb", "-d", "edit", path).CombinedOutput()
	if err != nil {
		log.Fatalf("plumb: %v\n%s", err, out)
	}
}

func main() {
	log.SetFlags(0)
	log.SetPrefix("edit: ")
	flag.Usage = usage
	flag.Parse()

	if flag.NArg() < 1 || (*printOnly && *editOnly) {
		usage()
	}

	query := flag.Arg(0)
	dirs := flag.Args()[1:]
	if len(dirs) == 0 {
		dirs = []string{"."}
	}

	cased := false
	for _, r := range query {
		cased = cased || unicode.IsUpper(r)
	}

	if !cased {
		query = strings.ToLower(query)
	}

	matches := []string{}

	for _, d := range dirs {
		filepath.Walk(d, func(path string, info os.FileInfo, err error) error {
			fi, err := os.Stat(path)
			if err != nil {
				return err
			}

			if !fi.Mode().IsRegular() {
				if _, ok := ignoreDirs[filepath.Base(path)]; ok {
					return filepath.SkipDir
				}
				return nil
			}

			rel, err := filepath.Rel(d, path)
			if err != nil {
				return err
			}

			if !cased {
				rel = strings.ToLower(rel)
			}

			if match(query, rel) {
				matches = append(matches, path)
			}
			return nil
		})
	}

	if len(matches) < 3 && !*printOnly || *editOnly {
		for _, path := range matches {
			plumb(path)
		}
	} else {
		for _, path := range matches {
			fmt.Println(path)
		}
	}

}<commit_msg>EDITPATH, globbing, substring matching<commit_after>// Edit is a file finder/plumber for Acme.
//
// Usage:
//
// 	edit query [dirs...]
//
// Edit executes a query against a set of directories (default: .).
// If there is exactly one result, edit will automatically plumb the
// files, similar to Plan 9's B command.
//
// The EDITPATH environment variable is a colon-separated list of
// directories to look for files.
//
// Using the invocation:
//
//	edit dir:query
//
// Edit executes the query against  x/dir for every directory x in EDITPATH.
//
// Edit traverses each given directory, skipping common database paths
// (.git, .svn), and matches each entry against the query.
//
// Queries are partial paths. A query matches a candidate path
// when each path element in the query matches a path element
// in the candidate path. The elements have to appear in the same
// order, but not all path elements from the candidate path are
// required to match.
//
// A query path element matches a candidate path element if
// (1) it is a substring of the path element; or (2) it is a glob pattern
// (containing any of "*?[") that matches according to filepath.Match.
package main // import "marius.ae/edit"

// 	- Scoring/select first

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

var ignoreDirs = map[string]bool{
	".git": true,
	".svn": true,
}

var printOnly = flag.Bool("n", false, "Don't plumb results, just print them.")
var editOnly = flag.Bool("e", false, "Force edit, regardless of number of hits.")

func usage() {
	fmt.Fprintf(os.Stderr, "usage: edit query [dir...]\n")
	fmt.Fprint(os.Stderr, "options:\n")
	flag.PrintDefaults()
	os.Exit(2)
}

func match1(q, p string) bool {
	if strings.IndexAny(q, "*?[") > -1 {
		ok, _ := filepath.Match(q, p)
		return ok
	} else {
		return strings.Index(p, q) > -1
	}
}

func match(query, path string) bool {
	ps := strings.Split(path, "/")
	qs := strings.Split(query, "/")
	i := 0

	for _, q := range qs[:len(qs)-1] {
		found := false
		for !found && i < len(ps)-1 {
			found = match1(q, ps[i])
			i++
		}
		if !found {
			return false
		}
	}

	p := ps[len(ps)-1]
	q := qs[len(qs)-1]

	return match1(q, p)
}

func plumb(path string) {
	out, err := exec.Command("plumb", "-d", "edit", path).CombinedOutput()
	if err != nil {
		log.Fatalf("plumb: %v\n%s", err, out)
	}
}

func main() {
	log.SetFlags(0)
	log.SetPrefix("edit: ")
	flag.Usage = usage
	flag.Parse()

	if flag.NArg() < 1 || (*printOnly && *editOnly) {
		usage()
	}

	query := flag.Arg(0)
	cased := false
	for _, r := range query {
		cased = cased || unicode.IsUpper(r)
	}

	if !cased {
		query = strings.ToLower(query)
	}

	var dirs []string
	if strings.Contains(query, ":") && flag.NArg() == 1 {
		i := strings.Index(query, ":")
		var path string
		path, query = query[0:i], query[i+1:]

		dirs = filepath.SplitList(os.Getenv("EDITPATH"))
		for i := range dirs {
			dirs[i] = filepath.Join(dirs[i], path)
		}
	} else {
		if flag.NArg() == 1 {
			dirs = []string{"."}
		} else {

			dirs = flag.Args()[1:]
		}
	}

	//	log.Printf("query \"%s\" dirs \"%v\"", query, dirs)

	matches := []string{}

	for _, d := range dirs {
		filepath.Walk(d, func(path string, info os.FileInfo, err error) error {
			fi, err := os.Stat(path)
			if err != nil {
				return err
			}

			if !fi.Mode().IsRegular() {
				if _, ok := ignoreDirs[filepath.Base(path)]; ok {
					return filepath.SkipDir
				}
				return nil
			}

			rel, err := filepath.Rel(d, path)
			if err != nil {
				return err
			}

			if !cased {
				rel = strings.ToLower(rel)
			}

			if match(query, rel) {
				matches = append(matches, path)
			}
			return nil
		})
	}

	if len(matches) == 1 && !*printOnly || *editOnly {
		for _, path := range matches {
			plumb(path)
		}
	} else {
		for _, path := range matches {
			fmt.Println(path)
		}
	}

}<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"gnd.la/app"
	_ "gnd.la/bootstrap"
	"gnd.la/config"
	"gnd.la/html"
	"gnd.la/template"
	"gnd.la/util"
	"net/http"
	"os"
	"path/filepath"
	"time"
)

var (
	Config config.Config
	App    *app.App
	data   = util.RelativePath("data")
)

func fileHandler(name string) app.Handler {
	p := filepath.Join(data, name)
	return func(ctx *app.Context) {
		f, err := os.Open(p)
		if err != nil {
			ctx.NotFound("")
		}
		defer f.Close()
		var modtime time.Time
		if fi, err := f.Stat(); err == nil {
			modtime = fi.ModTime()
		}
		http.ServeContent(ctx, ctx.R, name, modtime, f)
	}
}

func init() {
	template.AddFuncs(template.FuncMap{
		"#config": func(name string, def string) template.HTML {
			var buf bytes.Buffer
			buf.WriteString("
")
			buf.WriteString(html.Escape(name))
			if def != "" {
				buf.WriteString(" optional")
				fmt.Fprintf(&buf, " default: %s", html.Escape(def))
			} else {
				buf.WriteString(" required")
			}
			buf.WriteString("
")
			return template.HTML(buf.String())
		}})
	config.MustParse(&Config)
	App = app.New()
	App.SetTrustXHeaders(true)
	App.HandleAssets("/assets/", util.RelativePath("assets"))
	App.Handle("^/$", app.TemplateHandler("main.html", nil))
	App.Handle("^/install\\.sh$", fileHandler("install.sh"))
	App.Handle("^/get/releases/linux/x86_64/latest/governator$", fileHandler("governator"))
	App.Handle("^/contrib/upstart/governator.conf$", fileHandler("governator.conf"))
}

func main() {
	App.MustListenAndServe()
}
<commit_msg>Update to new Gondola APIs<commit_after>package main

import (
	"bytes"
	"fmt"
	"gnd.la/app"
	_ "gnd.la/bootstrap"
	"gnd.la/config"
	"gnd.la/html"
	"gnd.la/template"
	"gnd.la/util/pathutil"
	"net/http"
	"os"
	"path/filepath"
	"time"
)

var (
	Config config.Config
	App    *app.App
	data   = pathutil.Relative("data")
)

func fileHandler(name string) app.Handler {
	p := filepath.Join(data, name)
	return func(ctx *app.Context) {
		f, err := os.Open(p)
		if err != nil {
			ctx.NotFound("")
		}
		defer f.Close()
		var modtime time.Time
		if fi, err := f.Stat(); err == nil {
			modtime = fi.ModTime()
		}
		http.ServeContent(ctx, ctx.R, name, modtime, f)
	}
}

func init() {
	template.AddFuncs(template.FuncMap{
		"#config": func(name string, def string) template.HTML {
			var buf bytes.Buffer
			buf.WriteString("
")
			buf.WriteString(html.Escape(name))
			if def != "" {
				buf.WriteString(" optional")
				fmt.Fprintf(&buf, " default: %s", html.Escape(def))
			} else {
				buf.WriteString(" required")
			}
			buf.WriteString("
")
			return template.HTML(buf.String())
		}})
	config.MustParse(&Config)
	App = app.New()
	App.SetTrustXHeaders(true)
	App.HandleAssets("/assets/", pathutil.Relative("assets"))
	App.Handle("^/$", app.TemplateHandler("main.html", nil))
	App.Handle("^/install\\.sh$", fileHandler("install.sh"))
	App.Handle("^/get/releases/linux/x86_64/latest/governator$", fileHandler("governator"))
	App.Handle("^/contrib/upstart/governator.conf$", fileHandler("governator.conf"))
}

func main() {
	App.MustListenAndServe()
}
<|endoftext|>


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

package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"os"
	"strconv"
	"time"

	"github.com/google/uuid"
)

var outputName = flag.String("output", "-", "output file name")
var gcpProjectNumber = flag.Int64("gcp-project-number", 0,
	"the gcp project number. If unknown, can be found via 'gcloud projects list'")
var vpcNetworkName = flag.String("vpc-network-name", "default", "VPC network name")

func main() {
	flag.Parse()
	if *gcpProjectNumber == 0 {
		var err error
		*gcpProjectNumber, err = getProjectId()
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error: failed to determine project id: %s\n", err)
			os.Exit(1)
		}
	}
	ip, err := getHostIp()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Warning: failed to determine host's ip: %s\n", err)
		ip = ""
	}
	zone, err := getZone()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Warning: failed to determine zone: %s\n", err)
		zone = ""
	}
	config, err := generate(configInput{
		gcpProjectNumber: *gcpProjectNumber,
		vpcNetworkName:   *vpcNetworkName,
		ip:               ip,
		zone:             zone,
	})
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to generate config: %s\n", err)
		os.Exit(1)
	}
	if *outputName == "-" {
		_, err = os.Stdout.Write(config)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Failed to write config: %s\n", err)
			os.Exit(1)
		}
		_, err = os.Stdout.WriteString("\n")
		if err != nil {
			fmt.Fprintf(os.Stderr, "Failed to write config: %s\n", err)
			os.Exit(1)
		}
	} else {
		// Let umask filter file permissions
		err = ioutil.WriteFile(*outputName, config, 0777)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Failed to write config: %s\n", err)
			os.Exit(1)
		}
	}
}

type configInput struct {
	gcpProjectNumber int64
	vpcNetworkName   string
	ip               string
	zone             string
}

func generate(in configInput) ([]byte, error) {
	c := &config{
		XdsServers: []server{
			{
				ServerUri: "trafficdirector.googleapis.com:443",
				ChannelCreds: []creds{
					{Type: "google_default"},
				},
			},
		},
		Node: &node{
			Id:      uuid.New().String() + "~" + in.ip,
			Cluster: "cluster", // unused by TD
			Locality: &locality{
				Zone: in.zone,
			},
			Metadata: map[string]string{
				"TRAFFICDIRECTOR_NETWORK_NAME":       in.vpcNetworkName,
				"TRAFFICDIRECTOR_GCP_PROJECT_NUMBER": strconv.FormatInt(in.gcpProjectNumber, 10),
			},
		},
	}
	return json.MarshalIndent(c, "", "  ")
}

func getHostIp() (string, error) {
	hostname, err := os.Hostname()
	if err != nil {
		return "", err
	}
	addrs, err := net.LookupHost(hostname)
	if err != nil {
		return "", err
	}
	if len(addrs) == 0 {
		return "", fmt.Errorf("no addresses found for hostname: %s", hostname)
	}
	return addrs[0], nil
}

func getZone() (string, error) {
	qualifiedZone, err := getFromMetadata("http://metadata.google.internal/computeMetadata/v1/instance/zone")
	if err != nil {
		return "", fmt.Errorf("could not discover instance zone: %w", err)
	}
	i := bytes.LastIndexByte(qualifiedZone, '/')
	if i == -1 {
		return "", fmt.Errorf("could not parse zone from metadata server: %s", qualifiedZone)
	}
	return string(qualifiedZone[i+1:]), nil
}

func getProjectId() (int64, error) {
	projectIdBytes, err := getFromMetadata("http://metadata.google.internal/computeMetadata/v1/project/numeric-project-id")
	if err != nil {
		return 0, fmt.Errorf("could not discover project id: %w", err)
	}
	projectId, err := strconv.ParseInt(string(projectIdBytes), 10, 64)
	if err != nil {
		return 0, fmt.Errorf("could not parse project id from metadata server: %w", err)
	}
	return projectId, nil
}

func getFromMetadata(urlStr string) ([]byte, error) {
	parsedUrl, err := url.Parse(urlStr)
	if err != nil {
		return nil, err
	}
	client := &http.Client{
		Timeout: 5 * time.Second,
	}
	req := &http.Request{
		Method: "GET",
		URL:    parsedUrl,
		Header: http.Header{
			"Metadata-Flavor": {"Google"},
		},
	}
	resp, err := client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("failed communicating with metadata server: %w", err)
	}
	body, err := ioutil.ReadAll(resp.Body)
	resp.Body.Close()
	if err != nil {
		return nil, fmt.Errorf("failed reading from metadata server: %w", err)
	}
	return body, nil
}

type config struct {
	XdsServers []server `json:"xds_servers,omitempty"`
	Node       *node    `json:"node,omitempty"`
}

type server struct {
	ServerUri    string  `json:"server_uri,omitempty"`
	ChannelCreds []creds `json:"channel_creds,omitempty"`
}

type creds struct {
	Type   string      `json:"type,omitempty"`
	Config interface{} `json:"config,omitempty"`
}

type node struct {
	Id           string      `json:"id,omitempty"`
	Cluster      string      `json:"cluster,omitempty"`
	Metadata     interface{} `json:"metadata,omitempty"`
	Locality     *locality   `json:"locality,omitempty"`
	BuildVersion string      `json:"build_version,omitempty"`
}

type locality struct {
	Region  string `json:"region,omitempty"`
	Zone    string `json:"zone,omitempty"`
	SubZone string `json:"sub_zone,omitempty"`
}
<commit_msg>Combine stdout and file output paths<commit_after>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"os"
	"strconv"
	"time"

	"github.com/google/uuid"
)

var outputName = flag.String("output", "-", "output file name")
var gcpProjectNumber = flag.Int64("gcp-project-number", 0,
	"the gcp project number. If unknown, can be found via 'gcloud projects list'")
var vpcNetworkName = flag.String("vpc-network-name", "default", "VPC network name")

func main() {
	flag.Parse()
	if *gcpProjectNumber == 0 {
		var err error
		*gcpProjectNumber, err = getProjectId()
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error: failed to determine project id: %s\n", err)
			os.Exit(1)
		}
	}
	ip, err := getHostIp()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Warning: failed to determine host's ip: %s\n", err)
		ip = ""
	}
	zone, err := getZone()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Warning: failed to determine zone: %s\n", err)
		zone = ""
	}
	config, err := generate(configInput{
		gcpProjectNumber: *gcpProjectNumber,
		vpcNetworkName:   *vpcNetworkName,
		ip:               ip,
		zone:             zone,
	})
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to generate config: %s\n", err)
		os.Exit(1)
	}
	var output *os.File
	if *outputName == "-" {
		output = os.Stdout
	} else {
		output, err = os.Create(*outputName)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Failed to open output file: %s\n", err)
			os.Exit(1)
		}
	}
	_, err = output.Write(config)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to write config: %s\n", err)
		os.Exit(1)
	}
	_, err = output.Write([]byte("\n"))
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to write config: %s\n", err)
		os.Exit(1)
	}
	err = output.Close()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to close config: %s\n", err)
		os.Exit(1)
	}
}

type configInput struct {
	gcpProjectNumber int64
	vpcNetworkName   string
	ip               string
	zone             string
}

func generate(in configInput) ([]byte, error) {
	c := &config{
		XdsServers: []server{
			{
				ServerUri: "trafficdirector.googleapis.com:443",
				ChannelCreds: []creds{
					{Type: "google_default"},
				},
			},
		},
		Node: &node{
			Id:      uuid.New().String() + "~" + in.ip,
			Cluster: "cluster", // unused by TD
			Locality: &locality{
				Zone: in.zone,
			},
			Metadata: map[string]string{
				"TRAFFICDIRECTOR_NETWORK_NAME":       in.vpcNetworkName,
				"TRAFFICDIRECTOR_GCP_PROJECT_NUMBER": strconv.FormatInt(in.gcpProjectNumber, 10),
			},
		},
	}
	return json.MarshalIndent(c, "", "  ")
}

func getHostIp() (string, error) {
	hostname, err := os.Hostname()
	if err != nil {
		return "", err
	}
	addrs, err := net.LookupHost(hostname)
	if err != nil {
		return "", err
	}
	if len(addrs) == 0 {
		return "", fmt.Errorf("no addresses found for hostname: %s", hostname)
	}
	return addrs[0], nil
}

func getZone() (string, error) {
	qualifiedZone, err := getFromMetadata("http://metadata.google.internal/computeMetadata/v1/instance/zone")
	if err != nil {
		return "", fmt.Errorf("could not discover instance zone: %w", err)
	}
	i := bytes.LastIndexByte(qualifiedZone, '/')
	if i == -1 {
		return "", fmt.Errorf("could not parse zone from metadata server: %s", qualifiedZone)
	}
	return string(qualifiedZone[i+1:]), nil
}

func getProjectId() (int64, error) {
	projectIdBytes, err := getFromMetadata("http://metadata.google.internal/computeMetadata/v1/project/numeric-project-id")
	if err != nil {
		return 0, fmt.Errorf("could not discover project id: %w", err)
	}
	projectId, err := strconv.ParseInt(string(projectIdBytes), 10, 64)
	if err != nil {
		return 0, fmt.Errorf("could not parse project id from metadata server: %w", err)
	}
	return projectId, nil
}

func getFromMetadata(urlStr string) ([]byte, error) {
	parsedUrl, err := url.Parse(urlStr)
	if err != nil {
		return nil, err
	}
	client := &http.Client{
		Timeout: 5 * time.Second,
	}
	req := &http.Request{
		Method: "GET",
		URL:    parsedUrl,
		Header: http.Header{
			"Metadata-Flavor": {"Google"},
		},
	}
	resp, err := client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("failed communicating with metadata server: %w", err)
	}
	body, err := ioutil.ReadAll(resp.Body)
	resp.Body.Close()
	if err != nil {
		return nil, fmt.Errorf("failed reading from metadata server: %w", err)
	}
	return body, nil
}

type config struct {
	XdsServers []server `json:"xds_servers,omitempty"`
	Node       *node    `json:"node,omitempty"`
}

type server struct {
	ServerUri    string  `json:"server_uri,omitempty"`
	ChannelCreds []creds `json:"channel_creds,omitempty"`
}

type creds struct {
	Type   string      `json:"type,omitempty"`
	Config interface{} `json:"config,omitempty"`
}

type node struct {
	Id           string      `json:"id,omitempty"`
	Cluster      string      `json:"cluster,omitempty"`
	Metadata     interface{} `json:"metadata,omitempty"`
	Locality     *locality   `json:"locality,omitempty"`
	BuildVersion string      `json:"build_version,omitempty"`
}

type locality struct {
	Region  string `json:"region,omitempty"`
	Zone    string `json:"zone,omitempty"`
	SubZone string `json:"sub_zone,omitempty"`
}
<|endoftext|>