<commit_before>// Copyright (c) 2014,2015,2016 Docker, Inc.
// Copyright (c) 2017-2018 Intel Corporation
//
// 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 (
	"fmt"
	"io"
	"os"
	goruntime "runtime"
	"runtime/debug"
	"strings"

	vc "github.com/containers/virtcontainers"
	"github.com/containers/virtcontainers/pkg/oci"
	specs "github.com/opencontainers/runtime-spec/specs-go"
	"github.com/sirupsen/logrus"
	"github.com/urfave/cli"
)

// specConfig is the name of the file holding the containers configuration
const specConfig = "config.json"

// arch is the architecture for the running program
const arch = goruntime.GOARCH

var usage = fmt.Sprintf(`%s runtime

%s is a command line program for running applications packaged
according to the Open Container Initiative (OCI).`, name, name)

var notes = fmt.Sprintf(`
NOTES:

- Commands starting "%s-" and options starting "--%s-" are `+project+` extensions.

URL:

  The canonical URL for this project is: %s

`, projectPrefix, projectPrefix, projectURL)

// ccLog is the logger used to record all messages
var ccLog *logrus.Entry

// originalLoggerLevel is the default log level. It is used to revert the
// current log level back to its original value if debug output is not
// required.
var originalLoggerLevel logrus.Level

// concrete virtcontainer implementation
var virtcontainersImpl = &vc.VCImpl{}

// vci is used to access a particular virtcontainers implementation.
// Normally, it refers to the official package, but is re-assigned in
// the tests to allow virtcontainers to be mocked.
var vci vc.VC = virtcontainersImpl

// defaultOutputFile is the default output file to write the gathered
// information to.
var defaultOutputFile = os.Stdout

// defaultErrorFile is the default output file to write error
// messages to.
var defaultErrorFile = os.Stderr

// runtimeFlags is the list of supported global command-line flags
var runtimeFlags = []cli.Flag{
	cli.StringFlag{
		Name:  configFilePathOption,
		Usage: project + " config file path",
	},
	cli.StringFlag{
		Name:  "log",
		Value: "/dev/null",
		Usage: "set the log file path where internal debug information is written",
	},
	cli.StringFlag{
		Name:  "log-format",
		Value: "text",
		Usage: "set the format used by logs ('text' (default), or 'json')",
	},
	cli.StringFlag{
		Name:  "root",
		Value: defaultRootDirectory,
		Usage: "root directory for storage of container state (this should be located in tmpfs)",
	},
	cli.BoolFlag{
		Name:  showConfigPathsOption,
		Usage: "show config file paths that will be checked for (in order)",
	},
}

// runtimeCommands is the list of supported command-line (sub-)
// commands.
var runtimeCommands = []cli.Command{
	createCLICommand,
	deleteCLICommand,
	execCLICommand,
	killCLICommand,
	listCLICommand,
	pauseCLICommand,
	psCLICommand,
	resumeCLICommand,
	runCLICommand,
	startCLICommand,
	stateCLICommand,
	versionCLICommand,

	// Clear Containers specific extensions
	ccCheckCLICommand,
	ccEnvCLICommand,
}

// runtimeBeforeSubcommands is the function to run before command-line
// parsing occurs.
var runtimeBeforeSubcommands = beforeSubcommands

// runtimeCommandNotFound is the function to handle an invalid sub-command.
var runtimeCommandNotFound = commandNotFound

// runtimeVersion is the function that returns the full version
// string describing the runtime.
var runtimeVersion = makeVersionString

// saved default cli package values (for testing).
var savedCLIAppHelpTemplate = cli.AppHelpTemplate
var savedCLIVersionPrinter = cli.VersionPrinter
var savedCLIErrWriter = cli.ErrWriter

func init() {
	ccLog = logrus.WithField(logrus.Fields{
		"source": "runtime",
		"pid":    os.Getpid(),
	})

	// Save the original log level and then set to debug level to ensure
	// that any problems detected before the config file is parsed are
	// logged. This is required since the config file determines the true
	// log level for the runtime: once parsed the log level is set
	// appropriately but for issues between now and completion of the
	// config file parsing, it is prudent to operate in verbose mode.
	originalLoggerLevel = ccLog.Logger.Level
	ccLog.Logger.Level = logrus.DebugLevel

	// Force a coredump + full stacktrace on internal error
	debug.SetTraceback("crash")
}

// beforeSubcommands is the function to perform preliminary checks
// before command-line parsing occurs.
func beforeSubcommands(context *cli.Context) error {
	if context.GlobalBool(showConfigPathsOption) {
		files := getDefaultConfigFilePaths()

		for _, file := range files {
			fmt.Fprintf(defaultOutputFile, "%s\n", file)
		}

		exit(0)
	}

	if userWantsUsage(context) || (context.NArg() == 1 && (context.Args()[0] == checkCmd)) {
		// No setup required if the user just
		// wants to see the usage statement or are
		// running a command that does not manipulate
		// containers.
		return nil
	}

	if path := context.GlobalString("log"); path != "" {
		f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_APPEND|os.O_SYNC, 0640)
		if err != nil {
			return err
		}
		ccLog.Logger.Out = f
	}

	switch context.GlobalString("log-format") {
	case "text":
		// retain logrus's default.
	case "json":
		ccLog.Logger.Formatter = new(logrus.JSONFormatter)
	default:
		return fmt.Errorf("unknown log-format %q", context.GlobalString("log-format"))
	}

	// Set virtcontainers logger.
	vci.SetLogger(ccLog)

	// Set the OCI package logger.
	oci.SetLogger(ccLog)

	ignoreLogging := false

	// Add the name of the sub-command to each log entry for easier
	// debugging.
	name := context.Args().First()
	if context.App.Command(name) != nil {
		ccLog = ccLog.WithField("command", name)
	}

	if context.NArg() == 1 && context.Args()[0] == envCmd {
		// simply report the logging setup
		ignoreLogging = true
	}

	configFile, runtimeConfig, err := loadConfiguration(context.GlobalString(configFilePathOption), ignoreLogging)
	if err != nil {
		fatal(err)
	}

	args := strings.Join(context.Args(), " ")

	fields := logrus.Fields{
		"name":      name,
		"version":   version,
		"commit":    commit,
		"arguments": `"` + args + `"`,
	}

	ccLog.WithFields(fields).Info()

	// make the data accessible to the sub-commands.
	context.App.Metadata = map[string]interface{}{
		"runtimeConfig": runtimeConfig,
		"configFile":    configFile,
	}

	return nil
}

// function called when an invalid command is specified which causes the
// runtime to error.
func commandNotFound(c *cli.Context, command string) {
	err := fmt.Errorf("Invalid command %q", command)
	fatal(err)
}

// makeVersionString returns a multi-line string describing the runtime
// version along with the version of the OCI specification it supports.
func makeVersionString() string {
	v := make([]string, 0, 3)

	versionStr := version
	if versionStr == "" {
		versionStr = unknown
	}

	v = append(v, name+"  : "+versionStr)

	commitStr := commit
	if commitStr == "" {
		commitStr = unknown
	}

	v = append(v, "   commit   : "+commitStr)

	specVersionStr := specs.Version
	if specVersionStr == "" {
		specVersionStr = unknown
	}

	v = append(v, "   OCI specs: "+specVersionStr)

	return strings.Join(v, "\n")
}

// setCLIGlobals modifies various cli package global variables
func setCLIGlobals() {
	cli.AppHelpTemplate = fmt.Sprintf(`%s%s`, cli.AppHelpTemplate, notes)

	// Override the default function to display version details to
	// ensure the "--version" option and "version" command are identical.
	cli.VersionPrinter = func(c *cli.Context) {
		fmt.Fprintln(defaultOutputFile, c.App.Version)
	}

	// If the command returns an error, cli takes upon itself to print
	// the error on cli.ErrWriter and exit.
	// Use our own writer here to ensure the log gets sent to the right
	// location.
	cli.ErrWriter = &fatalWriter{cli.ErrWriter}
}

// createRuntimeApp creates an application to process the command-line
// arguments and invoke the requested runtime command.
func createRuntimeApp(args []string) error {
	app := cli.NewApp()

	app.Name = name
	app.Writer = defaultOutputFile
	app.Usage = usage
	app.CommandNotFound = runtimeCommandNotFound
	app.Version = runtimeVersion()
	app.Flags = runtimeFlags
	app.Commands = runtimeCommands
	app.Before = runtimeBeforeSubcommands
	app.EnableBashCompletion = true

	return app.Run(args)
}

// userWantsUsage determines if the user only wishes to see the usage
// statement.
func userWantsUsage(context *cli.Context) bool {
	if context.NArg() == 0 {
		return true
	}

	if context.NArg() == 1 && (context.Args()[0] == "help" || context.Args()[0] == "version") {
		return true
	}

	if context.NArg() >= 2 && (context.Args()[1] == "-h" || context.Args()[1] == "--help") {
		return true
	}

	return false
}

// fatal prints the error's details exits the program.
func fatal(err error) {
	ccLog.Error(err)
	fmt.Fprintln(defaultErrorFile, err)
	exit(1)
}

type fatalWriter struct {
	cliErrWriter io.Writer
}

func (f *fatalWriter) Write(p []byte) (n int, err error) {
	// Ensure error is logged before displaying to the user
	ccLog.Error(string(p))
	return f.cliErrWriter.Write(p)
}

func createRuntime() {
	setCLIGlobals()

	err := createRuntimeApp(os.Args)
	if err != nil {
		fatal(err)
	}
}

func main() {
	createRuntime()
}
<commit_msg>logging: Add name to all log calls<commit_after>// Copyright (c) 2014,2015,2016 Docker, Inc.
// Copyright (c) 2017-2018 Intel Corporation
//
// 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 (
	"fmt"
	"io"
	"os"
	goruntime "runtime"
	"runtime/debug"
	"strings"

	vc "github.com/containers/virtcontainers"
	"github.com/containers/virtcontainers/pkg/oci"
	specs "github.com/opencontainers/runtime-spec/specs-go"
	"github.com/sirupsen/logrus"
	"github.com/urfave/cli"
)

// specConfig is the name of the file holding the containers configuration
const specConfig = "config.json"

// arch is the architecture for the running program
const arch = goruntime.GOARCH

var usage = fmt.Sprintf(`%s runtime

%s is a command line program for running applications packaged
according to the Open Container Initiative (OCI).`, name, name)

var notes = fmt.Sprintf(`
NOTES:

- Commands starting "%s-" and options starting "--%s-" are `+project+` extensions.

URL:

  The canonical URL for this project is: %s

`, projectPrefix, projectPrefix, projectURL)

// ccLog is the logger used to record all messages
var ccLog *logrus.Entry

// originalLoggerLevel is the default log level. It is used to revert the
// current log level back to its original value if debug output is not
// required.
var originalLoggerLevel logrus.Level

// concrete virtcontainer implementation
var virtcontainersImpl = &vc.VCImpl{}

// vci is used to access a particular virtcontainers implementation.
// Normally, it refers to the official package, but is re-assigned in
// the tests to allow virtcontainers to be mocked.
var vci vc.VC = virtcontainersImpl

// defaultOutputFile is the default output file to write the gathered
// information to.
var defaultOutputFile = os.Stdout

// defaultErrorFile is the default output file to write error
// messages to.
var defaultErrorFile = os.Stderr

// runtimeFlags is the list of supported global command-line flags
var runtimeFlags = []cli.Flag{
	cli.StringFlag{
		Name:  configFilePathOption,
		Usage: project + " config file path",
	},
	cli.StringFlag{
		Name:  "log",
		Value: "/dev/null",
		Usage: "set the log file path where internal debug information is written",
	},
	cli.StringFlag{
		Name:  "log-format",
		Value: "text",
		Usage: "set the format used by logs ('text' (default), or 'json')",
	},
	cli.StringFlag{
		Name:  "root",
		Value: defaultRootDirectory,
		Usage: "root directory for storage of container state (this should be located in tmpfs)",
	},
	cli.BoolFlag{
		Name:  showConfigPathsOption,
		Usage: "show config file paths that will be checked for (in order)",
	},
}

// runtimeCommands is the list of supported command-line (sub-)
// commands.
var runtimeCommands = []cli.Command{
	createCLICommand,
	deleteCLICommand,
	execCLICommand,
	killCLICommand,
	listCLICommand,
	pauseCLICommand,
	psCLICommand,
	resumeCLICommand,
	runCLICommand,
	startCLICommand,
	stateCLICommand,
	versionCLICommand,

	// Clear Containers specific extensions
	ccCheckCLICommand,
	ccEnvCLICommand,
}

// runtimeBeforeSubcommands is the function to run before command-line
// parsing occurs.
var runtimeBeforeSubcommands = beforeSubcommands

// runtimeCommandNotFound is the function to handle an invalid sub-command.
var runtimeCommandNotFound = commandNotFound

// runtimeVersion is the function that returns the full version
// string describing the runtime.
var runtimeVersion = makeVersionString

// saved default cli package values (for testing).
var savedCLIAppHelpTemplate = cli.AppHelpTemplate
var savedCLIVersionPrinter = cli.VersionPrinter
var savedCLIErrWriter = cli.ErrWriter

func init() {
	ccLog = logrus.WithFields(logrus.Fields{
		"name":   name,
		"source": "runtime",
		"pid":    os.Getpid(),
	})

	// Save the original log level and then set to debug level to ensure
	// that any problems detected before the config file is parsed are
	// logged. This is required since the config file determines the true
	// log level for the runtime: once parsed the log level is set
	// appropriately but for issues between now and completion of the
	// config file parsing, it is prudent to operate in verbose mode.
	originalLoggerLevel = ccLog.Logger.Level
	ccLog.Logger.Level = logrus.DebugLevel

	// Force a coredump + full stacktrace on internal error
	debug.SetTraceback("crash")
}

// beforeSubcommands is the function to perform preliminary checks
// before command-line parsing occurs.
func beforeSubcommands(context *cli.Context) error {
	if context.GlobalBool(showConfigPathsOption) {
		files := getDefaultConfigFilePaths()

		for _, file := range files {
			fmt.Fprintf(defaultOutputFile, "%s\n", file)
		}

		exit(0)
	}

	if userWantsUsage(context) || (context.NArg() == 1 && (context.Args()[0] == checkCmd)) {
		// No setup required if the user just
		// wants to see the usage statement or are
		// running a command that does not manipulate
		// containers.
		return nil
	}

	if path := context.GlobalString("log"); path != "" {
		f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_APPEND|os.O_SYNC, 0640)
		if err != nil {
			return err
		}
		ccLog.Logger.Out = f
	}

	switch context.GlobalString("log-format") {
	case "text":
		// retain logrus's default.
	case "json":
		ccLog.Logger.Formatter = new(logrus.JSONFormatter)
	default:
		return fmt.Errorf("unknown log-format %q", context.GlobalString("log-format"))
	}

	// Set virtcontainers logger.
	vci.SetLogger(ccLog)

	// Set the OCI package logger.
	oci.SetLogger(ccLog)

	ignoreLogging := false

	// Add the name of the sub-command to each log entry for easier
	// debugging.
	cmdName := context.Args().First()
	if context.App.Command(cmdName) != nil {
		ccLog = ccLog.WithField("command", cmdName)
	}

	if context.NArg() == 1 && context.Args()[0] == envCmd {
		// simply report the logging setup
		ignoreLogging = true
	}

	configFile, runtimeConfig, err := loadConfiguration(context.GlobalString(configFilePathOption), ignoreLogging)
	if err != nil {
		fatal(err)
	}

	args := strings.Join(context.Args(), " ")

	fields := logrus.Fields{
		"version":   version,
		"commit":    commit,
		"arguments": `"` + args + `"`,
	}

	ccLog.WithFields(fields).Info()

	// make the data accessible to the sub-commands.
	context.App.Metadata = map[string]interface{}{
		"runtimeConfig": runtimeConfig,
		"configFile":    configFile,
	}

	return nil
}

// function called when an invalid command is specified which causes the
// runtime to error.
func commandNotFound(c *cli.Context, command string) {
	err := fmt.Errorf("Invalid command %q", command)
	fatal(err)
}

// makeVersionString returns a multi-line string describing the runtime
// version along with the version of the OCI specification it supports.
func makeVersionString() string {
	v := make([]string, 0, 3)

	versionStr := version
	if versionStr == "" {
		versionStr = unknown
	}

	v = append(v, name+"  : "+versionStr)

	commitStr := commit
	if commitStr == "" {
		commitStr = unknown
	}

	v = append(v, "   commit   : "+commitStr)

	specVersionStr := specs.Version
	if specVersionStr == "" {
		specVersionStr = unknown
	}

	v = append(v, "   OCI specs: "+specVersionStr)

	return strings.Join(v, "\n")
}

// setCLIGlobals modifies various cli package global variables
func setCLIGlobals() {
	cli.AppHelpTemplate = fmt.Sprintf(`%s%s`, cli.AppHelpTemplate, notes)

	// Override the default function to display version details to
	// ensure the "--version" option and "version" command are identical.
	cli.VersionPrinter = func(c *cli.Context) {
		fmt.Fprintln(defaultOutputFile, c.App.Version)
	}

	// If the command returns an error, cli takes upon itself to print
	// the error on cli.ErrWriter and exit.
	// Use our own writer here to ensure the log gets sent to the right
	// location.
	cli.ErrWriter = &fatalWriter{cli.ErrWriter}
}

// createRuntimeApp creates an application to process the command-line
// arguments and invoke the requested runtime command.
func createRuntimeApp(args []string) error {
	app := cli.NewApp()

	app.Name = name
	app.Writer = defaultOutputFile
	app.Usage = usage
	app.CommandNotFound = runtimeCommandNotFound
	app.Version = runtimeVersion()
	app.Flags = runtimeFlags
	app.Commands = runtimeCommands
	app.Before = runtimeBeforeSubcommands
	app.EnableBashCompletion = true

	return app.Run(args)
}

// userWantsUsage determines if the user only wishes to see the usage
// statement.
func userWantsUsage(context *cli.Context) bool {
	if context.NArg() == 0 {
		return true
	}

	if context.NArg() == 1 && (context.Args()[0] == "help" || context.Args()[0] == "version") {
		return true
	}

	if context.NArg() >= 2 && (context.Args()[1] == "-h" || context.Args()[1] == "--help") {
		return true
	}

	return false
}

// fatal prints the error's details exits the program.
func fatal(err error) {
	ccLog.Error(err)
	fmt.Fprintln(defaultErrorFile, err)
	exit(1)
}

type fatalWriter struct {
	cliErrWriter io.Writer
}

func (f *fatalWriter) Write(p []byte) (n int, err error) {
	// Ensure error is logged before displaying to the user
	ccLog.Error(string(p))
	return f.cliErrWriter.Write(p)
}

func createRuntime() {
	setCLIGlobals()

	err := createRuntimeApp(os.Args)
	if err != nil {
		fatal(err)
	}
}

func main() {
	createRuntime()
}
<|endoftext|>


<commit_before>/* ELF tree - Tree viewer for ELF library dependency */
package main

import (
	"debug/elf"
	"fmt"
	"os"
	"path"
	"strings"
)

type DepsInfo struct {
	name  string
	path  string
	depth int
}

var (
	deps      map[string]bool
	deps_list []DepsInfo
	deflib    []string
	envlib    string
)

func init() {
	deps = make(map[string]bool)
	deflib = []string{"/lib/", "/usr/lib/"}
	envlib = os.Getenv("LD_LIBRARY_PATH")
}

func findLib(name string) string {
	if strings.Contains(name, "/") {
		return name
	}

	// check LD_LIBRARY_PATH environ
	for _, libpath := range strings.Split(envlib, ":") {
		fullpath := path.Join(libpath, name)
		if _, err := os.Stat(fullpath); err == nil {
			return fullpath
		}
	}

	// check default library directories
	for _, libpath := range deflib {
		fullpath := path.Join(libpath, name)
		if _, err := os.Stat(fullpath); err == nil {
			return fullpath
		}
	}
	return ""
}

func processDep(dep DepsInfo) {
	for i := 0; i < dep.depth; i++ {
		fmt.Printf("   ")
	}
	fmt.Println(dep.name)

	// skip duplicate libraries
	if _, ok := deps[dep.name]; ok {
		return
	}
	deps[dep.name] = true

	f, err := elf.Open(dep.path)
	if err != nil {
		fmt.Printf("%v: %s\n", err, dep.path)
		os.Exit(1)
	}
	defer f.Close()

	libs, err := f.ImportedLibraries()
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	var L []DepsInfo
	for _, soname := range libs {
		L = append(L, DepsInfo{soname, findLib(soname), dep.depth + 1})
	}

	deps_list = append(L, deps_list...)
}

func main() {
	if len(os.Args) < 2 {
		fmt.Println("Usage: elftree <executable>")
		os.Exit(1)
	}

	pathname := os.Args[1]
	f, err := elf.Open(pathname)
	if err != nil {
		fmt.Printf("%v: %s\n", err, pathname)
		os.Exit(1)
	}
	defer f.Close()

	deps_list = append(deps_list, DepsInfo{path.Base(pathname), pathname, 0})
	for len(deps_list) > 0 {
		// pop first element
		dep := deps_list[0]
		deps_list = deps_list[1:]

		processDep(dep)
	}
}
<commit_msg>Add -v option for file info<commit_after>/* ELF tree - Tree viewer for ELF library dependency */
package main

import (
	"debug/elf"
	"flag"
	"fmt"
	"os"
	"path"
	"path/filepath"
	"strings"
)

type DepsInfo struct {
	name  string
	path  string
	depth int
}

var (
	deps      map[string]bool
	deps_list []DepsInfo
	deflib    []string
	envlib    string
)

// command-line options
var (
	verbose bool
)

func init() {
	deps = make(map[string]bool)
	deflib = []string{"/lib/", "/usr/lib/"}
	envlib = os.Getenv("LD_LIBRARY_PATH")

	flag.BoolVar(&verbose, "v", false, "Show binary info")
}

func findLib(name string) string {
	if strings.Contains(name, "/") {
		return name
	}

	// check LD_LIBRARY_PATH environ
	for _, libpath := range strings.Split(envlib, ":") {
		fullpath := path.Join(libpath, name)
		if _, err := os.Stat(fullpath); err == nil {
			return fullpath
		}
	}

	// check default library directories
	for _, libpath := range deflib {
		fullpath := path.Join(libpath, name)
		if _, err := os.Stat(fullpath); err == nil {
			return fullpath
		}
	}
	return ""
}

func processDep(dep DepsInfo) {
	for i := 0; i < dep.depth; i++ {
		fmt.Printf("   ")
	}
	fmt.Println(dep.name)

	// skip duplicate libraries
	if _, ok := deps[dep.name]; ok {
		return
	}
	deps[dep.name] = true

	f, err := elf.Open(dep.path)
	if err != nil {
		fmt.Printf("%v: %s\n", err, dep.path)
		os.Exit(1)
	}
	defer f.Close()

	libs, err := f.ImportedLibraries()
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	var L []DepsInfo
	for _, soname := range libs {
		L = append(L, DepsInfo{soname, findLib(soname), dep.depth + 1})
	}

	deps_list = append(L, deps_list...)
}

func showDetails(f *elf.File, pathname string) {
	s := f.Section(".interp")
	if s == nil {
		fmt.Printf("static linked executable: %s\n", pathname)
		os.Exit(1)
	}
	interp, err := s.Data()
	if err != nil {
		fmt.Printf("%v: %s\n", err, pathname)
		os.Exit(1)
	}

	di_deps, err := f.ImportedLibraries()
	if err != nil {
		fmt.Printf("imported libraries: %v\n", err)
		os.Exit(1)
	}

	relpath, _ := filepath.EvalSymlinks(pathname)
	abspath, _ := filepath.Abs(relpath)

	fmt.Println()
	fmt.Printf("%s: %s\n", path.Base(pathname), abspath)
	fmt.Printf("  type:                     %s  (%s / %s / %s)\n",
		f.Type, f.Machine, f.Class, f.ByteOrder)
	fmt.Printf("  interpreter:              %s\n", string(interp))
	fmt.Printf("  total dependency:         %d\n", len(deps)-1) // exclude itself
	fmt.Printf("  direct dependency:        %d\n", len(di_deps))
}

func main() {
	flag.Parse()

	args := flag.Args()
	if len(args) < 1 {
		fmt.Println("Usage: elftree [<options>] <executable>")
		os.Exit(1)
	}

	pathname := args[0]
	f, err := elf.Open(pathname)
	if err != nil {
		fmt.Printf("%v: %s\n", err, pathname)
		os.Exit(1)
	}
	defer f.Close()

	deps_list = append(deps_list, DepsInfo{path.Base(pathname), pathname, 0})
	for len(deps_list) > 0 {
		// pop first element
		dep := deps_list[0]
		deps_list = deps_list[1:]

		processDep(dep)
	}

	if verbose {
		showDetails(f, pathname)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"log"
	"os"
	"path"
	"strings"

	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/sqlite"
	"github.com/zillolo/stash/stash"
)

const (
	ArchiveExtension = ".tar.gz"
	DataStoragePath  = "/.local/share/hidden"
	DatabaseFile     = "index.db"
)

func main() {
	flag.Parse()
	InitEnvironment()

	db, err := InitDB()
	if err != nil {
		log.Panicf("%v\n", err)
	}

	if len(flag.Args()) < 2 {
		flag.Usage()
	}

	source := flag.Arg(0)
	switch strings.ToLower(flag.Arg(0)) {
	case "list":
		source = "."
		if len(flag.Args()) >= 2 {
			source = flag.Arg(1)
		}
		if err := stash.List(db, source); err != nil {
			log.Panicf("%v\n", err)
		}
	case "release":
		source = "/home/alex/.local/share/hidden"
		target := flag.Arg(1)
		destination := "."

		if len(flag.Args()) >= 3 {
			destination = flag.Arg(2)
		}
		if err := stash.Release(db, source, target, destination); err != nil {
			log.Panicf("%v\n", err)
		}
	case "stash":
		source = flag.Arg(1)
		fallthrough
	default:
		if err := stash.Stash(db, source, "/home/alex/.local/share/hidden"); err != nil {
			log.Panicf("%v\n", err)
		}
	}
}

func InitEnvironment() {
	path := path.Join(getHome(), DataStoragePath)
	if _, err := os.Stat(path); os.IsNotExist(err) {
		if err = os.Mkdir(path, 0755|os.ModeDir); err != nil {
			panic(err)
		}
	}
}

func InitDB() (db *gorm.DB, err error) {
	db, err = gorm.Open("sqlite3", path.Join(getHome(), DataStoragePath, DatabaseFile))
	if err != nil {
		return nil, err
	}

	if !db.HasTable(&stash.Entry{}) {
		db.CreateTable(&stash.Entry{})
	}
	return db, nil
}

//func Restore(path string) (err error) {
//	name := filepath.Join(getDataPath(), computeFilename(path))
//	name += ArchiveExtension
//
//	file, err := os.Open(name)
//	if err != nil {
//		return err
//	}
//	defer file.Close()
//
//	path, err = filepath.Abs(path)
//	if err != nil {
//		return err
//	}
//
//	if err := stash.Unpack(filepath.Dir(path), file); err != nil {
//		return err
//	}
//	return nil
//}

func getHome() string {
	homePath := os.Getenv("HOME")
	if homePath == "" {
		panic("Hide may not be used by non-humans.")
	}
	return homePath
}

func getDataPath() string {
	return path.Join(getHome(), DataStoragePath)
}
<commit_msg>Set logging to file and print better error messages<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"path"
	"strings"

	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/sqlite"
	"github.com/zillolo/stash/stash"
)

const (
	ArchiveExtension = ".tar.gz"
	DataStoragePath  = "/.local/share/hidden"
	DatabaseFile     = "index.db"
)

func main() {
	flag.Parse()

	InitEnvironment()
	InitLogging()

	db, err := InitDB()
	if err != nil {
		fmt.Printf("There was an error creating the database.\nMore info: %v\n", err)
		log.Printf("%v\n", err)
	}

	if len(flag.Args()) < 2 {
		flag.Usage()
	}

	source := flag.Arg(0)
	switch strings.ToLower(flag.Arg(0)) {
	case "list":
		source = "."
		if len(flag.Args()) >= 2 {
			source = flag.Arg(1)
		}
		if err := stash.List(db, source); err != nil {
			fmt.Printf("Could not list entries.\nMore info: %v\n", err)
			log.Printf("%v\n", err)
		}
	case "release":
		source = "/home/alex/.local/share/hidden"
		target := flag.Arg(1)
		destination := "."

		if len(flag.Args()) >= 3 {
			destination = flag.Arg(2)
		}
		if err := stash.Release(db, source, target, destination); err != nil {
			fmt.Printf("Could not release.\nMore info: %v\n", err)
			log.Printf("%v\n", err)
		}
	case "stash":
		source = flag.Arg(1)
		fallthrough
	default:
		if err := stash.Stash(db, source, "/home/alex/.local/share/hidden"); err != nil {
			fmt.Printf("Could not stash files.\nMore info: %v\n", err)
			log.Printf("%v\n", err)
		}
	}
}

func InitLogging() {
	file, err := os.OpenFile("stash.log", os.O_CREATE|os.O_APPEND, 0666)
	if err != nil {
		//TODO: Handle error here.
	}
	defer file.Close()

	log.SetOutput(file)
}

func InitEnvironment() {
	path := path.Join(getHome(), DataStoragePath)
	if _, err := os.Stat(path); os.IsNotExist(err) {
		if err = os.Mkdir(path, 0755|os.ModeDir); err != nil {
			panic(err)
		}
	}
}

func InitDB() (db *gorm.DB, err error) {
	db, err = gorm.Open("sqlite3", path.Join(getHome(), DataStoragePath, DatabaseFile))
	if err != nil {
		return nil, err
	}

	if !db.HasTable(&stash.Entry{}) {
		db.CreateTable(&stash.Entry{})
	}
	return db, nil
}

//func Restore(path string) (err error) {
//	name := filepath.Join(getDataPath(), computeFilename(path))
//	name += ArchiveExtension
//
//	file, err := os.Open(name)
//	if err != nil {
//		return err
//	}
//	defer file.Close()
//
//	path, err = filepath.Abs(path)
//	if err != nil {
//		return err
//	}
//
//	if err := stash.Unpack(filepath.Dir(path), file); err != nil {
//		return err
//	}
//	return nil
//}

func getHome() string {
	homePath := os.Getenv("HOME")
	if homePath == "" {
		panic("Hide may not be used by non-humans.")
	}
	return homePath
}

func getDataPath() string {
	return path.Join(getHome(), DataStoragePath)
}
<|endoftext|>


<commit_before>// Copyright 2016 Red Hat, Inc. and/or its affiliates
// and other contributors.
//
// 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
package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"
	"time"

	"github.com/yaacov/mohawk/backends"
	"github.com/yaacov/mohawk/router"
)

// VER the server version
const VER = "0.4.1"

func main() {
	var db backend.Backend

	// Get user options
	// 	port    - default to 8443
	// 	backend - default to random
	portPtr := flag.Int("port", 8443, "server port")
	backendPtr := flag.String("backend", "random", "the backend to use [random, sqlite]")
	apiPtr := flag.String("api", "0.21.0", "the hawkulr api to mimic [e.g. 0.8.9.Testing, 0.21.2.Final]")
	apiTLS := flag.String("tls", "true", "use TLS server")
	flag.Parse()

	// Create and init the backend
	if *backendPtr == "sqlite" {
		db = &backend.Sqlite{}
	} else {
		db = &backend.Random{}
	}
	db.Open()

	// h common variables to be used by all Handler functions
	// backend the backend to use for metrics source
	// version the Hawkular server version we mimic
	h := Handler{
		backend: db,
		version: *apiPtr,
	}

	// Create the routers
	// Requests not handled by the routers will be forworded to BadRequest Handler
	rRoot := router.Router{
		Prefix: "/",
		Next:   BadRequest{},
	}
	// Root Routing table
	rRoot.Add("GET", "oapi", h.GetAPIVersions)

	rAlerts := router.Router{
		Prefix: "/hawkular/alerts/",
		Next:   rRoot,
	}
	// Alerts Routing table
	rAlerts.Add("GET", "status", h.GetStatus)

	rMetrics := router.Router{
		Prefix: "/hawkular/metrics/",
		Next:   rAlerts,
	}
	// Metrics Routing table
	rMetrics.Add("GET", "status", h.GetStatus)
	rMetrics.Add("GET", "metrics", h.GetMetrics)

	// api version >= 0.16.0
	rMetrics.Add("GET", "gauges/:id/raw", h.GetData)
	rMetrics.Add("GET", "counters/:id/raw", h.GetData)
	rMetrics.Add("GET", "availability/:id/raw", h.GetData)

	rMetrics.Add("GET", "gauges/:id/stats", h.GetData)
	rMetrics.Add("GET", "counters/:id/stats", h.GetData)
	rMetrics.Add("GET", "availability/:id/stats", h.GetData)

	rMetrics.Add("POST", "gauges/raw", h.PostData)
	rMetrics.Add("POST", "counters/raw", h.PostData)

	rMetrics.Add("PUT", "gauges/:id/tags", h.PutTags)
	rMetrics.Add("PUT", "counters/:id/tags", h.PutTags)

	// api version < 0.16.0
	rMetrics.Add("GET", "gauges/:id/data", h.GetData)
	rMetrics.Add("GET", "counters/:id/data", h.GetData)
	rMetrics.Add("GET", "availability/:id/data", h.GetData)

	rMetrics.Add("POST", "gauges/data", h.PostData)
	rMetrics.Add("POST", "counters/data", h.PostData)

	// logger a logging middleware
	logger := Logger{
		Next: rMetrics,
	}

	// Run the server
	srv := &http.Server{
		Addr:           fmt.Sprintf("0.0.0.0:%d", *portPtr),
		Handler:        logger,
		ReadTimeout:    10 * time.Second,
		WriteTimeout:   10 * time.Second,
		MaxHeaderBytes: 1 << 20,
	}
	if *apiTLS == "true" {
		log.Printf("Start server, listen on https://%+v", srv.Addr)
		log.Fatal(srv.ListenAndServeTLS("server.pem", "server.key"))
	} else {
		log.Printf("Start server, listen on http://%+v", srv.Addr)
		log.Fatal(srv.ListenAndServe())
	}
}
<commit_msg>bump version<commit_after>// Copyright 2016 Red Hat, Inc. and/or its affiliates
// and other contributors.
//
// 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
package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"
	"time"

	"github.com/yaacov/mohawk/backends"
	"github.com/yaacov/mohawk/router"
)

// VER the server version
const VER = "0.4.2"

func main() {
	var db backend.Backend

	// Get user options
	// 	port    - default to 8443
	// 	backend - default to random
	portPtr := flag.Int("port", 8443, "server port")
	backendPtr := flag.String("backend", "random", "the backend to use [random, sqlite]")
	apiPtr := flag.String("api", "0.21.0", "the hawkulr api to mimic [e.g. 0.8.9.Testing, 0.21.2.Final]")
	apiTLS := flag.String("tls", "true", "use TLS server")
	flag.Parse()

	// Create and init the backend
	if *backendPtr == "sqlite" {
		db = &backend.Sqlite{}
	} else {
		db = &backend.Random{}
	}
	db.Open()

	// h common variables to be used by all Handler functions
	// backend the backend to use for metrics source
	// version the Hawkular server version we mimic
	h := Handler{
		backend: db,
		version: *apiPtr,
	}

	// Create the routers
	// Requests not handled by the routers will be forworded to BadRequest Handler
	rRoot := router.Router{
		Prefix: "/",
		Next:   BadRequest{},
	}
	// Root Routing table
	rRoot.Add("GET", "oapi", h.GetAPIVersions)

	rAlerts := router.Router{
		Prefix: "/hawkular/alerts/",
		Next:   rRoot,
	}
	// Alerts Routing table
	rAlerts.Add("GET", "status", h.GetStatus)

	rMetrics := router.Router{
		Prefix: "/hawkular/metrics/",
		Next:   rAlerts,
	}
	// Metrics Routing table
	rMetrics.Add("GET", "status", h.GetStatus)
	rMetrics.Add("GET", "metrics", h.GetMetrics)

	// api version >= 0.16.0
	rMetrics.Add("GET", "gauges/:id/raw", h.GetData)
	rMetrics.Add("GET", "counters/:id/raw", h.GetData)
	rMetrics.Add("GET", "availability/:id/raw", h.GetData)

	rMetrics.Add("GET", "gauges/:id/stats", h.GetData)
	rMetrics.Add("GET", "counters/:id/stats", h.GetData)
	rMetrics.Add("GET", "availability/:id/stats", h.GetData)

	rMetrics.Add("POST", "gauges/raw", h.PostData)
	rMetrics.Add("POST", "counters/raw", h.PostData)

	rMetrics.Add("PUT", "gauges/:id/tags", h.PutTags)
	rMetrics.Add("PUT", "counters/:id/tags", h.PutTags)

	// api version < 0.16.0
	rMetrics.Add("GET", "gauges/:id/data", h.GetData)
	rMetrics.Add("GET", "counters/:id/data", h.GetData)
	rMetrics.Add("GET", "availability/:id/data", h.GetData)

	rMetrics.Add("POST", "gauges/data", h.PostData)
	rMetrics.Add("POST", "counters/data", h.PostData)

	// logger a logging middleware
	logger := Logger{
		Next: rMetrics,
	}

	// Run the server
	srv := &http.Server{
		Addr:           fmt.Sprintf("0.0.0.0:%d", *portPtr),
		Handler:        logger,
		ReadTimeout:    10 * time.Second,
		WriteTimeout:   10 * time.Second,
		MaxHeaderBytes: 1 << 20,
	}
	if *apiTLS == "true" {
		log.Printf("Start server, listen on https://%+v", srv.Addr)
		log.Fatal(srv.ListenAndServeTLS("server.pem", "server.key"))
	} else {
		log.Printf("Start server, listen on http://%+v", srv.Addr)
		log.Fatal(srv.ListenAndServe())
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/xml"
	"log"
	"strings"
	"time"

	"github.com/PuerkitoBio/goquery"
	"github.com/nenadl/atom"
)

func ParsePage() (atom.Feed, error) {
	feed := atom.Feed{Logo: "https://www.openrightsgroup.org/assets/site/org/images/logo.png",
		Icon:    "https://www.openrightsgroup.org/assets/site/org/images/favicon.ico",
		ID:      "tag:openrightsgroup.org,2017-04-02:/blog/",
		Title:   "Open Rights Group",
		Updated: atom.Time(time.Now())}

	feed.Link = []atom.Link{atom.Link{Href: "https://www.openrightsgroup.org/blog/",
		Rel:      "alternate",
		Type:     "text/html",
		HrefLang: "en-gb"},
		atom.Link{Href: "https://tml.betterfeeds.org/org.atom",
			Rel:      "self",
			Type:     "application/atom+xml",
			HrefLang: "en-gb"}}

	doc, err := goquery.NewDocument("https://www.openrightsgroup.org/blog/")
	if err != nil {
		return atom.Feed{}, err
	}

	doc.Find(".container .post").Each(func(i int, s *goquery.Selection) {
		titleElement := s.Find("h2 a")

		entry := atom.Entry{Title: titleElement.Text()}

		entry.ID, _ = titleElement.Attr("href")
		entry.Link = []atom.Link{atom.Link{Href: entry.ID,
			Rel:      "alternate",
			Type:     "text/html",
			HrefLang: "en-gb"},
			atom.Link{Href: entry.ID + "#quip-topofcomments-qcom",
				Rel:      "replies",
				Type:     "text/html",
				HrefLang: "en-gb"}}

		postTime, _ := s.Find(".info span").Attr("datetime")
		entry.Updated = atom.TimeStr(postTime)

		authorName := s.Find(".info").Text()
		authorName = strings.Split(authorName, "|")[1]
		authorName = strings.Replace(authorName, "\n   ", "", 1)
		entry.Author = []atom.Person{atom.Person{Name: authorName}}

		content, _ := s.Find(".text").Html()
		entry.Content = &atom.Text{Type: "html", Body: content}

		feed.Entry = append(feed.Entry, entry)
	})

	return feed, nil
}

func main() {
	feed, _ := ParsePage()

	buffer, err := xml.MarshalIndent(feed, "", "	")
	if err != nil {
		log.Fatal(err)
	}

	log.Println("\n" + xml.Header + string(buffer))
}
<commit_msg>Print a valid feed to stdout<commit_after>package main

import (
	"encoding/xml"
	"fmt"
	"strings"
	"time"

	"github.com/PuerkitoBio/goquery"
	"github.com/nenadl/atom"
)

func ParsePage() (atom.Feed, error) {
	feed := atom.Feed{Logo: "https://www.openrightsgroup.org/assets/site/org/images/logo.png",
		Icon:    "https://www.openrightsgroup.org/assets/site/org/images/favicon.ico",
		ID:      "tag:openrightsgroup.org,2017-04-02:/blog/",
		Title:   "Open Rights Group",
		Updated: atom.Time(time.Now())}

	feed.Link = []atom.Link{atom.Link{Href: "https://www.openrightsgroup.org/blog/",
		Rel:      "alternate",
		Type:     "text/html",
		HrefLang: "en-gb"},
		atom.Link{Href: "https://tml.betterfeeds.org/org.atom",
			Rel:      "self",
			Type:     "application/atom+xml",
			HrefLang: "en-gb"}}

	doc, err := goquery.NewDocument("https://www.openrightsgroup.org/blog/")
	if err != nil {
		return atom.Feed{}, err
	}

	doc.Find(".container .post").Each(func(i int, s *goquery.Selection) {
		titleElement := s.Find("h2 a")

		entry := atom.Entry{Title: titleElement.Text()}

		entry.ID, _ = titleElement.Attr("href")
		entry.Link = []atom.Link{atom.Link{Href: entry.ID,
			Rel:      "alternate",
			Type:     "text/html",
			HrefLang: "en-gb"},
			atom.Link{Href: entry.ID + "#quip-topofcomments-qcom",
				Rel:      "replies",
				Type:     "text/html",
				HrefLang: "en-gb"}}

		postTime, _ := s.Find(".info span").Attr("datetime")
		entry.Updated = atom.TimeStr(postTime)

		authorName := s.Find(".info").Text()
		authorName = strings.Split(authorName, "|")[1]
		authorName = strings.Replace(authorName, "\n   ", "", 1)
		entry.Author = []atom.Person{atom.Person{Name: authorName}}

		content, _ := s.Find(".text").Html()
		entry.Content = &atom.Text{Type: "html", Body: content}

		feed.Entry = append(feed.Entry, entry)
	})

	return feed, nil
}

func main() {
	feed, _ := ParsePage()

	buffer, err := xml.MarshalIndent(feed, "", "	")
	if err != nil {
		fmt.Println(err)
		return
	}

	fmt.Println("\n" + xml.Header + string(buffer))
}
<|endoftext|>


<commit_before>package main

import (
	log "github.com/Sirupsen/logrus"
	"github.com/kawamuray/prometheus-exporter-harness/harness"
	c "github.com/matsumana/flink_exporter/collector"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/urfave/cli"
)

const (
	version = "0.1.0"
)

var (
	flinkJobManagerUrl string
)

type collector struct{}

func main() {
	opts := harness.NewExporterOpts("flink_exporter", version)
	opts.Init = initExporter
	opts.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "flink-job-manager-url",
			Usage: "flink job manager url",
			Value: "http://localhost:8081/",
		},
	}

	harness.Main(opts)
}

func initExporter(c *cli.Context, reg *harness.MetricRegistry) (harness.Collector, error) {
	flinkJobManagerUrl = c.String("flink-job-manager-url")
	log.Debug(flinkJobManagerUrl)

	// overview
	reg.Register("flink_overview_taskmanagers", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_overview_taskmanagers",
		Help: "flink overview taskmanagers",
	}))
	reg.Register("flink_overview_slots_total", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_overview_slots_total",
		Help: "flink overview slots-total",
	}))
	reg.Register("flink_overview_slots_available", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_overview_slots_available",
		Help: "flink overview slots-available",
	}))
	reg.Register("flink_overview_jobs_running", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_overview_jobs_running",
		Help: "flink overview jobs-running",
	}))
	reg.Register("flink_overview_jobs_finished", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_overview_jobs_finished",
		Help: "flink overview jobs-finished",
	}))
	reg.Register("flink_overview_jobs_cancelled", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_overview_jobs_cancelled",
		Help: "flink overview jobs-cancelled",
	}))
	reg.Register("flink_overview_jobs_failed", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_overview_jobs_failed",
		Help: "flink overview jobs-failed",
	}))

	// job status
	reg.Register("flink_job_status_created", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_job_status_created",
		Help: "flink job status created",
	}))
	reg.Register("flink_job_status_running", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_job_status_running",
		Help: "flink job status running",
	}))
	reg.Register("flink_job_status_failing", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_job_status_failing",
		Help: "flink job status failing",
	}))
	reg.Register("flink_job_status_failed", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_job_status_failed",
		Help: "flink job status failed",
	}))
	reg.Register("flink_job_status_cancelling", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_job_status_cancelling",
		Help: "flink job status cancelling",
	}))
	reg.Register("flink_job_status_canceled", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_job_status_canceled",
		Help: "flink job status canceled",
	}))
	reg.Register("flink_job_status_finished", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_job_status_finished",
		Help: "flink job status finished",
	}))
	reg.Register("flink_job_status_restarting", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_job_status_restarting",
		Help: "flink job status restarting",
	}))

	// Read/Write
	reg.Register("flink_read_bytes", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_read_bytes",
		Help: "flink read bytes",
	}))
	reg.Register("flink_read_records", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_read_records",
		Help: "flink read records",
	}))
	reg.Register("flink_write_bytes", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_write_bytes",
		Help: "flink write bytes",
	}))
	reg.Register("flink_write_records", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_write_records",
		Help: "flink write records",
	}))

	// checkpoint
	reg.Register("flink_checkpoint_count_avg", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_checkpoint_count_avg",
		Help: "flink checkpoint count avg",
	}))
	reg.Register("flink_checkpoint_count_min", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_checkpoint_count_min",
		Help: "flink checkpoint count min",
	}))
	reg.Register("flink_checkpoint_count_max", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_checkpoint_count_max",
		Help: "flink checkpoint count max",
	}))
	reg.Register("flink_checkpoint_duration_min", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_checkpoint_duration_min",
		Help: "flink checkpoint duration min",
	}))
	reg.Register("flink_checkpoint_duration_max", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_checkpoint_duration_max",
		Help: "flink checkpoint duration max",
	}))
	reg.Register("flink_checkpoint_duration_avg", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_checkpoint_duration_avg",
		Help: "flink checkpoint duration avg",
	}))
	reg.Register("flink_checkpoint_size_min", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_checkpoint_size_min",
		Help: "flink checkpoint size min",
	}))
	reg.Register("flink_checkpoint_size_max", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_checkpoint_size_max",
		Help: "flink checkpoint size max",
	}))
	reg.Register("flink_checkpoint_size_avg", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_checkpoint_size_avg",
		Help: "flink checkpoint size avg",
	}))

	return &collector{}, nil
}

func (col *collector) Collect(reg *harness.MetricRegistry) {
	// overview
	o := c.Overview{}
	overview := o.GetMetrics(flinkJobManagerUrl)
	reg.Get("flink_overview_taskmanagers").(prometheus.Gauge).Set(float64(overview.TaskManagers))
	reg.Get("flink_overview_slots_total").(prometheus.Gauge).Set(float64(overview.SlotsTotal))
	reg.Get("flink_overview_slots_available").(prometheus.Gauge).Set(float64(overview.SlotsAvailable))
	reg.Get("flink_overview_jobs_running").(prometheus.Gauge).Set(float64(overview.JobsRunning))
	reg.Get("flink_overview_jobs_finished").(prometheus.Gauge).Set(float64(overview.JobsFinished))
	reg.Get("flink_overview_jobs_cancelled").(prometheus.Gauge).Set(float64(overview.JobsCancelled))
	reg.Get("flink_overview_jobs_failed").(prometheus.Gauge).Set(float64(overview.JobsFailed))

	j := c.Job{}
	readWriteMertics, checkpoint, jobStatus := j.GetMetrics(flinkJobManagerUrl)

	// job status
	reg.Get("flink_job_status_created").(prometheus.Gauge).Set(float64(jobStatus.Created))
	reg.Get("flink_job_status_running").(prometheus.Gauge).Set(float64(jobStatus.Running))
	reg.Get("flink_job_status_failing").(prometheus.Gauge).Set(float64(jobStatus.Failing))
	reg.Get("flink_job_status_failed").(prometheus.Gauge).Set(float64(jobStatus.Failed))
	reg.Get("flink_job_status_cancelling").(prometheus.Gauge).Set(float64(jobStatus.Cancelling))
	reg.Get("flink_job_status_canceled").(prometheus.Gauge).Set(float64(jobStatus.Canceled))
	reg.Get("flink_job_status_finished").(prometheus.Gauge).Set(float64(jobStatus.Finished))
	reg.Get("flink_job_status_restarting").(prometheus.Gauge).Set(float64(jobStatus.Restarting))

	// Read/Write
	reg.Get("flink_read_bytes").(prometheus.Gauge).Set(float64(readWriteMertics.ReadBytes))
	reg.Get("flink_read_records").(prometheus.Gauge).Set(float64(readWriteMertics.ReadRecords))
	reg.Get("flink_write_bytes").(prometheus.Gauge).Set(float64(readWriteMertics.WriteBytes))
	reg.Get("flink_write_records").(prometheus.Gauge).Set(float64(readWriteMertics.WriteRecords))

	// checkpoint
	reg.Get("flink_checkpoint_count_min").(prometheus.Gauge).Set(float64(checkpoint.CountMin))
	reg.Get("flink_checkpoint_count_max").(prometheus.Gauge).Set(float64(checkpoint.CountMax))
	reg.Get("flink_checkpoint_count_avg").(prometheus.Gauge).Set(float64(checkpoint.CountAvg))
	reg.Get("flink_checkpoint_duration_min").(prometheus.Gauge).Set(float64(checkpoint.DurationMin))
	reg.Get("flink_checkpoint_duration_max").(prometheus.Gauge).Set(float64(checkpoint.DurationMax))
	reg.Get("flink_checkpoint_duration_avg").(prometheus.Gauge).Set(float64(checkpoint.DurationAvg))
	reg.Get("flink_checkpoint_size_min").(prometheus.Gauge).Set(float64(checkpoint.SizeMin))
	reg.Get("flink_checkpoint_size_max").(prometheus.Gauge).Set(float64(checkpoint.SizeMax))
	reg.Get("flink_checkpoint_size_avg").(prometheus.Gauge).Set(float64(checkpoint.SizeAvg))
}
<commit_msg>bump version to 0.1.1<commit_after>package main

import (
	log "github.com/Sirupsen/logrus"
	"github.com/kawamuray/prometheus-exporter-harness/harness"
	c "github.com/matsumana/flink_exporter/collector"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/urfave/cli"
)

const (
	version = "0.1.1"
)

var (
	flinkJobManagerUrl string
)

type collector struct{}

func main() {
	opts := harness.NewExporterOpts("flink_exporter", version)
	opts.Init = initExporter
	opts.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "flink-job-manager-url",
			Usage: "flink job manager url",
			Value: "http://localhost:8081/",
		},
	}

	harness.Main(opts)
}

func initExporter(c *cli.Context, reg *harness.MetricRegistry) (harness.Collector, error) {
	flinkJobManagerUrl = c.String("flink-job-manager-url")
	log.Debug(flinkJobManagerUrl)

	// overview
	reg.Register("flink_overview_taskmanagers", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_overview_taskmanagers",
		Help: "flink overview taskmanagers",
	}))
	reg.Register("flink_overview_slots_total", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_overview_slots_total",
		Help: "flink overview slots-total",
	}))
	reg.Register("flink_overview_slots_available", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_overview_slots_available",
		Help: "flink overview slots-available",
	}))
	reg.Register("flink_overview_jobs_running", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_overview_jobs_running",
		Help: "flink overview jobs-running",
	}))
	reg.Register("flink_overview_jobs_finished", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_overview_jobs_finished",
		Help: "flink overview jobs-finished",
	}))
	reg.Register("flink_overview_jobs_cancelled", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_overview_jobs_cancelled",
		Help: "flink overview jobs-cancelled",
	}))
	reg.Register("flink_overview_jobs_failed", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_overview_jobs_failed",
		Help: "flink overview jobs-failed",
	}))

	// job status
	reg.Register("flink_job_status_created", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_job_status_created",
		Help: "flink job status created",
	}))
	reg.Register("flink_job_status_running", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_job_status_running",
		Help: "flink job status running",
	}))
	reg.Register("flink_job_status_failing", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_job_status_failing",
		Help: "flink job status failing",
	}))
	reg.Register("flink_job_status_failed", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_job_status_failed",
		Help: "flink job status failed",
	}))
	reg.Register("flink_job_status_cancelling", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_job_status_cancelling",
		Help: "flink job status cancelling",
	}))
	reg.Register("flink_job_status_canceled", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_job_status_canceled",
		Help: "flink job status canceled",
	}))
	reg.Register("flink_job_status_finished", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_job_status_finished",
		Help: "flink job status finished",
	}))
	reg.Register("flink_job_status_restarting", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_job_status_restarting",
		Help: "flink job status restarting",
	}))

	// Read/Write
	reg.Register("flink_read_bytes", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_read_bytes",
		Help: "flink read bytes",
	}))
	reg.Register("flink_read_records", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_read_records",
		Help: "flink read records",
	}))
	reg.Register("flink_write_bytes", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_write_bytes",
		Help: "flink write bytes",
	}))
	reg.Register("flink_write_records", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_write_records",
		Help: "flink write records",
	}))

	// checkpoint
	reg.Register("flink_checkpoint_count_avg", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_checkpoint_count_avg",
		Help: "flink checkpoint count avg",
	}))
	reg.Register("flink_checkpoint_count_min", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_checkpoint_count_min",
		Help: "flink checkpoint count min",
	}))
	reg.Register("flink_checkpoint_count_max", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_checkpoint_count_max",
		Help: "flink checkpoint count max",
	}))
	reg.Register("flink_checkpoint_duration_min", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_checkpoint_duration_min",
		Help: "flink checkpoint duration min",
	}))
	reg.Register("flink_checkpoint_duration_max", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_checkpoint_duration_max",
		Help: "flink checkpoint duration max",
	}))
	reg.Register("flink_checkpoint_duration_avg", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_checkpoint_duration_avg",
		Help: "flink checkpoint duration avg",
	}))
	reg.Register("flink_checkpoint_size_min", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_checkpoint_size_min",
		Help: "flink checkpoint size min",
	}))
	reg.Register("flink_checkpoint_size_max", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_checkpoint_size_max",
		Help: "flink checkpoint size max",
	}))
	reg.Register("flink_checkpoint_size_avg", prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "flink_checkpoint_size_avg",
		Help: "flink checkpoint size avg",
	}))

	return &collector{}, nil
}

func (col *collector) Collect(reg *harness.MetricRegistry) {
	// overview
	o := c.Overview{}
	overview := o.GetMetrics(flinkJobManagerUrl)
	reg.Get("flink_overview_taskmanagers").(prometheus.Gauge).Set(float64(overview.TaskManagers))
	reg.Get("flink_overview_slots_total").(prometheus.Gauge).Set(float64(overview.SlotsTotal))
	reg.Get("flink_overview_slots_available").(prometheus.Gauge).Set(float64(overview.SlotsAvailable))
	reg.Get("flink_overview_jobs_running").(prometheus.Gauge).Set(float64(overview.JobsRunning))
	reg.Get("flink_overview_jobs_finished").(prometheus.Gauge).Set(float64(overview.JobsFinished))
	reg.Get("flink_overview_jobs_cancelled").(prometheus.Gauge).Set(float64(overview.JobsCancelled))
	reg.Get("flink_overview_jobs_failed").(prometheus.Gauge).Set(float64(overview.JobsFailed))

	j := c.Job{}
	readWriteMertics, checkpoint, jobStatus := j.GetMetrics(flinkJobManagerUrl)

	// job status
	reg.Get("flink_job_status_created").(prometheus.Gauge).Set(float64(jobStatus.Created))
	reg.Get("flink_job_status_running").(prometheus.Gauge).Set(float64(jobStatus.Running))
	reg.Get("flink_job_status_failing").(prometheus.Gauge).Set(float64(jobStatus.Failing))
	reg.Get("flink_job_status_failed").(prometheus.Gauge).Set(float64(jobStatus.Failed))
	reg.Get("flink_job_status_cancelling").(prometheus.Gauge).Set(float64(jobStatus.Cancelling))
	reg.Get("flink_job_status_canceled").(prometheus.Gauge).Set(float64(jobStatus.Canceled))
	reg.Get("flink_job_status_finished").(prometheus.Gauge).Set(float64(jobStatus.Finished))
	reg.Get("flink_job_status_restarting").(prometheus.Gauge).Set(float64(jobStatus.Restarting))

	// Read/Write
	reg.Get("flink_read_bytes").(prometheus.Gauge).Set(float64(readWriteMertics.ReadBytes))
	reg.Get("flink_read_records").(prometheus.Gauge).Set(float64(readWriteMertics.ReadRecords))
	reg.Get("flink_write_bytes").(prometheus.Gauge).Set(float64(readWriteMertics.WriteBytes))
	reg.Get("flink_write_records").(prometheus.Gauge).Set(float64(readWriteMertics.WriteRecords))

	// checkpoint
	reg.Get("flink_checkpoint_count_min").(prometheus.Gauge).Set(float64(checkpoint.CountMin))
	reg.Get("flink_checkpoint_count_max").(prometheus.Gauge).Set(float64(checkpoint.CountMax))
	reg.Get("flink_checkpoint_count_avg").(prometheus.Gauge).Set(float64(checkpoint.CountAvg))
	reg.Get("flink_checkpoint_duration_min").(prometheus.Gauge).Set(float64(checkpoint.DurationMin))
	reg.Get("flink_checkpoint_duration_max").(prometheus.Gauge).Set(float64(checkpoint.DurationMax))
	reg.Get("flink_checkpoint_duration_avg").(prometheus.Gauge).Set(float64(checkpoint.DurationAvg))
	reg.Get("flink_checkpoint_size_min").(prometheus.Gauge).Set(float64(checkpoint.SizeMin))
	reg.Get("flink_checkpoint_size_max").(prometheus.Gauge).Set(float64(checkpoint.SizeMax))
	reg.Get("flink_checkpoint_size_avg").(prometheus.Gauge).Set(float64(checkpoint.SizeAvg))
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/kr/beanstalk"
	"github.com/peterh/liner"
	"os"
	"os/signal"
	"strconv"
	"strings"
	"time"
)

var (
	// Used for autocompletion.
	commands = []string{
		"clear",
		"help",
		"inspect",
		"exit",
		"quit",
		"kick",
		"list",
		"next",
		"pause",
		"stats",
		"use",
	}
	hf     = "/tmp/.bsa_history"
	conn   *beanstalk.Conn // Our one and only beanstalkd connection.
	line   *liner.State
	sigc   chan os.Signal   // Signal channel.
	ctubes []beanstalk.Tube // The currently selected tubes.
)

// Prints help and usage.
func help() {
	fmt.Printf(`
clear <state>
	Deletes all jobs in given state and selected tubes.
	<state> may be either 'ready', 'buried' or 'delayed'.

help
	Show this wonderful help.

exit,
quit
	Exit the console.

inspect <job>
	Inspects a single job.

pause <delay>
	Pauses selected tubes for given number of seconds.

kick <bound>
	Kicks all jobs in selected tubes.

list
	Lists all selected tubes or if none is selected all exstings tubes
	and shows status of each.

next <state>
	Inspects next jobs in given state in selected tubes.
	<state> may be either 'ready', 'buried' or 'delayed'.

stats
	Shows server statistics.

use [<tube0>] [<tube1> ...]
	Selects one or multiple tubes. Separate multiple tubes by spaces.
	If no tube name is given resets selection.

`)
}

func cleanup() {
	conn.Close()

	if f, err := os.Create(hf); err == nil {
		line.WriteHistory(f)
		f.Close()
	}
	line.Close()
}

func main() {
	fmt.Print("Enter 'help' for available commands and 'exit' to quit.\n\n")

	// Setup connection to server.
	var err error
	if conn, err = beanstalk.Dial("tcp", "127.0.0.1:11300"); err != nil {
		panic("Failed to connect to beanstalkd server.")
	}

	// Register signal handler.
	sigc = make(chan os.Signal, 1)
	signal.Notify(sigc, os.Interrupt)
	go func() {
		for sig := range sigc {
			fmt.Printf("Caught %v. Bye.\n", sig)
			cleanup()
			os.Exit(1)
		}
	}()

	//
	line = liner.NewLiner()

	// Autocomplete commands, tube names and states.
	line.SetCompleter(func(line string) (c []string) {
		for _, cmd := range commands {
			if strings.HasPrefix(cmd, line) {
				c = append(c, cmd)
			}
		}
		if strings.HasPrefix(line, "use") {
			tns, _ := conn.ListTubes()
			for _, v := range tns {
				c = append(c, fmt.Sprintf("%s%s", line, v))
			}
		}
		if strings.HasPrefix(line, "clear") || strings.HasPrefix(line, "next") {
			for _, v := range []string{"ready", "delayed", "buried"} {
				c = append(c, fmt.Sprintf("%s%s", line, v))
			}
		}
		return c
	})

	// Load console history if possible.
	if f, err := os.Open(hf); err == nil {
		line.ReadHistory(f)
		f.Close()
	}

	// Dispatch commands.
	for {
		// We may have a new set of selected tubes after an iteration, update prompt.
		// Show selected tubes in prompt, so that we know what commands operate on.
		var names []string
		for _, t := range ctubes {
			names = append(names, t.Name)
		}
		prompt := fmt.Sprintf("beanstalkd [%s] > ", strings.Join(names, ", "))

		if input, err := line.Prompt(prompt); err == nil {
			// Always add input to history, even if it contains a syntax error. We
			// may want to skip back and correct ourselves.
			line.AppendHistory(input)

			args := strings.Split(input, " ")

			switch args[0] {
			case "exit", "quit":
				cleanup()
				os.Exit(0)
			case "help":
				help()
			case "stats":
				stats()
			case "use":
				ctubes = ctubes[:0]

				if len(args) < 2 {
					continue // Just reset.
				}
				if err := useTubes(args[1:]); err != nil {
					fmt.Printf("Error: %s.\n", err)
				}
			case "list":
				var reset bool = false

				if len(ctubes) == 0 {
					// Temporarily select all tubes.
					reset = true

					// Do not need to check if tubes are valid names as we just
					// use the list of available ones.
					tns, _ := conn.ListTubes()
					useTubes(tns)
				}
				listTubes()

				if reset {
					// Revert temporary selection back again.
					ctubes = ctubes[:0]
				}
			case "pause":
				if len(args) < 2 {
					fmt.Printf("Error: no delay given.\n")
					continue
				}
				if r, err := strconv.ParseUint(args[1], 0, 0); err == nil {
					pauseTubes(time.Duration(r) * time.Second)
					continue
				}
				fmt.Printf("Error: given delay is not a valid number.\n")
			case "kick":
				if len(args) < 2 {
					fmt.Printf("Error: no bound given.\n")
					continue
				}
				if r, err := strconv.ParseUint(args[1], 0, 0); err == nil {
					kickTubes(int(r))
					continue
				}
				fmt.Printf("Error: given bound is not a valid number.\n")
			case "clear":
				if len(args) < 2 {
					fmt.Printf("Error: no state given.\n")
					continue
				}
				clearTubes(args[1])
			case "next":
				if len(args) < 2 {
					fmt.Printf("Error: no state given.\n")
					continue
				}
				nextJobs(args[1])
			case "inspect":
				if len(args) < 2 {
					fmt.Printf("Error: no job id given.\n")
					continue
				}
				if r, err := strconv.ParseUint(args[1], 0, 0); err == nil {
					inspectJob(uint64(r))
					continue
				}
				fmt.Printf("Error: not a valid job id.\n")
			case "":
				continue
			default:
				fmt.Println("Error: unknown command.")
				continue
			}
		}
	}
}
<commit_msg>Just exit and do not panic on missing conn.<commit_after>package main

import (
	"fmt"
	"github.com/kr/beanstalk"
	"github.com/peterh/liner"
	"os"
	"os/signal"
	"strconv"
	"strings"
	"time"
)

var (
	// Used for autocompletion.
	commands = []string{
		"clear",
		"help",
		"inspect",
		"exit",
		"quit",
		"kick",
		"list",
		"next",
		"pause",
		"stats",
		"use",
	}
	hf     = "/tmp/.bsa_history"
	conn   *beanstalk.Conn // Our one and only beanstalkd connection.
	line   *liner.State
	sigc   chan os.Signal   // Signal channel.
	ctubes []beanstalk.Tube // The currently selected tubes.
)

// Prints help and usage.
func help() {
	fmt.Printf(`
clear <state>
	Deletes all jobs in given state and selected tubes.
	<state> may be either 'ready', 'buried' or 'delayed'.

help
	Show this wonderful help.

exit,
quit
	Exit the console.

inspect <job>
	Inspects a single job.

pause <delay>
	Pauses selected tubes for given number of seconds.

kick <bound>
	Kicks all jobs in selected tubes.

list
	Lists all selected tubes or if none is selected all exstings tubes
	and shows status of each.

next <state>
	Inspects next jobs in given state in selected tubes.
	<state> may be either 'ready', 'buried' or 'delayed'.

stats
	Shows server statistics.

use [<tube0>] [<tube1> ...]
	Selects one or multiple tubes. Separate multiple tubes by spaces.
	If no tube name is given resets selection.

`)
}

func cleanup() {
	conn.Close()

	if f, err := os.Create(hf); err == nil {
		line.WriteHistory(f)
		f.Close()
	}
	line.Close()
}

func main() {
	var err error
	if conn, err = beanstalk.Dial("tcp", "127.0.0.1:11300"); err != nil {
		fmt.Println("Fatal: failed to connect to beanstalkd server.")
		cleanup()
		os.Exit(1)
	}

	// Register signal handler.
	sigc = make(chan os.Signal, 1)
	signal.Notify(sigc, os.Interrupt)
	go func() {
		for sig := range sigc {
			fmt.Printf("Caught %v. Bye.\n", sig)
			cleanup()
			os.Exit(1)
		}
	}()

	//
	line = liner.NewLiner()

	// Autocomplete commands, tube names and states.
	line.SetCompleter(func(line string) (c []string) {
		for _, cmd := range commands {
			if strings.HasPrefix(cmd, line) {
				c = append(c, cmd)
			}
		}
		if strings.HasPrefix(line, "use") {
			tns, _ := conn.ListTubes()
			for _, v := range tns {
				c = append(c, fmt.Sprintf("%s%s", line, v))
			}
		}
		if strings.HasPrefix(line, "clear") || strings.HasPrefix(line, "next") {
			for _, v := range []string{"ready", "delayed", "buried"} {
				c = append(c, fmt.Sprintf("%s%s", line, v))
			}
		}
		return c
	})

	// Load console history if possible.
	if f, err := os.Open(hf); err == nil {
		line.ReadHistory(f)
		f.Close()
	}

	fmt.Print("Enter 'help' for available commands and 'exit' to quit.\n\n")

	// Dispatch commands.
	for {
		// We may have a new set of selected tubes after an iteration, update prompt.
		// Show selected tubes in prompt, so that we know what commands operate on.
		var names []string
		for _, t := range ctubes {
			names = append(names, t.Name)
		}
		prompt := fmt.Sprintf("beanstalkd [%s] > ", strings.Join(names, ", "))

		if input, err := line.Prompt(prompt); err == nil {
			// Always add input to history, even if it contains a syntax error. We
			// may want to skip back and correct ourselves.
			line.AppendHistory(input)

			args := strings.Split(input, " ")

			switch args[0] {
			case "exit", "quit":
				cleanup()
				os.Exit(0)
			case "help":
				help()
			case "stats":
				stats()
			case "use":
				ctubes = ctubes[:0]

				if len(args) < 2 {
					continue // Just reset.
				}
				if err := useTubes(args[1:]); err != nil {
					fmt.Printf("Error: %s.\n", err)
				}
			case "list":
				var reset bool = false

				if len(ctubes) == 0 {
					// Temporarily select all tubes.
					reset = true

					// Do not need to check if tubes are valid names as we just
					// use the list of available ones.
					tns, _ := conn.ListTubes()
					useTubes(tns)
				}
				listTubes()

				if reset {
					// Revert temporary selection back again.
					ctubes = ctubes[:0]
				}
			case "pause":
				if len(args) < 2 {
					fmt.Printf("Error: no delay given.\n")
					continue
				}
				if r, err := strconv.ParseUint(args[1], 0, 0); err == nil {
					pauseTubes(time.Duration(r) * time.Second)
					continue
				}
				fmt.Printf("Error: given delay is not a valid number.\n")
			case "kick":
				if len(args) < 2 {
					fmt.Printf("Error: no bound given.\n")
					continue
				}
				if r, err := strconv.ParseUint(args[1], 0, 0); err == nil {
					kickTubes(int(r))
					continue
				}
				fmt.Printf("Error: given bound is not a valid number.\n")
			case "clear":
				if len(args) < 2 {
					fmt.Printf("Error: no state given.\n")
					continue
				}
				clearTubes(args[1])
			case "next":
				if len(args) < 2 {
					fmt.Printf("Error: no state given.\n")
					continue
				}
				nextJobs(args[1])
			case "inspect":
				if len(args) < 2 {
					fmt.Printf("Error: no job id given.\n")
					continue
				}
				if r, err := strconv.ParseUint(args[1], 0, 0); err == nil {
					inspectJob(uint64(r))
					continue
				}
				fmt.Printf("Error: not a valid job id.\n")
			case "":
				continue
			default:
				fmt.Println("Error: unknown command.")
				continue
			}
		}
	}
}
<|endoftext|>


<commit_before>// pbullet project main.go
package main

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

var pushUrl string

type PushDev struct {
	Id string
}

func SetAPIKey(apiKey string) {
	pUrl := url.URL{}
	pUrl.Scheme = "https"
	pUrl.User = url.UserPassword(apiKey, "")
	pUrl.Host = "www.pushbullet.com"
	pUrl.Path = "/api/pushes"
	pushUrl = pUrl.String()
}

func (pd *PushDev) PushNote(title, body string) (resp *http.Response, err error) {
	pushVals := url.Values{}
	pushVals.Set("device_id", pd.Id)
	pushVals.Set("type", "note")
	pushVals.Set("title", title)
	pushVals.Set("body", body)

	return http.PostForm(pushUrl, pushVals)
}

func (pd *PushDev) PushAddress(name, address string) (resp *http.Response, err error) {
	pushVals := url.Values{}
	pushVals.Set("device_id", pd.Id)
	pushVals.Set("type", "note")
	pushVals.Set("name", name)
	pushVals.Set("address", address)

	return http.PostForm(pushUrl, pushVals)
}

func (pd *PushDev) PushLink(title, urlAddress string) (resp *http.Response, err error) {
	pushVals := url.Values{}
	pushVals.Set("device_id", pd.Id)
	pushVals.Set("type", "note")
	pushVals.Set("title", title)
	pushVals.Set("url", urlAddress)

	return http.PostForm(pushUrl, pushVals)
}

func main() {
	SetAPIKey("e4ac3e11929d522888c58ed67268b643")

	pushDev := &PushDev{"37413"}

	resp, err := pushDev.PushNote("testy sub", "long body orar\n \" ya")
	fmt.Println(resp)
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println("Hello World!")
}
<commit_msg>Get Devices<commit_after>// pbullet project main.go
package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"strconv"
)

var pushUrl string
var getUrl string

type DeviceInfo struct {
	Manufacturer   string `json:"manufacturer"`
	Model          string `json:"model"`
	AndroidVersion string `json:"android_version"`
	SDKVersion     string `json:"sdk_version"`
	AppVersion     string `json:"app_version"`
	Nickname       string `json:"nickname"`
}

type Device struct {
	Id      int        `json:"id"`
	DevInfo DeviceInfo `json:"extras"`
	Owner   string     `json:"owner_name"`
}

type DeviceList struct {
	Devices       []Device `json:"devices"`
	SharedDevices []Device `json:"shared_devices"`
}

func SetAPIKey(apiKey string) {
	pUrl := url.URL{}
	pUrl.Scheme = "https"
	pUrl.User = url.UserPassword(apiKey, "")
	pUrl.Host = "www.pushbullet.com"
	pUrl.Path = "/api/pushes"
	pushUrl = pUrl.String()

	gUrl := url.URL{}
	gUrl.Scheme = "https"
	gUrl.User = url.UserPassword(apiKey, "")
	gUrl.Host = "www.pushbullet.com"
	gUrl.Path = "/api/devices"
	getUrl = gUrl.String()
}

func GetDevices() (DeviceList, error) {
	var devList DeviceList
	resp, err := http.Get(getUrl)
	if err != nil {
		return devList, err
	}
	fmt.Println(resp)
	respBytes, _ := ioutil.ReadAll(resp.Body)
	err = json.Unmarshal(respBytes, &devList)
	return devList, err
}

func (pd *Device) PushNote(title, body string) (resp *http.Response, err error) {
	pushVals := url.Values{}
	pushVals.Set("device_id", strconv.Itoa(pd.Id))
	pushVals.Set("type", "note")
	pushVals.Set("title", title)
	pushVals.Set("body", body)

	return http.PostForm(pushUrl, pushVals)
}

func (pd *Device) PushAddress(name, address string) (resp *http.Response, err error) {
	pushVals := url.Values{}
	pushVals.Set("device_id", strconv.Itoa(pd.Id))
	pushVals.Set("type", "note")
	pushVals.Set("name", name)
	pushVals.Set("address", address)

	return http.PostForm(pushUrl, pushVals)
}

func (pd *Device) PushLink(title, urlAddress string) (resp *http.Response, err error) {
	pushVals := url.Values{}
	pushVals.Set("device_id", strconv.Itoa(pd.Id))
	pushVals.Set("type", "note")
	pushVals.Set("title", title)
	pushVals.Set("url", urlAddress)

	return http.PostForm(pushUrl, pushVals)
}

func main() {
	SetAPIKey("e4ac3e11929d522888c58ed67268b643")

	devList, err := GetDevices()
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println(devList)
	for _, dev := range devList.Devices {
		_, pushErr := dev.PushNote("testy sub", "body")
		if pushErr != nil {
			fmt.Println(err)
		}
	}
	fmt.Println("Done")
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"os"

	fm "github.com/enocom/fm/lib"
)

// Version designates the currently released version of fm
const Version = "1.1.0"

func main() {
	printVersion := flag.Bool("version", false, "Print version and exit")
	outputFilename := flag.String(
		"out",
		"fm_test.go",
		"Name of output file with generated spies",
	)
	workingDir := flag.String(
		"dir",
		".",
		"Directory to search for interfaces",
	)
	flag.Parse()

	if *printVersion {
		fmt.Printf("fm version %s\n", Version)
		return
	}

	conv := &fm.SpyStructConverter{}
	impl := &fm.SpyFuncImplementer{}
	c := &fm.Cmd{
		DeclGenerator: &fm.SpyGenerator{Converter: conv, Implementer: impl},
		Parser:        &fm.SrcFileParser{},
		FileWriter:    &fm.DiskFileWriter{},
	}

	err := c.Run(*workingDir, *outputFilename)
	if err != nil {
		fmt.Printf("Error %v\n", err)
		os.Exit(1)
	}
}
<commit_msg>Simplify main setup<commit_after>package main

import (
	"flag"
	"fmt"
	"os"

	fm "github.com/enocom/fm/lib"
)

// Version designates the currently released version of fm
const Version = "1.1.0"

func main() {
	printVersion := flag.Bool("version", false, "Print version and exit")
	outputFilename := flag.String(
		"out",
		"fm_test.go",
		"Name of output file with generated spies",
	)
	workingDir := flag.String(
		"dir",
		".",
		"Directory to search for interfaces",
	)
	flag.Parse()

	if *printVersion {
		fmt.Printf("fm version %s\n", Version)
		return
	}

	c := &fm.Cmd{
		DeclGenerator: &fm.SpyGenerator{
			Converter:   &fm.SpyStructConverter{},
			Implementer: &fm.SpyFuncImplementer{},
		},
		Parser:     &fm.SrcFileParser{},
		FileWriter: &fm.DiskFileWriter{},
	}

	err := c.Run(*workingDir, *outputFilename)
	if err != nil {
		fmt.Printf("Error %v\n", err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

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

	"crypto/tls"
	"crypto/x509"
	"github.com/prometheus/client_golang/prometheus"
	"io/ioutil"
)

const (
	namespace = "elasticsearch"
	indexHTML = `

			<title>Elasticsearch Exporter</title>

Elasticsearch Exporter

			Metrics

	`
)

func main() {
	var (
		listenAddress      = flag.String("web.listen-address", ":9108", "Address to listen on for web interface and telemetry.")
		metricsPath        = flag.String("web.telemetry-path", "/metrics", "Path under which to expose metrics.")
		esHostname         = flag.String("es.hostname", localhost", "hostname of an Elasticsearch node, where client http is enabled.")
		esProtocol         = flag.String("es.protocol", http", "http/https protocol of an Elasticsearch node")
		esPort             = flag.String("es.port", 9200", "Port of an Elasticsearch node 9200 or 443")
		esUser             = flag.String("es.user", "username", "HTTP username for basic auth of an Elasticsearch node.")
		esPassword         = flag.String("es.password", "password", "HTTP password for basic auth of an Elasticsearch node.")
		esTimeout          = flag.Duration("es.timeout", 5*time.Second, "Timeout for trying to get stats from Elasticsearch.")
		esAllNodes         = flag.Bool("es.all", false, "Export stats for all nodes in the cluster.")
		esCA               = flag.String("es.ca", "", "Path to PEM file that conains trusted CAs for the Elasticsearch connection.")
		esClientPrivateKey = flag.String("es.client-private-key", "", "Path to PEM file that conains the private key for client auth when connecting to Elasticsearch.")
		esClientCert       = flag.String("es.client-cert", "", "Path to PEM file that conains the corresponding cert for the private key to connect to Elasticsearch.")
	)
	flag.Parse()

	nodesStatsURI := *esProtocol "://" + *esUser + ":" + *esPassword + "@" + *esURI + ":" + *esPort + "/" + "/_nodes/_local/stats"
	if *esAllNodes {
		nodesStatsURI = *esProtocol "://" + *esUser + ":" + *esPassword + "@" + *esURI + ":" + *esPort + "/" + "/_nodes/stats"
	}
	clusterHealthURI := *esProtocol "://" + *esUser + ":" + *esPassword + "@" + *esURI + ":" + *esPort + "/" + "/_cluster/health"

	exporter := NewExporter(nodesStatsURI, clusterHealthURI, *esTimeout, *esAllNodes, createElasticSearchTlsConfig(*esCA, *esClientCert, *esClientPrivateKey))
	prometheus.MustRegister(exporter)

	log.Println("Starting Server:", *listenAddress)
	http.Handle(*metricsPath, prometheus.Handler())
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte(fmt.Sprintf(indexHTML, *metricsPath)))
	})
	log.Fatal(http.ListenAndServe(*listenAddress, nil))
}

func createElasticSearchTlsConfig(pemFile, pemCertFile, pemPrivateKeyFile string) *tls.Config {
	if len(pemFile) <= 0 {
		return nil
	}
	rootCerts, err := loadCertificatesFrom(pemFile)
	if err != nil {
		log.Fatalf("Couldn't load root certificate from %s. Got %s.", pemFile, err)
	}
	if len(pemCertFile) > 0 && len(pemPrivateKeyFile) > 0 {
		clientPrivateKey, err := loadPrivateKeyFrom(pemCertFile, pemPrivateKeyFile)
		if err != nil {
			log.Fatalf("Couldn't setup client authentication. Got %s.", err)
		}
		return &tls.Config{
			RootCAs:      rootCerts,
			Certificates: []tls.Certificate{*clientPrivateKey},
		}
	} else {
		return &tls.Config{
			RootCAs: rootCerts,
		}
	}
}

func loadCertificatesFrom(pemFile string) (*x509.CertPool, error) {
	caCert, err := ioutil.ReadFile(pemFile)
	if err != nil {
		return nil, err
	}
	certificates := x509.NewCertPool()
	certificates.AppendCertsFromPEM(caCert)
	return certificates, nil
}

func loadPrivateKeyFrom(pemCertFile, pemPrivateKeyFile string) (*tls.Certificate, error) {
	privateKey, err := tls.LoadX509KeyPair(pemCertFile, pemPrivateKeyFile)
	if err != nil {
		return nil, err
	}
	return &privateKey, nil
}
<commit_msg>fix typos<commit_after>package main

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

	"crypto/tls"
	"crypto/x509"
	"github.com/prometheus/client_golang/prometheus"
	"io/ioutil"
)

const (
	namespace = "elasticsearch"
	indexHTML = `

			<title>Elasticsearch Exporter</title>

Elasticsearch Exporter

			Metrics

	`
)

func main() {
	var (
		listenAddress      = flag.String("web.listen-address", ":9108", "Address to listen on for web interface and telemetry.")
		metricsPath        = flag.String("web.telemetry-path", "/metrics", "Path under which to expose metrics.")
		esHostname         = flag.String("es.hostname", "localhost", "hostname of an Elasticsearch node, where client http is enabled.")
		esProtocol         = flag.String("es.protocol", "http", "http/https protocol of an Elasticsearch node")
		esPort             = flag.String("es.port", "9200", "Port of an Elasticsearch node 9200 or 443")
		esUser             = flag.String("es.user", "username", "HTTP username for basic auth of an Elasticsearch node.")
		esPassword         = flag.String("es.password", "password", "HTTP password for basic auth of an Elasticsearch node.")
		esTimeout          = flag.Duration("es.timeout", 5*time.Second, "Timeout for trying to get stats from Elasticsearch.")
		esAllNodes         = flag.Bool("es.all", false, "Export stats for all nodes in the cluster.")
		esCA               = flag.String("es.ca", "", "Path to PEM file that conains trusted CAs for the Elasticsearch connection.")
		esClientPrivateKey = flag.String("es.client-private-key", "", "Path to PEM file that conains the private key for client auth when connecting to Elasticsearch.")
		esClientCert       = flag.String("es.client-cert", "", "Path to PEM file that conains the corresponding cert for the private key to connect to Elasticsearch.")
	)
	flag.Parse()

	nodesStatsURI := *esProtocol "://" + *esUser + ":" + *esPassword + "@" + *esURI + ":" + *esPort + "/" + "/_nodes/_local/stats"
	if *esAllNodes {
		nodesStatsURI = *esProtocol "://" + *esUser + ":" + *esPassword + "@" + *esURI + ":" + *esPort + "/" + "/_nodes/stats"
	}
	clusterHealthURI := *esProtocol "://" + *esUser + ":" + *esPassword + "@" + *esURI + ":" + *esPort + "/" + "/_cluster/health"

	exporter := NewExporter(nodesStatsURI, clusterHealthURI, *esTimeout, *esAllNodes, createElasticSearchTlsConfig(*esCA, *esClientCert, *esClientPrivateKey))
	prometheus.MustRegister(exporter)

	log.Println("Starting Server:", *listenAddress)
	http.Handle(*metricsPath, prometheus.Handler())
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte(fmt.Sprintf(indexHTML, *metricsPath)))
	})
	log.Fatal(http.ListenAndServe(*listenAddress, nil))
}

func createElasticSearchTlsConfig(pemFile, pemCertFile, pemPrivateKeyFile string) *tls.Config {
	if len(pemFile) <= 0 {
		return nil
	}
	rootCerts, err := loadCertificatesFrom(pemFile)
	if err != nil {
		log.Fatalf("Couldn't load root certificate from %s. Got %s.", pemFile, err)
	}
	if len(pemCertFile) > 0 && len(pemPrivateKeyFile) > 0 {
		clientPrivateKey, err := loadPrivateKeyFrom(pemCertFile, pemPrivateKeyFile)
		if err != nil {
			log.Fatalf("Couldn't setup client authentication. Got %s.", err)
		}
		return &tls.Config{
			RootCAs:      rootCerts,
			Certificates: []tls.Certificate{*clientPrivateKey},
		}
	} else {
		return &tls.Config{
			RootCAs: rootCerts,
		}
	}
}

func loadCertificatesFrom(pemFile string) (*x509.CertPool, error) {
	caCert, err := ioutil.ReadFile(pemFile)
	if err != nil {
		return nil, err
	}
	certificates := x509.NewCertPool()
	certificates.AppendCertsFromPEM(caCert)
	return certificates, nil
}

func loadPrivateKeyFrom(pemCertFile, pemPrivateKeyFile string) (*tls.Certificate, error) {
	privateKey, err := tls.LoadX509KeyPair(pemCertFile, pemPrivateKeyFile)
	if err != nil {
		return nil, err
	}
	return &privateKey, nil
}
<|endoftext|>


<commit_before>package main

import (
  "net/http"
  "fmt"
  "sync"
  "os"
  "log"
  "path/filepath"
  "time"
  "strings"
  "os/exec"
  "io/ioutil"
  "encoding/json"
  "github.com/levigross/grequests"
  transport "google.golang.org/api/googleapi/transport"
  youtube   "google.golang.org/api/youtube/v3"
)

var _ = filepath.Join
var _ = grequests.Get
var _ = fmt.Println
var _ = time.Sleep
var _ = strings.Replace

const (
  playlist = "PL1531805E486A97FF" // the REAL Italo
  //playlist = "PLQh1lAYHwN7h0GJydjLRPrqghcg-_t6x_" // actually short Italo
  //playlist = "RDmbJ0aXxpTfM" // nightcore, not Italo
  maxListItems = 50
  youtubeDl = "youtube-dl"
  ffmpeg = "ffmpeg"
)

var dirname string = "outfiles"
var googleAPIKey string

func init() {
  // Check for command-line dependencies
  for _,dependency := range []string{youtubeDl, ffmpeg} {
    if _, err := exec.LookPath(dependency); err != nil {
      log.Fatalf("Must have %s in your PATH", dependency)
    }
  }

  // Make output directory
  if err := os.Mkdir(dirname, 0777); err != nil && !os.IsExist(err) {
    log.Fatal("Could not make directory", dirname, "for output files")
  }
  // Unpack configuration
  type config struct {
    GoogleAPIKey string `json:"google_api_key"`
  }
  configJson, err := ioutil.ReadFile("config.json")
  if err != nil {
    // config.json missing
    log.Fatal("Must have config.json file to run")
  }
  conf := new(config)
  err = json.Unmarshal(configJson, conf)
  if err != nil {
    // unmarshal error
    log.Fatal("config.json is formatted incorrectly")
  }
  if googleAPIKey = conf.GoogleAPIKey; googleAPIKey == "" {
    // google_api_key missing from config
    log.Fatal("Google API Key is missing from config.json")
  }
}

func main() {
  // Start up the YouTube service
  service, err := youtube.New(&http.Client{
    Transport: &transport.APIKey{Key: googleAPIKey},
  })
  if err != nil {
    log.Fatal(err.Error())
  }

  playlistItems := make([]*OrderedPlaylistItem, 0)
  sieve := make(chan *youtube.PlaylistItem)

  // fetch the video ids
  go playlistItemsSieve(service, playlist, sieve)

  // dispatch the downloads
  var counter int = 1
  for video := range sieve {
    orderedVideo := OrderedPlaylistItem{video, counter, 1}
    playlistItems = append(playlistItems, &orderedVideo)
    counter++
  }

  wg := new(sync.WaitGroup)
  for _, video := range playlistItems {
    wg.Add(1)
    go func(v *OrderedPlaylistItem) {
      e := v.Download()
      if e != nil {
        fmt.Println(e.Error())
      }
      wg.Done()
    }(video)
  }
  wg.Wait()

}

func (video *OrderedPlaylistItem) Download() error {
  if video.RetriesLeft < 1 {
    // look for the recursive base case, exit if max retries exceeded
    return fmt.Errorf("Exceeded maximum retries for video %s", video.ContentDetails.VideoId)
  }
  fname := filepath.Join(dirname, fmt.Sprintf("%d - %s.m4a", video.PositionInPlaylist, video.Snippet.Title))
  cmd := exec.Command(youtubeDl, "-o", fname, "https://youtube.com/watch?v="+video.ContentDetails.VideoId, "-f", "141/140")
  output, err := cmd.Output()
  fmt.Println(string(output))

  convert := exec.Command(ffmpeg, "-i", fname, "-acodec", "libmp3lame", "-ab", "128k", strings.Replace(fname, ".m4a", ".mp3", 1))
  _, err = convert.Output()

  if err == nil {
    return nil
  } else {
    video.RetriesLeft -= 1
    return video.Download()
  }
}

func playlistItemsSieve(service *youtube.Service, playlistId string, output chan *youtube.PlaylistItem) {
  var nextPageToken string
  for {
    req := service.PlaylistItems.List("snippet,contentDetails").PlaylistId(playlistId).MaxResults(maxListItems)
    if nextPageToken != "" {
      // we are paginating
      req = req.PageToken(nextPageToken)
    }
    playlist, err := req.Do()
    if err != nil {
      panic(err)
    }

    for _, video := range playlist.Items {
      output <- video
    }

    nextPageToken = playlist.NextPageToken
    if nextPageToken == "" {
      break
    }
  }
  close(output)
}

type OrderedPlaylistItem struct {
  *youtube.PlaylistItem
  PositionInPlaylist    int
  RetriesLeft           int
}
<commit_msg>Refactor Download() so converting to mp3 is contained in a a different method and can be performed optionally<commit_after>package main

import (
  "net/http"
  "fmt"
  "sync"
  "os"
  "log"
  "path/filepath"
  "time"
  "strings"
  "os/exec"
  "io/ioutil"
  "encoding/json"
  "github.com/levigross/grequests"
  transport "google.golang.org/api/googleapi/transport"
  youtube   "google.golang.org/api/youtube/v3"
)

var _ = filepath.Join
var _ = grequests.Get
var _ = fmt.Println
var _ = time.Sleep
var _ = strings.Replace

const (
  playlist = "PL1531805E486A97FF" // the REAL Italo
  //playlist = "PLQh1lAYHwN7h0GJydjLRPrqghcg-_t6x_" // actually short Italo
  //playlist = "RDmbJ0aXxpTfM" // nightcore, not Italo
  maxListItems = 50
  youtubeDl = "youtube-dl"
  ffmpeg = "ffmpeg"
)

var (
  dirname       string = "outfiles"
  googleAPIKey  string
  shouldConvert bool   = true
  Artist        string = ""
  Album         string = ""
)

func init() {
  // Check for command-line dependencies
  for _,dependency := range []string{youtubeDl, ffmpeg} {
    if _, err := exec.LookPath(dependency); err != nil {
      log.Fatalf("Must have %s in your PATH", dependency)
    }
  }

  // Make output directory
  if err := os.Mkdir(dirname, 0777); err != nil && !os.IsExist(err) {
    log.Fatal("Could not make directory", dirname, "for output files")
  }
  // Unpack configuration
  type config struct {
    GoogleAPIKey string `json:"google_api_key"`
  }
  configJson, err := ioutil.ReadFile("config.json")
  if err != nil {
    // config.json missing
    log.Fatal("Must have config.json file to run")
  }
  conf := new(config)
  err = json.Unmarshal(configJson, conf)
  if err != nil {
    // unmarshal error
    log.Fatal("config.json is formatted incorrectly")
  }
  if googleAPIKey = conf.GoogleAPIKey; googleAPIKey == "" {
    // google_api_key missing from config
    log.Fatal("Google API Key is missing from config.json")
  }
}

func main() {
  // Start up the YouTube service
  service, err := youtube.New(&http.Client{
    Transport: &transport.APIKey{Key: googleAPIKey},
  })
  if err != nil {
    log.Fatal(err.Error())
  }

  playlistItems := make([]*OrderedPlaylistItem, 0)
  sieve := make(chan *youtube.PlaylistItem)

  // fetch the video ids
  go playlistItemsSieve(service, playlist, sieve)

  // dispatch the downloads
  var counter int = 1
  for video := range sieve {
    orderedVideo := OrderedPlaylistItem{video, counter, 1}
    playlistItems = append(playlistItems, &orderedVideo)
    counter++
  }

  wg := new(sync.WaitGroup)
  for _, video := range playlistItems {
    wg.Add(1)
    go func(v *OrderedPlaylistItem) {
      var e error = v.Download()
      if shouldConvert && e == nil {
        e = v.ConvertToMp3(Artist, Album)
        os.Remove(v.M4aFname())
      }
      if e != nil {
        fmt.Println(e.Error())
      }
      wg.Done()
    }(video)
  }
  wg.Wait()

}

func (video *OrderedPlaylistItem) M4aFname() string {
  return filepath.Join(dirname, fmt.Sprintf("%d - %s.m4a", video.PositionInPlaylist, video.Snippet.Title))
}

func (video *OrderedPlaylistItem) Mp3Fname() string {
  return strings.TrimSuffix(video.M4aFname(), "m4a") + "mp3"
}

func (video *OrderedPlaylistItem) ConvertToMp3(artist, album string) error {
  if _, err := os.Stat(video.M4aFname()); os.IsNotExist(err) {
    return err
  }
  cmd := exec.Command(ffmpeg, "-i", video.M4aFname(), "-acodec", "libmp3lame", "-ab", "128k", video.Mp3Fname())
  _, err := cmd.Output()
  return err
}

func (video *OrderedPlaylistItem) Download() error {
  if video.RetriesLeft < 1 {
    // look for the recursive base case, exit if max retries exceeded
    return fmt.Errorf("Exceeded maximum retries for video %s", video.ContentDetails.VideoId)
  }
  cmd := exec.Command(youtubeDl, "-o", video.M4aFname(), "https://youtube.com/watch?v="+video.ContentDetails.VideoId, "-f", "141/140")
  output, err := cmd.Output()
  fmt.Println(string(output))

  if err == nil {
    return nil
  } else {
    video.RetriesLeft -= 1
    return video.Download()
  }
}

func playlistItemsSieve(service *youtube.Service, playlistId string, output chan *youtube.PlaylistItem) {
  var nextPageToken string
  for {
    req := service.PlaylistItems.List("snippet,contentDetails").PlaylistId(playlistId).MaxResults(maxListItems)
    if nextPageToken != "" {
      // we are paginating
      req = req.PageToken(nextPageToken)
    }
    playlist, err := req.Do()
    if err != nil {
      panic(err)
    }

    for _, video := range playlist.Items {
      output <- video
    }

    nextPageToken = playlist.NextPageToken
    if nextPageToken == "" {
      break
    }
  }
  close(output)
}

type OrderedPlaylistItem struct {
  *youtube.PlaylistItem
  PositionInPlaylist    int
  RetriesLeft           int
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/subtle"
	"fmt"
	"html/template"
	"net/http"
)

var app *App
var templates *template.Template

func homeHandler(w http.ResponseWriter, r *http.Request) {
	domain := r.Host
	if site, err := app.SiteForDomain(domain); err != nil {
		w.WriteHeader(500)
		w.Write([]byte(err.Error()))
	} else {
		if len(site.AuthUser) > 0 && len(site.AuthPass) > 0 {
			if u, p, ok := r.BasicAuth(); !ok || u != site.AuthUser || subtle.ConstantTimeCompare([]byte(p), []byte(site.AuthPass)) != 1 {
				w.Header().Set("WWW-Authenticate", `Basic realm="You need a username/password to access this site"`)
				w.WriteHeader(401)
				w.Write([]byte("Unauthorized\n"))
				return
			}
		}

		if imageUrls, err := site.GetAllImageUrls(); err != nil {
			w.WriteHeader(500)
			w.Write([]byte(err.Error()))
		} else {
			type HomeContext struct {
				MetaTitle            string
				SiteTitle            string
				AlbumTitle           string
				LoadAtStartImageUrls []string
				LazyLoadImageUrls    []string
			}

			ctx := &HomeContext{
				site.MetaTitle,
				site.SiteTitle,
				site.AlbumTitle,
				imageUrls[:10],
				imageUrls[10:],
			}
			templates.ExecuteTemplate(w, "home.html", ctx)
		}
	}
}

func main() {
	app = NewApp()
	templates = template.Must(template.ParseFiles("templates/home.html"))

	http.HandleFunc("/", homeHandler)
	http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static/"))))

	fmt.Printf("Starting server at port %s\n", app.port)
	if err := http.ListenAndServe(fmt.Sprintf(":%s", app.port), nil); err != nil {
		fmt.Printf("Unable to start server. Error: %s\n", err.Error())
	}
}
<commit_msg>Fixed bug when less than 10 images in bucket<commit_after>package main

import (
	"crypto/subtle"
	"fmt"
	"html/template"
	"net/http"
)

var app *App
var templates *template.Template

func homeHandler(w http.ResponseWriter, r *http.Request) {
	domain := r.Host
	if site, err := app.SiteForDomain(domain); err != nil {
		w.WriteHeader(500)
		w.Write([]byte(err.Error()))
	} else {
		if len(site.AuthUser) > 0 && len(site.AuthPass) > 0 {
			if u, p, ok := r.BasicAuth(); !ok || u != site.AuthUser || subtle.ConstantTimeCompare([]byte(p), []byte(site.AuthPass)) != 1 {
				w.Header().Set("WWW-Authenticate", `Basic realm="You need a username/password to access this site"`)
				w.WriteHeader(401)
				w.Write([]byte("Unauthorized\n"))
				return
			}
		}

		if imageUrls, err := site.GetAllImageUrls(); err != nil {
			w.WriteHeader(500)
			w.Write([]byte(err.Error()))
		} else {
			type HomeContext struct {
				MetaTitle            string
				SiteTitle            string
				AlbumTitle           string
				LoadAtStartImageUrls []string
				LazyLoadImageUrls    []string
			}

			loadAtStartImageUrls, lazyLoadImageUrls := imageUrls, imageUrls
			if len(imageUrls) > 10 {
				loadAtStartImageUrls = loadAtStartImageUrls[:10]
				lazyLoadImageUrls = lazyLoadImageUrls[10:]
			}
			ctx := &HomeContext{
				site.MetaTitle,
				site.SiteTitle,
				site.AlbumTitle,
				loadAtStartImageUrls,
				lazyLoadImageUrls,
			}
			templates.ExecuteTemplate(w, "home.html", ctx)
		}
	}
}

func main() {
	app = NewApp()
	templates = template.Must(template.ParseFiles("templates/home.html"))

	http.HandleFunc("/", homeHandler)
	http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static/"))))

	fmt.Printf("Starting server at port %s\n", app.port)
	if err := http.ListenAndServe(fmt.Sprintf(":%s", app.port), nil); err != nil {
		fmt.Printf("Unable to start server. Error: %s\n", err.Error())
	}
}
<|endoftext|>