<commit_before>package cmd

import (
	"os"

	"github.com/containerum/chkit/pkg/chkitErrors"
	"github.com/containerum/chkit/pkg/client"
	"gopkg.in/urfave/cli.v2"
)

const (
	ErrUnableToLoadConfig chkitErrors.Err = "unable to load config"
	ErrInvalidAPIurl      chkitErrors.Err = "invalid API url"
	ErrUnableToInitClient chkitErrors.Err = "unable to init client"
)

func setupClient(ctx *cli.Context) error {
	log := getLog(ctx)
	config := getConfig(ctx)
	var client *chClient.Client
	var err error
	if ctx.Bool("test") {
		log.Infof("running in test mode")
		client, err = chClient.NewClient(config, chClient.UnsafeSkipTLSCheck)
	} else {
		client, err = chClient.NewClient(config)
	}
	if err != nil {
		return ErrUnableToInitClient.
			Wrap(err)
	}
	setClient(ctx, *client)
	return nil
}

func setupConfig(ctx *cli.Context) error {
	config := getConfig(ctx)
	err := loadConfig(ctx.String("config"), &config)
	if err != nil {
		return ErrUnableToLoadConfig.
			Wrap(err)
	}
	if ctx.Bool("test") {
		config.APIaddr = os.Getenv("CONTAINERUM_API")
	}
	if config.APIaddr == "" {
		return ErrInvalidAPIurl
	}
	config.Fingerprint = Fingerprint()
	setConfig(ctx, config)
	return nil
}

func persist(ctx *cli.Context) error {
	if !ctx.IsSet("config") {
		return saveConfig(ctx)
	}
	return nil
}
<commit_msg>use mock on test<commit_after>package cmd

import (
	"os"

	"github.com/containerum/chkit/pkg/chkitErrors"
	"github.com/containerum/chkit/pkg/client"
	"gopkg.in/urfave/cli.v2"
)

const (
	ErrUnableToLoadConfig chkitErrors.Err = "unable to load config"
	ErrInvalidUserInfo    chkitErrors.Err = "invalid user info"
	ErrInvalidAPIurl      chkitErrors.Err = "invalid API url"
	ErrUnableToInitClient chkitErrors.Err = "unable to init client"
)

func setupClient(ctx *cli.Context) error {
	log := getLog(ctx)
	config := getConfig(ctx)
	var client *chClient.Client
	var err error
	if ctx.IsSet("test") {
		log.Infof("running in test mode")
		switch ctx.String("test") {
		case "mock":
			client, err = chClient.NewClient(config, chClient.Mock)
		case "api":
			client, err = chClient.NewClient(config, chClient.UnsafeSkipTLSCheck)
		}
	} else {
		client, err = chClient.NewClient(config)
	}
	if err != nil {
		return ErrUnableToInitClient.
			Wrap(err)
	}
	setClient(ctx, *client)
	return nil
}

func setupConfig(ctx *cli.Context) error {
	log := getLog(ctx)
	config := getConfig(ctx)
	err := loadConfig(ctx.String("config"), &config)
	if err != nil {
		return ErrUnableToLoadConfig.
			Wrap(err)
	}
	if ctx.IsSet("test") {
		testAPIurl := os.Getenv("CONTAINERUM_API")
		log.Infof("useing test api %q", testAPIurl)
		config.APIaddr = testAPIurl
	}

	if config.APIaddr == "" {
		return ErrInvalidAPIurl
	}
	if config.Password == "" || config.Username == "" {
		return ErrInvalidUserInfo
	}

	config.Fingerprint = Fingerprint()
	setConfig(ctx, config)
	return nil
}

func persist(ctx *cli.Context) error {
	if !ctx.IsSet("config") {
		return saveConfig(ctx)
	}
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2014 Richard Lehane. All rights reserved.
//
// 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 (
	"encoding/csv"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"runtime"
	"strconv"
	"time"

	"github.com/richardlehane/siegfried"
	"github.com/richardlehane/siegfried/config"
	"github.com/richardlehane/siegfried/pkg/core"

	"github.com/pkg/profile"
)

const (
	CONCURRENT = 32
	PROCS      = -1
)

var (
	update  = flag.Bool("update", false, "update or install the default signature file")
	version = flag.Bool("version", false, "display version information")
	debug   = flag.Bool("debug", false, "scan in debug mode")
	nr      = flag.Bool("nr", false, "prevent automatic directory recursion")
	csvo    = flag.Bool("csv", false, "CSV output format")
	sig     = flag.String("sig", config.SignatureBase(), "set the signature file")
	home    = flag.String("home", config.Home(), "override the default home directory")
	serve   = flag.String("serve", "false", "not yet implemented - coming with v1")
)

var csvWriter *csv.Writer

func getHttp(url string) ([]byte, error) {
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, err
	}
	_, timeout, transport := config.UpdateOptions()
	req.Header.Add("User-Agent", "siegfried/siegbot (+https://github.com/richardlehane/siegfried)")
	req.Header.Add("Cache-Control", "no-cache")
	timer := time.AfterFunc(timeout, func() {
		transport.CancelRequest(req)
	})
	defer timer.Stop()
	client := http.Client{
		Transport: transport,
	}
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	return ioutil.ReadAll(resp.Body)
}

type Update struct {
	SfVersion  [3]int
	SigCreated string
	GobSize    int
	LatestURL  string
}

func updateSigs() (string, error) {
	url, _, _ := config.UpdateOptions()
	if url == "" {
		return "Update is not available for this distribution of Siegfried", nil
	}
	response, err := getHttp(url)
	if err != nil {
		return "", err
	}
	var u Update
	if err := json.Unmarshal(response, &u); err != nil {
		return "", err
	}
	version := config.Version()
	if version[0] < u.SfVersion[0] || (u.SfVersion[0] == version[0] && version[1] < u.SfVersion[1]) {
		return "Your version of Siegfried is out of date; please install latest from http://www.itforarchivists.com/siegfried before continuing.", nil
	}
	s, err := siegfried.Load(config.Signature())
	if err == nil {
		if !s.Update(u.SigCreated) {
			return "You are already up to date!", nil
		}
	} else {
		// this hairy bit of golang exception handling is thanks to Ross! :)
		if _, err = os.Stat(config.Home()); err != nil {
			if os.IsNotExist(err) {
				err = os.MkdirAll(config.Home(), os.ModePerm)
				if err != nil {
					return "", fmt.Errorf("Siegfried: cannot create home directory %s, %v", config.Home(), err)
				}
			} else {
				return "", fmt.Errorf("Siegfried: error opening directory %s, %v", config.Home(), err)
			}
		}
	}
	fmt.Println("... downloading latest signature file ...")
	response, err = getHttp(u.LatestURL)
	if err != nil {
		return "", err
	}
	if len(response) != u.GobSize {
		return "", fmt.Errorf("Siegfried: error retrieving pronom.gob; expecting %d bytes, got %d bytes", u.GobSize, len(response))
	}
	err = ioutil.WriteFile(config.Signature(), response, os.ModePerm)
	if err != nil {
		return "", fmt.Errorf("Siegfried: error writing to directory, %v", err)
	}
	fmt.Printf("... writing %s ...\n", config.Signature())
	return "Your signature file has been updated", nil
}

func load() (*siegfried.Siegfried, error) {
	s, err := siegfried.Load(config.Signature())
	if err != nil {
		return nil, err
	}
	return s, nil
}

func identify(s *siegfried.Siegfried, p string) ([]string, error) {
	ids := make([]string, 0)
	file, err := os.Open(p)
	if err != nil {
		return nil, fmt.Errorf("failed to open %v, got: %v", p, err)
	}
	c, err := s.Identify(p, file)
	if c == nil {
		return nil, fmt.Errorf("failed to identify %v, got: %v", p, err)
	}
	for i := range c {
		ids = append(ids, i.String())
	}
	err = file.Close()
	if err != nil {
		return nil, err
	}
	return ids, nil
}

func multiIdentify(s *siegfried.Siegfried, r string) ([][]string, error) {
	set := make([][]string, 0)
	wf := func(path string, info os.FileInfo, err error) error {
		if info.IsDir() {
			if *nr && path != r {
				return filepath.SkipDir
			}
			return nil
		}
		ids, err := identify(s, path)
		if err != nil {
			return err
		}
		set = append(set, ids)
		return nil
	}
	err := filepath.Walk(r, wf)
	return set, err
}

type res struct {
	path string
	sz   int64
	c    []core.Identification
	err  error
}

func printer(resc chan chan res) {
	for rr := range resc {
		r := <-rr
		if !config.Debug() && !*csvo {
			PrintFile(r.path, r.sz, r.err)
		}
		var csvRecord []string
		if *csvo {
			csvRecord = make([]string, 9)
		}
		for _, v := range r.c {
			switch {
			case config.Debug():
			case *csvo:
				csvRecord[0], csvRecord[1] = r.path, strconv.Itoa(int(r.sz))
				copy(csvRecord[2:], v.Csv())
				csvWriter.Write(csvRecord)
			default:
				fmt.Print(v.Yaml())
			}
		}
	}
}

func multiIdentifyP(s *siegfried.Siegfried, r string) {
	runtime.GOMAXPROCS(PROCS)
	resc := make(chan chan res, CONCURRENT)
	go printer(resc)
	wf := func(path string, info os.FileInfo, err error) error {
		if info.IsDir() {
			if *nr && path != r {
				return filepath.SkipDir
			}
			return nil
		}
		rchan := make(chan res, 1)
		resc <- rchan
		go func() {
			file, err := os.Open(path)
			if err != nil {
				rchan <- res{"", 0, nil, fmt.Errorf("failed to open %v, got: %v", path, err)}
				return
			}
			c, err := s.Identify(path, file)
			if c == nil {
				file.Close()
				rchan <- res{"", 0, nil, fmt.Errorf("failed to identify %v, got: %v", path, err)}
				return
			}
			ids := make([]core.Identification, 0, 1)
			for id := range c {
				ids = append(ids, id)
			}
			rchan <- res{path, info.Size(), ids, err}
			file.Close()
		}()
		return nil
	}
	filepath.Walk(r, wf)
	close(resc)
}

func PrintFile(name string, sz int64, err error) {
	fmt.Println("---")
	fmt.Printf("filename : \"%v\"\n", name)
	fmt.Printf("filesize : %d\n", sz)
	if err != nil {
		fmt.Printf("errors   : %v\n", err)
	}
	if !config.Debug() {
		fmt.Print("matches  :\n")
	}
}

func main() {
	defer profile.Start(profile.MemProfile).Stop()

	flag.Parse()

	if *csvo {
		csvWriter = csv.NewWriter(os.Stdout)
		csvWriter.Write([]string{"filename", "filesize", "identifier", "id", "format name", "format version", "mimetype", "basis", "warning"})
	}

	if *home != config.Home() {
		config.SetHome(*home)
	}

	if *sig != config.SignatureBase() {
		config.SetSignature(*sig)
	}

	if *version {
		version := config.Version()
		fmt.Printf("Siegfried version: %d.%d.%d\n", version[0], version[1], version[2])
		return
	}

	if *debug {
		config.SetDebug()
	}

	if *update {
		msg, err := updateSigs()
		if err != nil {
			log.Fatalf("Siegfried: error updating signature file, %v", err)
		}
		fmt.Println(msg)
		return
	}

	if *serve != "false" {
		fmt.Println("sf server not yet implemented; expect by v1")
	}

	if flag.NArg() != 1 {
		log.Fatal("Error: expecting a single file or directory argument")
	}

	var err error
	file, err := os.Open(flag.Arg(0))
	if err != nil {
		log.Fatalf("Error: error opening %v, got: %v", flag.Arg(0), err)
	}
	info, err := file.Stat()
	if err != nil {
		log.Fatalf("Error: error getting info for %v, got: %v", flag.Arg(0), err)
	}

	s, err := load()
	if err != nil {
		log.Fatalf("Error: error loading signature file, got: %v", err)

	}

	if info.IsDir() {
		file.Close()
		if !config.Debug() && !*csvo {
			fmt.Print(s.Yaml())
		}
		multiIdentifyP(s, flag.Arg(0))
		if *csvo {
			csvWriter.Flush()
		}
		os.Exit(0)
	}
	c, err := s.Identify(flag.Arg(0), file)
	if c == nil {
		file.Close()
		log.Fatal(err)
	}
	if !config.Debug() && !*csvo {
		fmt.Print(s.Yaml())
		PrintFile(flag.Arg(0), info.Size(), err)
	}
	var csvRecord []string
	if *csvo {
		csvRecord = make([]string, 9)
	}
	for i := range c {
		switch {
		case config.Debug():
		case *csvo:
			csvRecord[0], csvRecord[1] = flag.Arg(0), strconv.Itoa(int(info.Size()))
			copy(csvRecord[2:], i.Csv())
			csvWriter.Write(csvRecord)
		default:
			fmt.Print(i.Yaml())
		}
	}
	file.Close()
	if *csvo {
		csvWriter.Flush()
	}

	os.Exit(0)
}
<commit_msg>comment out the profiling<commit_after>// Copyright 2014 Richard Lehane. All rights reserved.
//
// 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 (
	"encoding/csv"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"runtime"
	"strconv"
	"time"

	"github.com/richardlehane/siegfried"
	"github.com/richardlehane/siegfried/config"
	"github.com/richardlehane/siegfried/pkg/core"

	//"github.com/pkg/profile"
)

const (
	CONCURRENT = 32
	PROCS      = -1
)

var (
	update  = flag.Bool("update", false, "update or install the default signature file")
	version = flag.Bool("version", false, "display version information")
	debug   = flag.Bool("debug", false, "scan in debug mode")
	nr      = flag.Bool("nr", false, "prevent automatic directory recursion")
	csvo    = flag.Bool("csv", false, "CSV output format")
	sig     = flag.String("sig", config.SignatureBase(), "set the signature file")
	home    = flag.String("home", config.Home(), "override the default home directory")
	serve   = flag.String("serve", "false", "not yet implemented - coming with v1")
)

var csvWriter *csv.Writer

func getHttp(url string) ([]byte, error) {
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, err
	}
	_, timeout, transport := config.UpdateOptions()
	req.Header.Add("User-Agent", "siegfried/siegbot (+https://github.com/richardlehane/siegfried)")
	req.Header.Add("Cache-Control", "no-cache")
	timer := time.AfterFunc(timeout, func() {
		transport.CancelRequest(req)
	})
	defer timer.Stop()
	client := http.Client{
		Transport: transport,
	}
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	return ioutil.ReadAll(resp.Body)
}

type Update struct {
	SfVersion  [3]int
	SigCreated string
	GobSize    int
	LatestURL  string
}

func updateSigs() (string, error) {
	url, _, _ := config.UpdateOptions()
	if url == "" {
		return "Update is not available for this distribution of Siegfried", nil
	}
	response, err := getHttp(url)
	if err != nil {
		return "", err
	}
	var u Update
	if err := json.Unmarshal(response, &u); err != nil {
		return "", err
	}
	version := config.Version()
	if version[0] < u.SfVersion[0] || (u.SfVersion[0] == version[0] && version[1] < u.SfVersion[1]) {
		return "Your version of Siegfried is out of date; please install latest from http://www.itforarchivists.com/siegfried before continuing.", nil
	}
	s, err := siegfried.Load(config.Signature())
	if err == nil {
		if !s.Update(u.SigCreated) {
			return "You are already up to date!", nil
		}
	} else {
		// this hairy bit of golang exception handling is thanks to Ross! :)
		if _, err = os.Stat(config.Home()); err != nil {
			if os.IsNotExist(err) {
				err = os.MkdirAll(config.Home(), os.ModePerm)
				if err != nil {
					return "", fmt.Errorf("Siegfried: cannot create home directory %s, %v", config.Home(), err)
				}
			} else {
				return "", fmt.Errorf("Siegfried: error opening directory %s, %v", config.Home(), err)
			}
		}
	}
	fmt.Println("... downloading latest signature file ...")
	response, err = getHttp(u.LatestURL)
	if err != nil {
		return "", err
	}
	if len(response) != u.GobSize {
		return "", fmt.Errorf("Siegfried: error retrieving pronom.gob; expecting %d bytes, got %d bytes", u.GobSize, len(response))
	}
	err = ioutil.WriteFile(config.Signature(), response, os.ModePerm)
	if err != nil {
		return "", fmt.Errorf("Siegfried: error writing to directory, %v", err)
	}
	fmt.Printf("... writing %s ...\n", config.Signature())
	return "Your signature file has been updated", nil
}

func load() (*siegfried.Siegfried, error) {
	s, err := siegfried.Load(config.Signature())
	if err != nil {
		return nil, err
	}
	return s, nil
}

func identify(s *siegfried.Siegfried, p string) ([]string, error) {
	ids := make([]string, 0)
	file, err := os.Open(p)
	if err != nil {
		return nil, fmt.Errorf("failed to open %v, got: %v", p, err)
	}
	c, err := s.Identify(p, file)
	if c == nil {
		return nil, fmt.Errorf("failed to identify %v, got: %v", p, err)
	}
	for i := range c {
		ids = append(ids, i.String())
	}
	err = file.Close()
	if err != nil {
		return nil, err
	}
	return ids, nil
}

func multiIdentify(s *siegfried.Siegfried, r string) ([][]string, error) {
	set := make([][]string, 0)
	wf := func(path string, info os.FileInfo, err error) error {
		if info.IsDir() {
			if *nr && path != r {
				return filepath.SkipDir
			}
			return nil
		}
		ids, err := identify(s, path)
		if err != nil {
			return err
		}
		set = append(set, ids)
		return nil
	}
	err := filepath.Walk(r, wf)
	return set, err
}

type res struct {
	path string
	sz   int64
	c    []core.Identification
	err  error
}

func printer(resc chan chan res) {
	for rr := range resc {
		r := <-rr
		if !config.Debug() && !*csvo {
			PrintFile(r.path, r.sz, r.err)
		}
		var csvRecord []string
		if *csvo {
			csvRecord = make([]string, 9)
		}
		for _, v := range r.c {
			switch {
			case config.Debug():
			case *csvo:
				csvRecord[0], csvRecord[1] = r.path, strconv.Itoa(int(r.sz))
				copy(csvRecord[2:], v.Csv())
				csvWriter.Write(csvRecord)
			default:
				fmt.Print(v.Yaml())
			}
		}
	}
}

func multiIdentifyP(s *siegfried.Siegfried, r string) {
	runtime.GOMAXPROCS(PROCS)
	resc := make(chan chan res, CONCURRENT)
	go printer(resc)
	wf := func(path string, info os.FileInfo, err error) error {
		if info.IsDir() {
			if *nr && path != r {
				return filepath.SkipDir
			}
			return nil
		}
		rchan := make(chan res, 1)
		resc <- rchan
		go func() {
			file, err := os.Open(path)
			if err != nil {
				rchan <- res{"", 0, nil, fmt.Errorf("failed to open %v, got: %v", path, err)}
				return
			}
			c, err := s.Identify(path, file)
			if c == nil {
				file.Close()
				rchan <- res{"", 0, nil, fmt.Errorf("failed to identify %v, got: %v", path, err)}
				return
			}
			ids := make([]core.Identification, 0, 1)
			for id := range c {
				ids = append(ids, id)
			}
			rchan <- res{path, info.Size(), ids, err}
			file.Close()
		}()
		return nil
	}
	filepath.Walk(r, wf)
	close(resc)
}

func PrintFile(name string, sz int64, err error) {
	fmt.Println("---")
	fmt.Printf("filename : \"%v\"\n", name)
	fmt.Printf("filesize : %d\n", sz)
	if err != nil {
		fmt.Printf("errors   : %v\n", err)
	}
	if !config.Debug() {
		fmt.Print("matches  :\n")
	}
}

func main() {
	//defer profile.Start(profile.MemProfile).Stop()

	flag.Parse()

	if *csvo {
		csvWriter = csv.NewWriter(os.Stdout)
		csvWriter.Write([]string{"filename", "filesize", "identifier", "id", "format name", "format version", "mimetype", "basis", "warning"})
	}

	if *home != config.Home() {
		config.SetHome(*home)
	}

	if *sig != config.SignatureBase() {
		config.SetSignature(*sig)
	}

	if *version {
		version := config.Version()
		fmt.Printf("Siegfried version: %d.%d.%d\n", version[0], version[1], version[2])
		return
	}

	if *debug {
		config.SetDebug()
	}

	if *update {
		msg, err := updateSigs()
		if err != nil {
			log.Fatalf("Siegfried: error updating signature file, %v", err)
		}
		fmt.Println(msg)
		return
	}

	if *serve != "false" {
		fmt.Println("sf server not yet implemented; expect by v1")
	}

	if flag.NArg() != 1 {
		log.Fatal("Error: expecting a single file or directory argument")
	}

	var err error
	file, err := os.Open(flag.Arg(0))
	if err != nil {
		log.Fatalf("Error: error opening %v, got: %v", flag.Arg(0), err)
	}
	info, err := file.Stat()
	if err != nil {
		log.Fatalf("Error: error getting info for %v, got: %v", flag.Arg(0), err)
	}

	s, err := load()
	if err != nil {
		log.Fatalf("Error: error loading signature file, got: %v", err)

	}

	if info.IsDir() {
		file.Close()
		if !config.Debug() && !*csvo {
			fmt.Print(s.Yaml())
		}
		multiIdentifyP(s, flag.Arg(0))
		if *csvo {
			csvWriter.Flush()
		}
		os.Exit(0)
	}
	c, err := s.Identify(flag.Arg(0), file)
	if c == nil {
		file.Close()
		log.Fatal(err)
	}
	if !config.Debug() && !*csvo {
		fmt.Print(s.Yaml())
		PrintFile(flag.Arg(0), info.Size(), err)
	}
	var csvRecord []string
	if *csvo {
		csvRecord = make([]string, 9)
	}
	for i := range c {
		switch {
		case config.Debug():
		case *csvo:
			csvRecord[0], csvRecord[1] = flag.Arg(0), strconv.Itoa(int(info.Size()))
			copy(csvRecord[2:], i.Csv())
			csvWriter.Write(csvRecord)
		default:
			fmt.Print(i.Yaml())
		}
	}
	file.Close()
	if *csvo {
		csvWriter.Flush()
	}

	os.Exit(0)
}
<|endoftext|>


<commit_before>package main

import (
	"io/ioutil"
	"path"

	"github.com/codegangsta/cli"

	"github.com/coreos/coreinit/job"
	"github.com/coreos/coreinit/registry"
)

func newStartUnitCommand() cli.Command {
	return cli.Command{
		Name:  "start",
		Usage: "Start (activate) one or more units",
		Description: `Start adds one or more units to the cluster schedule.
Once scheduled the cluster will ensure that the unit is
running on one machine.`,
		Action: startUnitAction,
	}
}

func startUnitAction(c *cli.Context) {
	r := registry.New()

	payloads := make([]job.JobPayload, len(c.Args()))

	for i, v := range c.Args() {
		out, err := ioutil.ReadFile(v)
		if err != nil {
			logger.Fatalf("%s: No such file or directory\n", v)
		}

		name := path.Base(v)
		payload := job.JobPayload{name, string(out)}
		if err != nil {
			logger.Fatal(err)
		} else {
			payloads[i] = payload
		}
	}

	for _, p := range payloads {
		println(p.Name)
		println(p.Value)
	}

	//TODO: Handle error response from NewJobRequest
	req, _ := job.NewJobRequest(payloads, nil)
	r.AddRequest(req)
}
<commit_msg>fix(cmd): Remove unnecessary debug lines<commit_after>package main

import (
	"io/ioutil"
	"path"

	"github.com/codegangsta/cli"

	"github.com/coreos/coreinit/job"
	"github.com/coreos/coreinit/registry"
)

func newStartUnitCommand() cli.Command {
	return cli.Command{
		Name:  "start",
		Usage: "Start (activate) one or more units",
		Description: `Start adds one or more units to the cluster schedule.
Once scheduled the cluster will ensure that the unit is
running on one machine.`,
		Action: startUnitAction,
	}
}

func startUnitAction(c *cli.Context) {
	r := registry.New()

	payloads := make([]job.JobPayload, len(c.Args()))

	for i, v := range c.Args() {
		out, err := ioutil.ReadFile(v)
		if err != nil {
			logger.Fatalf("%s: No such file or directory\n", v)
		}

		name := path.Base(v)
		payload := job.JobPayload{name, string(out)}
		if err != nil {
			logger.Fatal(err)
		} else {
			payloads[i] = payload
		}
	}

	//TODO: Handle error response from NewJobRequest
	req, _ := job.NewJobRequest(payloads, nil)
	r.AddRequest(req)
}
<|endoftext|>


<commit_before>// Copyright © 2016 NAME HERE <EMAIL ADDRESS>
//
// 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 cmd

import (
	"bytes"
	"errors"
	"log"
	"time"

	"net"

	"github.com/google/gopacket"
	"github.com/google/gopacket/layers"
	"github.com/google/gopacket/pcap"
	"github.com/rhuss/puffer/pkg/api"
	"github.com/rhuss/puffer/pkg/speak"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

var buttonMac = "ac:63:be:fb:13:9d"

// watchCmd represents the watch command
var watchCmd = &cobra.Command{
	Use:   "watch",
	Short: "Watch for the press of a Amazon Dash button",
	Long: `Watch the press of a Amazon Dash button

	`,
	Run: watch,
}

func watch(cmd *cobra.Command, args []string) {
	netInterface := viper.GetString("interface")
	if netInterface == "" {
		netInterface = "en3"
	}

	iface, err := net.InterfaceByName(netInterface)
	if err != nil {
		panic(err)
	}

	addr, err := extractAddress(iface)
	if err != nil {
		panic(err)
	}

	log.Printf("Using network range %v for interface %v", addr, iface.Name)

	// Open up a pcap handle for packet reads/writes.
	handle, err := pcap.OpenLive(iface.Name, 65536, true, pcap.BlockForever)
	if err != nil {
		panic(err)
	}
	defer handle.Close()

	// Start up a goroutine to read in packet data.
	for {
		watchForButton(handle, iface, buttonPushed)
		time.Sleep(10 * time.Second)
	}
}

func buttonPushed() {
	log.Printf("Button pushed !")
	pufferData := api.FetchPufferData()
	speak.Speak(PufferMessage(pufferData), SpeakOptions())
}

var lastPushed = time.Time{}

// watchForButton watches a handle for incoming ARP responses we might care about, and prints them.
//
// watchForButton loops until 'stop' is closed.
func watchForButton(handle *pcap.Handle, iface *net.Interface, callback func()) {
	src := gopacket.NewPacketSource(handle, layers.LayerTypeEthernet)
	in := src.Packets()
	for {
		var packet gopacket.Packet
		select {
		case packet = <-in:
			arpLayer := packet.Layer(layers.LayerTypeARP)
			if arpLayer == nil {
				continue
			}
			arp := arpLayer.(*layers.ARP)
			if arp.Operation == layers.ARPRequest {
				if addressEquals("00:00:00:00:00:00", arp.DstHwAddress) && addressEquals(buttonMac, arp.SourceHwAddress) {
					var now = time.Now()
					if now.Sub(lastPushed).Seconds() > 5 {
						lastPushed = now
						go callback()
						return
					}
				}
			}
		}
	}
}

func addressEquals(mac string, addr []byte) bool {
	macParsed, error := net.ParseMAC(mac)
	if error != nil {
		return false
	}
	return bytes.Equal(macParsed, addr)
}

func extractAddress(iface *net.Interface) (*net.IPNet, error) {
	var addr *net.IPNet
	if addrs, err := iface.Addrs(); err != nil {
		return nil, err
	} else {
		for _, a := range addrs {
			if ipnet, ok := a.(*net.IPNet); ok {
				if ip4 := ipnet.IP.To4(); ip4 != nil {
					addr = &net.IPNet{
						IP:   ip4,
						Mask: ipnet.Mask[len(ipnet.Mask)-4:],
					}
					break
				}
			}
		}
	}
	// Sanity-check that the interface has a good address.
	if addr == nil {
		return nil, errors.New("no good IP network found")
	} else if addr.IP[0] == 127 {
		return nil, errors.New("skipping localhost")
	} else if addr.Mask[0] != 0xff || addr.Mask[1] != 0xff {
		return nil, errors.New("mask means network is too large")
	}
	return addr, nil
}

func init() {
	RootCmd.AddCommand(watchCmd)

	// Here you will define your flags and configuration settings.

	// Cobra supports Persistent Flags which will work for this command
	// and all subcommands, e.g.:
	// watchCmd.PersistentFlags().String("foo", "", "A help for foo")

	// Cobra supports local flags which will only run when this command
	// is called directly, e.g.:
	// watchCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")

}
<commit_msg>Some concurrency fixes<commit_after>// Copyright © 2016 NAME HERE <EMAIL ADDRESS>
//
// 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 cmd

import (
	"bytes"
	"errors"
	"log"
	"time"

	"net"

	"github.com/google/gopacket"
	"github.com/google/gopacket/layers"
	"github.com/google/gopacket/pcap"
	"github.com/rhuss/puffer/pkg/api"
	"github.com/rhuss/puffer/pkg/speak"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

var buttonMac = "ac:63:be:fb:13:9d"

// watchCmd represents the watch command
var watchCmd = &cobra.Command{
	Use:   "watch",
	Short: "Watch for the press of a Amazon Dash button",
	Long: `Watch the press of a Amazon Dash button

	`,
	Run: watch,
}

func watch(cmd *cobra.Command, args []string) {
	netInterface := viper.GetString("interface")
	if netInterface == "" {
		netInterface = "en3"
	}

	iface, err := net.InterfaceByName(netInterface)
	if err != nil {
		panic(err)
	}

	addr, err := extractAddress(iface)
	if err != nil {
		panic(err)
	}

	log.Printf("Using network range %v for interface %v", addr, iface.Name)

	// Start up a goroutine to read in packet data.
	for {
		// Open up a pcap handle for packet reads/writes.
		handle, err := pcap.OpenLive(iface.Name, 65536, true, pcap.BlockForever)
		if err != nil {
			panic(err)
		}
		if watchForButton(handle, iface) {
			handle.Close()
			buttonPushed()
		} else {
			handle.Close()
		}
	}
}

func buttonPushed() {
	log.Printf("Button pushed !")
	pufferData := api.FetchPufferData()
	speak.Speak(PufferMessage(pufferData), SpeakOptions())
}

var lastPushed = time.Time{}

// watchForButton watches a handle for incoming ARP responses we might care about, and prints them.
//
// watchForButton loops until 'stop' is closed.
func watchForButton(handle *pcap.Handle, iface *net.Interface) bool {
	src := gopacket.NewPacketSource(handle, layers.LayerTypeEthernet)
	in := src.Packets()
	for {
		var packet gopacket.Packet
		select {
		case packet = <-in:
			arpLayer := packet.Layer(layers.LayerTypeARP)
			if arpLayer == nil {
				continue
			}
			arp := arpLayer.(*layers.ARP)
			if arp.Operation == layers.ARPRequest {
				if addressEquals("00:00:00:00:00:00", arp.DstHwAddress) && addressEquals(buttonMac, arp.SourceHwAddress) {
					var now = time.Now()
					if now.Sub(lastPushed).Seconds() > 5 {
						lastPushed = now
						return true
					}
				}
			}
		}
	}
}

func addressEquals(mac string, addr []byte) bool {
	macParsed, error := net.ParseMAC(mac)
	if error != nil {
		return false
	}
	return bytes.Equal(macParsed, addr)
}

func extractAddress(iface *net.Interface) (*net.IPNet, error) {
	var addr *net.IPNet
	if addrs, err := iface.Addrs(); err != nil {
		return nil, err
	} else {
		for _, a := range addrs {
			if ipnet, ok := a.(*net.IPNet); ok {
				if ip4 := ipnet.IP.To4(); ip4 != nil {
					addr = &net.IPNet{
						IP:   ip4,
						Mask: ipnet.Mask[len(ipnet.Mask)-4:],
					}
					break
				}
			}
		}
	}
	// Sanity-check that the interface has a good address.
	if addr == nil {
		return nil, errors.New("no good IP network found")
	} else if addr.IP[0] == 127 {
		return nil, errors.New("skipping localhost")
	} else if addr.Mask[0] != 0xff || addr.Mask[1] != 0xff {
		return nil, errors.New("mask means network is too large")
	}
	return addr, nil
}

func init() {
	RootCmd.AddCommand(watchCmd)

	// Here you will define your flags and configuration settings.

	// Cobra supports Persistent Flags which will work for this command
	// and all subcommands, e.g.:
	// watchCmd.PersistentFlags().String("foo", "", "A help for foo")

	// Cobra supports local flags which will only run when this command
	// is called directly, e.g.:
	// watchCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")

}
<|endoftext|>


<commit_before>package clockwork

import (
	"sync"
	"time"
)

// Clock provides an interface that packages can use instead of directly
// using the time module, so that chronology-related behavior can be tested
type Clock interface {
	After(d time.Duration) <-chan time.Time
	Sleep(d time.Duration)
	Now() time.Time
	Since(t time.Time) time.Duration
	NewTicker(d time.Duration) Ticker
}

// FakeClock provides an interface for a clock which can be
// manually advanced through time
type FakeClock interface {
	Clock
	// Advance advances the FakeClock to a new point in time, ensuring any existing
	// sleepers are notified appropriately before returning
	Advance(d time.Duration)
	// BlockUntil will block until the FakeClock has the given number of
	// sleepers (callers of Sleep or After)
	BlockUntil(n int)
}

// NewRealClock returns a Clock which simply delegates calls to the actual time
// package; it should be used by packages in production.
func NewRealClock() Clock {
	return &realClock{}
}

// NewFakeClock returns a FakeClock implementation which can be
// manually advanced through time for testing. The initial time of the
// FakeClock will be an arbitrary non-zero time.
func NewFakeClock() FakeClock {
	// use a fixture that does not fulfill Time.IsZero()
	return NewFakeClockAt(time.Date(1984, time.April, 4, 0, 0, 0, 0, time.UTC))
}

// NewFakeClockAt returns a FakeClock initialised at the given time.Time.
func NewFakeClockAt(t time.Time) FakeClock {
	return &fakeClock{
		time: t,
	}
}

type realClock struct{}

func (rc *realClock) After(d time.Duration) <-chan time.Time {
	return time.After(d)
}

func (rc *realClock) Sleep(d time.Duration) {
	time.Sleep(d)
}

func (rc *realClock) Now() time.Time {
	return time.Now()
}

func (rc *realClock) Since(t time.Time) time.Duration {
	return rc.Now().Sub(t)
}

func (rc *realClock) NewTicker(d time.Duration) Ticker {
	return &realTicker{time.NewTicker(d)}
}

type fakeClock struct {
	sleepers []*sleeper
	blockers []*blocker
	time     time.Time

	l sync.RWMutex
}

// sleeper represents a caller of After or Sleep
type sleeper struct {
	until time.Time
	done  chan time.Time
}

// blocker represents a caller of BlockUntil
type blocker struct {
	count int
	ch    chan struct{}
}

// After mimics time.After; it waits for the given duration to elapse on the
// fakeClock, then sends the current time on the returned channel.
func (fc *fakeClock) After(d time.Duration) <-chan time.Time {
	fc.l.Lock()
	defer fc.l.Unlock()
	now := fc.time
	done := make(chan time.Time, 1)
	if d.Nanoseconds() == 0 {
		// special case - trigger immediately
		done <- now
	} else {
		// otherwise, add to the set of sleepers
		s := &sleeper{
			until: now.Add(d),
			done:  done,
		}
		fc.sleepers = append(fc.sleepers, s)
		// and notify any blockers
		fc.blockers = notifyBlockers(fc.blockers, len(fc.sleepers))
	}
	return done
}

// notifyBlockers notifies all the blockers waiting until the
// given number of sleepers are waiting on the fakeClock. It
// returns an updated slice of blockers (i.e. those still waiting)
func notifyBlockers(blockers []*blocker, count int) (newBlockers []*blocker) {
	for _, b := range blockers {
		if b.count == count {
			close(b.ch)
		} else {
			newBlockers = append(newBlockers, b)
		}
	}
	return
}

// Sleep blocks until the given duration has passed on the fakeClock
func (fc *fakeClock) Sleep(d time.Duration) {
	<-fc.After(d)
}

// Time returns the current time of the fakeClock
func (fc *fakeClock) Now() time.Time {
	fc.l.RLock()
	t := fc.time
	fc.l.RUnlock()
	return t
}

// Since returns the duration that has passed since the given time on the fakeClock
func (fc *fakeClock) Since(t time.Time) time.Duration {
	return fc.Now().Sub(t)
}

func (fc *fakeClock) NewTicker(d time.Duration) Ticker {
	ft := &fakeTicker{
		c:      make(chan time.Time, 1),
		stop:   make(chan bool, 1),
		clock:  fc,
		period: d,
	}
	go ft.tick()
	return ft
}

// Advance advances fakeClock to a new point in time, ensuring channels from any
// previous invocations of After are notified appropriately before returning
func (fc *fakeClock) Advance(d time.Duration) {
	fc.l.Lock()
	defer fc.l.Unlock()
	end := fc.time.Add(d)
	var newSleepers []*sleeper
	for _, s := range fc.sleepers {
		if end.Sub(s.until) >= 0 {
			s.done <- end
		} else {
			newSleepers = append(newSleepers, s)
		}
	}
	fc.sleepers = newSleepers
	fc.blockers = notifyBlockers(fc.blockers, len(fc.sleepers))
	fc.time = end
}

// BlockUntil will block until the fakeClock has the given number of sleepers
// (callers of Sleep or After)
func (fc *fakeClock) BlockUntil(n int) {
	fc.l.Lock()
	// Fast path: current number of sleepers is what we're looking for
	if len(fc.sleepers) == n {
		fc.l.Unlock()
		return
	}
	// Otherwise, set up a new blocker
	b := &blocker{
		count: n,
		ch:    make(chan struct{}),
	}
	fc.blockers = append(fc.blockers, b)
	fc.l.Unlock()
	<-b.ch
}
<commit_msg>FakeClock.After should short-circuit when duration is negative<commit_after>package clockwork

import (
	"sync"
	"time"
)

// Clock provides an interface that packages can use instead of directly
// using the time module, so that chronology-related behavior can be tested
type Clock interface {
	After(d time.Duration) <-chan time.Time
	Sleep(d time.Duration)
	Now() time.Time
	Since(t time.Time) time.Duration
	NewTicker(d time.Duration) Ticker
}

// FakeClock provides an interface for a clock which can be
// manually advanced through time
type FakeClock interface {
	Clock
	// Advance advances the FakeClock to a new point in time, ensuring any existing
	// sleepers are notified appropriately before returning
	Advance(d time.Duration)
	// BlockUntil will block until the FakeClock has the given number of
	// sleepers (callers of Sleep or After)
	BlockUntil(n int)
}

// NewRealClock returns a Clock which simply delegates calls to the actual time
// package; it should be used by packages in production.
func NewRealClock() Clock {
	return &realClock{}
}

// NewFakeClock returns a FakeClock implementation which can be
// manually advanced through time for testing. The initial time of the
// FakeClock will be an arbitrary non-zero time.
func NewFakeClock() FakeClock {
	// use a fixture that does not fulfill Time.IsZero()
	return NewFakeClockAt(time.Date(1984, time.April, 4, 0, 0, 0, 0, time.UTC))
}

// NewFakeClockAt returns a FakeClock initialised at the given time.Time.
func NewFakeClockAt(t time.Time) FakeClock {
	return &fakeClock{
		time: t,
	}
}

type realClock struct{}

func (rc *realClock) After(d time.Duration) <-chan time.Time {
	return time.After(d)
}

func (rc *realClock) Sleep(d time.Duration) {
	time.Sleep(d)
}

func (rc *realClock) Now() time.Time {
	return time.Now()
}

func (rc *realClock) Since(t time.Time) time.Duration {
	return rc.Now().Sub(t)
}

func (rc *realClock) NewTicker(d time.Duration) Ticker {
	return &realTicker{time.NewTicker(d)}
}

type fakeClock struct {
	sleepers []*sleeper
	blockers []*blocker
	time     time.Time

	l sync.RWMutex
}

// sleeper represents a caller of After or Sleep
type sleeper struct {
	until time.Time
	done  chan time.Time
}

// blocker represents a caller of BlockUntil
type blocker struct {
	count int
	ch    chan struct{}
}

// After mimics time.After; it waits for the given duration to elapse on the
// fakeClock, then sends the current time on the returned channel.
func (fc *fakeClock) After(d time.Duration) <-chan time.Time {
	fc.l.Lock()
	defer fc.l.Unlock()
	now := fc.time
	done := make(chan time.Time, 1)
	if d.Nanoseconds() <= 0 {
		// special case - trigger immediately
		done <- now
	} else {
		// otherwise, add to the set of sleepers
		s := &sleeper{
			until: now.Add(d),
			done:  done,
		}
		fc.sleepers = append(fc.sleepers, s)
		// and notify any blockers
		fc.blockers = notifyBlockers(fc.blockers, len(fc.sleepers))
	}
	return done
}

// notifyBlockers notifies all the blockers waiting until the
// given number of sleepers are waiting on the fakeClock. It
// returns an updated slice of blockers (i.e. those still waiting)
func notifyBlockers(blockers []*blocker, count int) (newBlockers []*blocker) {
	for _, b := range blockers {
		if b.count == count {
			close(b.ch)
		} else {
			newBlockers = append(newBlockers, b)
		}
	}
	return
}

// Sleep blocks until the given duration has passed on the fakeClock
func (fc *fakeClock) Sleep(d time.Duration) {
	<-fc.After(d)
}

// Time returns the current time of the fakeClock
func (fc *fakeClock) Now() time.Time {
	fc.l.RLock()
	t := fc.time
	fc.l.RUnlock()
	return t
}

// Since returns the duration that has passed since the given time on the fakeClock
func (fc *fakeClock) Since(t time.Time) time.Duration {
	return fc.Now().Sub(t)
}

func (fc *fakeClock) NewTicker(d time.Duration) Ticker {
	ft := &fakeTicker{
		c:      make(chan time.Time, 1),
		stop:   make(chan bool, 1),
		clock:  fc,
		period: d,
	}
	go ft.tick()
	return ft
}

// Advance advances fakeClock to a new point in time, ensuring channels from any
// previous invocations of After are notified appropriately before returning
func (fc *fakeClock) Advance(d time.Duration) {
	fc.l.Lock()
	defer fc.l.Unlock()
	end := fc.time.Add(d)
	var newSleepers []*sleeper
	for _, s := range fc.sleepers {
		if end.Sub(s.until) >= 0 {
			s.done <- end
		} else {
			newSleepers = append(newSleepers, s)
		}
	}
	fc.sleepers = newSleepers
	fc.blockers = notifyBlockers(fc.blockers, len(fc.sleepers))
	fc.time = end
}

// BlockUntil will block until the fakeClock has the given number of sleepers
// (callers of Sleep or After)
func (fc *fakeClock) BlockUntil(n int) {
	fc.l.Lock()
	// Fast path: current number of sleepers is what we're looking for
	if len(fc.sleepers) == n {
		fc.l.Unlock()
		return
	}
	// Otherwise, set up a new blocker
	b := &blocker{
		count: n,
		ch:    make(chan struct{}),
	}
	fc.blockers = append(fc.blockers, b)
	fc.l.Unlock()
	<-b.ch
}
<|endoftext|>


<commit_before>package cm15

import (
	"log"

	"github.com/rightscale/rsc/cmd"
	"github.com/rightscale/rsc/rsapi"
)

// Api 1.5 client
// Just a vanilla RightScale API client.
type Api struct {
	*rsapi.Api
}

// New returns a API 1.5 client.
// It makes a test request to API 1.5 and returns an error if authentication fails.
// host may be blank in which case client attempts to resolve it using auth.
// logger is optional.
// If client is nil then the default HTTP client is used.
func New(host string, auth rsapi.Authenticator, logger *log.Logger,
	client rsapi.HttpClient) *Api {
	return fromApi(rsapi.New(host, auth, logger, client))
}

// NewRL10 returns a API 1.5 client that uses the information stored in /var/run/rightlink/secret to do
// auth and configure the host. The client behaves identically to the one returned by New in
// all other aspects.
func NewRL10(logger *log.Logger, client rsapi.HttpClient) (*Api, error) {
	raw, err := rsapi.NewRL10(logger, client)
	if err != nil {
		return nil, err
	}
	return fromApi(raw), nil
}

// Build client from command line
func FromCommandLine(cmdLine *cmd.CommandLine) (*Api, error) {
	raw, err := rsapi.FromCommandLine(cmdLine)
	if err != nil {
		return nil, err
	}
	return fromApi(raw), nil
}

// Wrap generic client into API 1.5 client
func fromApi(api *rsapi.Api) *Api {
	api.Metadata = GenMetadata
	return &Api{api}
}
<commit_msg>Formatting<commit_after>package cm15

import (
	"log"

	"github.com/rightscale/rsc/cmd"
	"github.com/rightscale/rsc/rsapi"
)

// Api 1.5 client
// Just a vanilla RightScale API client.
type Api struct {
	*rsapi.Api
}

// New returns a API 1.5 client.
// It makes a test request to API 1.5 and returns an error if authentication fails.
// host may be blank in which case client attempts to resolve it using auth.
// logger is optional.
// If client is nil then the default HTTP client is used.
func New(host string, auth rsapi.Authenticator, logger *log.Logger, client rsapi.HttpClient) *Api {
	return fromApi(rsapi.New(host, auth, logger, client))
}

// NewRL10 returns a API 1.5 client that uses the information stored in /var/run/rightlink/secret to do
// auth and configure the host. The client behaves identically to the one returned by New in
// all other aspects.
func NewRL10(logger *log.Logger, client rsapi.HttpClient) (*Api, error) {
	raw, err := rsapi.NewRL10(logger, client)
	if err != nil {
		return nil, err
	}
	return fromApi(raw), nil
}

// Build client from command line
func FromCommandLine(cmdLine *cmd.CommandLine) (*Api, error) {
	raw, err := rsapi.FromCommandLine(cmdLine)
	if err != nil {
		return nil, err
	}
	return fromApi(raw), nil
}

// Wrap generic client into API 1.5 client
func fromApi(api *rsapi.Api) *Api {
	api.Metadata = GenMetadata
	return &Api{api}
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"
	"strings"

	"github.com/open-falcon/falcon-plus/g"
	"github.com/spf13/cobra"
)

var Check = &cobra.Command{
	Use:   "check [Module ...]",
	Short: "Check the status of Open-Falcon modules",
	Long: `
Check if the specified Open-Falcon modules are running.

Modules:
  ` + "all " + strings.Join(g.AllModulesInOrder, " "),
	RunE: check,
}

func check(c *cobra.Command, args []string) error {
	if len(args) == 0 {
		return c.Usage()
	}
	for _, moduleName := range args {
		if !g.HasModule(moduleName) {
			return fmt.Errorf("%s doesn't exist\n", moduleName)
		}

		if g.IsRunning(moduleName) {
			fmt.Print("[", g.ModuleApps[moduleName], "] ", g.Pid(moduleName), "\n")
		} else {
			fmt.Print("[", g.ModuleApps[moduleName], "] down\n")
		}
	}
	return nil
}
<commit_msg>add module 'all' for cmd/check<commit_after>package cmd

import (
	"fmt"
	"strings"

	"github.com/open-falcon/falcon-plus/g"
	"github.com/spf13/cobra"
)

var Check = &cobra.Command{
	Use:   "check [Module ...]",
	Short: "Check the status of Open-Falcon modules",
	Long: `
Check if the specified Open-Falcon modules are running.

Modules:
  ` + "all " + strings.Join(g.AllModulesInOrder, " "),
	RunE: check,
}

func check(c *cobra.Command, args []string) error {
	if len(args) == 0 {
		return c.Usage()
	}

	if len(args) == 1 && args[0] == "all" {
		for moduleName := range g.Modules {
			if g.IsRunning(moduleName) {
				fmt.Printf("%20s %10s %15s \n", g.ModuleApps[moduleName], "UP", g.Pid(moduleName))
			} else {
				fmt.Printf("%20s %10s %15s \n", g.ModuleApps[moduleName], "DOWN", "-")
			}
		}
	} else {
		for _, moduleName := range args {
			if !g.HasModule(moduleName) {
				return fmt.Errorf("%s doesn't exist\n", moduleName)
			}

			if g.IsRunning(moduleName) {
				fmt.Print("[", g.ModuleApps[moduleName], "] ", g.Pid(moduleName), "\n")
			} else {
				fmt.Print("[", g.ModuleApps[moduleName], "] down\n")
			}
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"path"
	"strconv"

	"github.com/codegangsta/cli"

	"github.com/yuuki1/droot/commands"
	"github.com/yuuki1/droot/log"
)

var AppHelpTemplate = `Usage: {{.Name}} {{if .Flags}}[OPTIONS] {{end}}COMMAND [arg...]

{{.Usage}}

Version: {{.Version}}{{if or .Author .Email}}

Author:{{if .Author}}
  {{.Author}}{{if .Email}} - <{{.Email}}>{{end}}{{else}}
  {{.Email}}{{end}}{{end}}
{{if .Flags}}
Options:
  {{range .Flags}}{{.}}
  {{end}}{{end}}
Commands:
  {{range .Commands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}}
  {{end}}
Run '{{.Name}} COMMAND --help' for more information on a command.
`

var commandArgs = map[string]string{
	"push":   commands.CommandArgPush,
	"pull":   commands.CommandArgPull,
	"run":    commands.CommandArgRun,
	"umount": commands.CommandArgUmount,
	"rm":     commands.CommandArgRm,
}

func setDebugOutputLevel() {
	for _, f := range os.Args {
		if f == "-D" || f == "--debug" || f == "-debug" {
			log.IsDebug = true
		}
	}

	debugEnv := os.Getenv("DROOT_DEBUG")
	if debugEnv != "" {
		showDebug, err := strconv.ParseBool(debugEnv)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error parsing boolean value from DROOT_DEBUG: %s\n", err)
			os.Exit(1)
		}
		log.IsDebug = showDebug
	}
}

func init() {
	setDebugOutputLevel()
	argsTemplate := "{{if false}}"
	for _, command := range append(commands.Commands) {
		argsTemplate = argsTemplate + fmt.Sprintf("{{else if (eq .Name %q)}}%s %s", command.Name, command.Name, commandArgs[command.Name])
	}
	argsTemplate = argsTemplate + "{{end}}"

	cli.CommandHelpTemplate = `Usage: droot ` + argsTemplate + `

{{.Usage}}{{if .Description}}

Description:
   {{.Description}}{{end}}{{if .Flags}}

Options:
   {{range .Flags}}
   {{.}}{{end}}{{ end }}
`

	cli.AppHelpTemplate = AppHelpTemplate
}

func main() {
	app := cli.NewApp()
	app.Name = path.Base(os.Args[0])
	app.Author = "y_uuki"
	app.Email = "https://github.com/yuuki1/droot"
	app.Commands = commands.Commands
	app.CommandNotFound = cmdNotFound
	app.Usage = "droot is a CLI tool for chrooting a docker image."
	app.Version = Version

	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:  "debug, D",
			Usage: "Enable debug mode",
		},
	}

	if err := app.Run(os.Args); err != nil {
		log.Error(err)
	}
}

func cmdNotFound(c *cli.Context, command string) {
	log.Errorf(
		"%s: '%s' is not a %s command. See '%s --help'.",
		c.App.Name,
		command,
		c.App.Name,
		os.Args[0],
	)
}
<commit_msg>Update help message<commit_after>package main

import (
	"fmt"
	"os"
	"path"
	"strconv"

	"github.com/codegangsta/cli"

	"github.com/yuuki1/droot/commands"
	"github.com/yuuki1/droot/log"
)

var AppHelpTemplate = `Usage: {{.Name}} {{if .Flags}}[OPTIONS] {{end}}COMMAND [arg...]

{{.Usage}}

Version: {{.Version}}{{if or .Author .Email}}

Author:{{if .Author}}
  {{.Author}}{{if .Email}} - <{{.Email}}>{{end}}{{else}}
  {{.Email}}{{end}}{{end}}
{{if .Flags}}
Options:
  {{range .Flags}}{{.}}
  {{end}}{{end}}
Commands:
  {{range .Commands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}}
  {{end}}
Run '{{.Name}} COMMAND --help' for more information on a command.
`

var commandArgs = map[string]string{
	"push":   commands.CommandArgPush,
	"pull":   commands.CommandArgPull,
	"run":    commands.CommandArgRun,
	"umount": commands.CommandArgUmount,
	"rm":     commands.CommandArgRm,
}

func setDebugOutputLevel() {
	for _, f := range os.Args {
		if f == "-D" || f == "--debug" || f == "-debug" {
			log.IsDebug = true
		}
	}

	debugEnv := os.Getenv("DROOT_DEBUG")
	if debugEnv != "" {
		showDebug, err := strconv.ParseBool(debugEnv)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error parsing boolean value from DROOT_DEBUG: %s\n", err)
			os.Exit(1)
		}
		log.IsDebug = showDebug
	}
}

func init() {
	setDebugOutputLevel()
	argsTemplate := "{{if false}}"
	for _, command := range append(commands.Commands) {
		argsTemplate = argsTemplate + fmt.Sprintf("{{else if (eq .Name %q)}}%s %s", command.Name, command.Name, commandArgs[command.Name])
	}
	argsTemplate = argsTemplate + "{{end}}"

	cli.CommandHelpTemplate = `Usage: droot ` + argsTemplate + `

{{.Usage}}{{if .Description}}

Description:
   {{.Description}}{{end}}{{if .Flags}}

Options:
   {{range .Flags}}
   {{.}}{{end}}{{ end }}
`

	cli.AppHelpTemplate = AppHelpTemplate
}

func main() {
	app := cli.NewApp()
	app.Name = path.Base(os.Args[0])
	app.Author = "y_uuki"
	app.Email = "https://github.com/yuuki1/droot"
	app.Commands = commands.Commands
	app.CommandNotFound = cmdNotFound
	app.Usage = "droot is a super-easy container with chroot without docker."
	app.Version = Version

	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:  "debug, D",
			Usage: "Enable debug mode",
		},
	}

	if err := app.Run(os.Args); err != nil {
		log.Error(err)
	}
}

func cmdNotFound(c *cli.Context, command string) {
	log.Errorf(
		"%s: '%s' is not a %s command. See '%s --help'.",
		c.App.Name,
		command,
		c.App.Name,
		os.Args[0],
	)
}
<|endoftext|>


<commit_before>//
// epharvest is an eprinttools based cli for harvesting EPrints content into a dataset collection.
//
// @author R. S. Doiel, <rsdoiel@caltech.edu>
//
// Copyright (c) 2018, Caltech
// All rights not granted herein are expressly reserved by Caltech.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
package main

import (
	"fmt"
	"log"
	"net/url"
	"os"
	"strconv"
	"strings"
	"time"

	// Caltech Library Packages
	"github.com/caltechlibrary/cli"
	"github.com/caltechlibrary/eprinttools"
	"github.com/caltechlibrary/eprinttools/harvest"
)

var (
	// cli help text
	description = `
%s uses the REST API for EPrints 3.x to harvest EPrints content into
a dataset collection. If you don't need dataset integration use eputil
instead. If you want to view  the harvested content then use the
dataset command.

CONFIGURATION

ep can be configured with following environment variables

EPRINT_URL the URL to your EPrints installation

DATASET the dataset collection name to use for storing your harvested EPrint content.
`

	examples = `
Save a list the URI end points for eprint records found at EPRINT_URL.

	%s -o uris.txt

Export the entire EPrints repository public content defined by the
environment variables EPRINT_URL, DATASET.

    %s -export all

Export 2000 EPrints from the repository with the heighest ID values.

    %s -export 2000

Export the EPrint records modified since July 1, 2017.

    %s -export-modified 2017-07-01

Explore a specific listof keys (e.g. "101,102,1304")

	%s -export-keys "101,102,1304"

Export the EPrint records with modified times in July 2017 and
save the keys for the records exported with one key per line.

    %s -export-modified 2017-07-01,2017-07-31 \
       -export-save-keys=july-keys.txt
`

	// Standard Options
	showHelp             bool
	showVersion          bool
	showLicense          bool
	showExamples         bool
	outputFName          string
	quiet                bool
	generateMarkdownDocs bool
	newLine              bool

	// App Options
	verbose     bool
	useAPI      bool
	prettyPrint bool

	apiURL      string
	datasetName string

	updatedSince          string
	exportEPrints         string
	exportEPrintsModified string
	exportSaveKeys        string
	exportEPrintsKeyList  string

	authMethod string
	userName   string
	userSecret string

	// NOTE: supressNote (Internal Note) added to handle the case where Note field is internal use only and not to be harvested
	suppressNote bool

	thisProcessID int
)

func main() {
	var (
		apiURLEnv       string
		datasetNameEnv  string
		suppressNoteEnv bool
	)
	app := cli.NewCli(eprinttools.Version)
	appName := app.AppName()
	thisProcessID = os.Getpid()

	// Document non-option parameters
	app.AddParams("[EPRINT_URL]", "[ONE_OR_MORE_EPRINT_ID]")

	// Add Help Docs
	app.AddHelp("license", []byte(fmt.Sprintf(eprinttools.LicenseText, appName, eprinttools.Version)))
	app.AddHelp("description", []byte(fmt.Sprintf(description, appName)))
	app.AddHelp("examples", []byte(fmt.Sprintf(examples, appName, appName, appName, appName, appName, appName)))

	// App Environment
	app.EnvStringVar(&apiURLEnv, "EPRINT_URL", "", "Sets the EPRints API URL")
	app.EnvStringVar(&datasetNameEnv, "DATASET", "", "Sets the dataset collection for storing EPrint harvested records")

	// Standard Options
	app.BoolVar(&showHelp, "h,help", false, "display help")
	app.BoolVar(&showLicense, "l,license", false, "display license")
	app.BoolVar(&showVersion, "v,version", false, "display version")
	app.BoolVar(&showExamples, "examples", false, "display example(s)")
	app.StringVar(&outputFName, "o,output", "", "output filename")
	app.BoolVar(&generateMarkdownDocs, "generate-markdown-docs", false, "generation markdown documentation")
	app.BoolVar(&quiet, "quiet", false, "suppress error output")
	app.BoolVar(&newLine, "nl,newline", true, "set to false to exclude trailing newline")

	// App Specific options
	app.BoolVar(&verbose, "verbose", true, "verbose logging")
	app.StringVar(&authMethod, "auth", "", "set the authentication method (e.g. none, basic, oauth, shib)")
	app.StringVar(&userName, "un,username", "", "set the username")
	app.StringVar(&userSecret, "pw,password", "", "set the password")

	app.StringVar(&apiURL, "api", "", "url for EPrints API")
	app.StringVar(&datasetName, "dataset", "", "dataset collection name")

	app.BoolVar(&prettyPrint, "p,pretty", false, "pretty print JSON output")
	app.BoolVar(&useAPI, "read-api", false, "read the contents from the API without saving in the database")
	app.StringVar(&exportEPrints, "export", "", "export N EPrints from highest ID to lowest")
	app.StringVar(&exportEPrintsModified, "export-modified", "", "export records by date or date range (e.g. 2017-07-01)")
	app.StringVar(&exportSaveKeys, "export-save-keys", "", "save the keys exported in a file with provided filename")
	app.StringVar(&exportEPrintsKeyList, "export-keys", "", "export a comma delimited list of EPrint keys")
	app.StringVar(&updatedSince, "updated-since", "", "list EPrint IDs updated since a given date (e.g 2017-07-01)")

	// Parse environment and options
	if err := app.Parse(); err != nil {
		fmt.Fprintf(os.Stderr, "Something went wrong parsing env and options!, %s\n", err)
		os.Exit(1)
	}
	args := app.Args()
	if apiURL == "" {
		apiURL = app.Getenv("EPRINT_URL")
		if len(args) > 0 {
			for _, val := range args {
				if strings.Contains(val, "://") {
					apiURL = val
					break
				}
			}
		}
	}
	if datasetName == "" {
		datasetName = app.Getenv("DATASET")
	}

	// Setup IO
	var err error

	app.Eout = os.Stderr

	app.Out, err = cli.Create(outputFName, os.Stdout)
	if err != nil {
		fmt.Fprintf(app.Eout, "%s\n", err)
		os.Exit(1)
	}
	defer cli.CloseFile(outputFName, app.In)

	// Process Options
	if generateMarkdownDocs {
		app.GenerateMarkdownDocs(app.Out)
		os.Exit(0)
	}
	if showHelp || showExamples {
		if len(args) > 0 {
			fmt.Println(app.Help(args...))
		} else {
			app.Usage(app.Out)
		}
		os.Exit(0)
	}
	if showVersion {
		fmt.Println(app.Version())
		os.Exit(0)
	}
	if showLicense {
		fmt.Println(app.License())
		os.Exit(0)
	}

	// Required configuration, let Env overide options if not options are defaults
	if apiURL == "" {
		if apiURLEnv == "" {
			fmt.Fprintf(app.Eout, "EPrint URL not provided, -api ..., 'export EPRINT_URL=...'\n")
			os.Exit(1)
		}
		apiURL = apiURLEnv
	}
	if datasetName == "" {
		if datasetNameEnv == "" {
			fmt.Fprintf(app.Eout, "Missing dataset (e.g. --dataset ..., 'export DATASET=...') name\n")
			os.Exit(1)
		}
		datasetName = datasetNameEnv
	}
	if suppressNote == false && suppressNoteEnv == true {
		suppressNote = true
	}

	// This will read in the settings from the app
	// and configure access to the EPrints API
	if u, err := url.Parse(apiURL); err == nil {
		if strings.HasSuffix(u.Path, "/rest/eprint") == true {
			u.Path = strings.TrimSuffix(u.Path, "/rest/eprint")
			apiURL = u.String()
		}
	} else {
		fmt.Fprintf(app.Eout, "%s\n", err)
		os.Exit(1)
	}
	api, err := eprinttools.New(apiURL, datasetName, suppressNote, authMethod, userName, userSecret)
	if err != nil {
		fmt.Fprintf(app.Eout, "%s\n", err)
		os.Exit(1)
	}

	log.Printf("(pid %d) %s %s", thisProcessID, appName, eprinttools.Version)
	log.Printf("(pid %d) Harvesting from %s", thisProcessID, apiURL)
	t0 := time.Now()
	switch {
	case exportEPrintsKeyList != "":
		log.Printf("(pid %d) Export started, %s", thisProcessID, t0)
		if err := harvest.ExportEPrintsKeyList(api, strings.Split(exportEPrintsKeyList, ","), exportSaveKeys, verbose); err != nil {
			log.Fatalf("(pid %d) %s", thisProcessID, err)
		}
	case exportEPrintsModified != "":
		s := exportEPrintsModified
		e := time.Now().Format("2006-01-02")
		if strings.Contains(s, ",") {
			p := strings.SplitN(s, ",", 2)
			s, e = p[0], p[1]
		}
		start, err := time.Parse("2006-01-02", s)
		if err != nil {
			log.Fatalf("(pid %d) %s", thisProcessID, err)
		}
		end, err := time.Parse("2006-01-02", e)
		if err != nil {
			log.Fatalf("(pid %d) %s", thisProcessID, err)
		}
		log.Printf("(pid %d) Export from %s to %s, started %s", thisProcessID, start.Format("2006-01-02"), end.Format("2006-01-02"), t0.Format("2006-01-02 15:04:05 MST"))
		if err := harvest.ExportModifiedEPrints(api, start, end, exportSaveKeys, verbose); err != nil {
			log.Fatalf("(pid %d) %s", thisProcessID, err)
		}
	case exportEPrints != "":
		exportNo := -1
		if exportEPrints != "all" {
			exportNo, err = strconv.Atoi(exportEPrints)
			if err != nil {
				log.Fatalf("(pid %d) Export count should be %q or an integer, %s", thisProcessID, exportEPrints, err)
			}
		}
		log.Printf("(pid %d) Export started, %s", thisProcessID, t0)
		if err := harvest.ExportEPrints(api, exportNo, exportSaveKeys, verbose); err != nil {
			log.Fatalf("(pid %d) %s", thisProcessID, err)
		}
	default:
		if uris, err := api.ListEPrintsURI(); err != nil {
			log.Fatalf("(pid %d) %s", thisProcessID, err)
		} else {
			fmt.Fprintf(app.Out, strings.Join(uris, "\n"))
		}
	}
	log.Printf("(pid %d) Export completed, running time %s", thisProcessID, time.Now().Sub(t0))
	os.Exit(0)
}
<commit_msg>another log output fix<commit_after>//
// epharvest is an eprinttools based cli for harvesting EPrints content into a dataset collection.
//
// @author R. S. Doiel, <rsdoiel@caltech.edu>
//
// Copyright (c) 2018, Caltech
// All rights not granted herein are expressly reserved by Caltech.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
package main

import (
	"fmt"
	"log"
	"net/url"
	"os"
	"strconv"
	"strings"
	"time"

	// Caltech Library Packages
	"github.com/caltechlibrary/cli"
	"github.com/caltechlibrary/eprinttools"
	"github.com/caltechlibrary/eprinttools/harvest"
)

var (
	// cli help text
	description = `
%s uses the REST API for EPrints 3.x to harvest EPrints content into
a dataset collection. If you don't need dataset integration use eputil
instead. If you want to view  the harvested content then use the
dataset command.

CONFIGURATION

ep can be configured with following environment variables

EPRINT_URL the URL to your EPrints installation

DATASET the dataset collection name to use for storing your harvested EPrint content.
`

	examples = `
Save a list the URI end points for eprint records found at EPRINT_URL.

	%s -o uris.txt

Export the entire EPrints repository public content defined by the
environment variables EPRINT_URL, DATASET.

    %s -export all

Export 2000 EPrints from the repository with the heighest ID values.

    %s -export 2000

Export the EPrint records modified since July 1, 2017.

    %s -export-modified 2017-07-01

Explore a specific listof keys (e.g. "101,102,1304")

	%s -export-keys "101,102,1304"

Export the EPrint records with modified times in July 2017 and
save the keys for the records exported with one key per line.

    %s -export-modified 2017-07-01,2017-07-31 \
       -export-save-keys=july-keys.txt
`

	// Standard Options
	showHelp             bool
	showVersion          bool
	showLicense          bool
	showExamples         bool
	outputFName          string
	quiet                bool
	generateMarkdownDocs bool
	newLine              bool

	// App Options
	verbose     bool
	useAPI      bool
	prettyPrint bool

	apiURL      string
	datasetName string

	updatedSince          string
	exportEPrints         string
	exportEPrintsModified string
	exportSaveKeys        string
	exportEPrintsKeyList  string

	authMethod string
	userName   string
	userSecret string

	// NOTE: supressNote (Internal Note) added to handle the case where Note field is internal use only and not to be harvested
	suppressNote bool

	thisProcessID int
)

func main() {
	var (
		apiURLEnv       string
		datasetNameEnv  string
		suppressNoteEnv bool
	)
	app := cli.NewCli(eprinttools.Version)
	appName := app.AppName()
	thisProcessID = os.Getpid()

	// Document non-option parameters
	app.AddParams("[EPRINT_URL]", "[ONE_OR_MORE_EPRINT_ID]")

	// Add Help Docs
	app.AddHelp("license", []byte(fmt.Sprintf(eprinttools.LicenseText, appName, eprinttools.Version)))
	app.AddHelp("description", []byte(fmt.Sprintf(description, appName)))
	app.AddHelp("examples", []byte(fmt.Sprintf(examples, appName, appName, appName, appName, appName, appName)))

	// App Environment
	app.EnvStringVar(&apiURLEnv, "EPRINT_URL", "", "Sets the EPRints API URL")
	app.EnvStringVar(&datasetNameEnv, "DATASET", "", "Sets the dataset collection for storing EPrint harvested records")

	// Standard Options
	app.BoolVar(&showHelp, "h,help", false, "display help")
	app.BoolVar(&showLicense, "l,license", false, "display license")
	app.BoolVar(&showVersion, "v,version", false, "display version")
	app.BoolVar(&showExamples, "examples", false, "display example(s)")
	app.StringVar(&outputFName, "o,output", "", "output filename")
	app.BoolVar(&generateMarkdownDocs, "generate-markdown-docs", false, "generation markdown documentation")
	app.BoolVar(&quiet, "quiet", false, "suppress error output")
	app.BoolVar(&newLine, "nl,newline", true, "set to false to exclude trailing newline")

	// App Specific options
	app.BoolVar(&verbose, "verbose", true, "verbose logging")
	app.StringVar(&authMethod, "auth", "", "set the authentication method (e.g. none, basic, oauth, shib)")
	app.StringVar(&userName, "un,username", "", "set the username")
	app.StringVar(&userSecret, "pw,password", "", "set the password")

	app.StringVar(&apiURL, "api", "", "url for EPrints API")
	app.StringVar(&datasetName, "dataset", "", "dataset collection name")

	app.BoolVar(&prettyPrint, "p,pretty", false, "pretty print JSON output")
	app.BoolVar(&useAPI, "read-api", false, "read the contents from the API without saving in the database")
	app.StringVar(&exportEPrints, "export", "", "export N EPrints from highest ID to lowest")
	app.StringVar(&exportEPrintsModified, "export-modified", "", "export records by date or date range (e.g. 2017-07-01)")
	app.StringVar(&exportSaveKeys, "export-save-keys", "", "save the keys exported in a file with provided filename")
	app.StringVar(&exportEPrintsKeyList, "export-keys", "", "export a comma delimited list of EPrint keys")
	app.StringVar(&updatedSince, "updated-since", "", "list EPrint IDs updated since a given date (e.g 2017-07-01)")

	// Parse environment and options
	if err := app.Parse(); err != nil {
		fmt.Fprintf(os.Stderr, "Something went wrong parsing env and options!, %s\n", err)
		os.Exit(1)
	}
	args := app.Args()
	if apiURL == "" {
		apiURL = app.Getenv("EPRINT_URL")
		if len(args) > 0 {
			for _, val := range args {
				if strings.Contains(val, "://") {
					apiURL = val
					break
				}
			}
		}
	}
	if datasetName == "" {
		datasetName = app.Getenv("DATASET")
	}

	// Setup IO
	var err error

	app.Eout = os.Stderr

	app.Out, err = cli.Create(outputFName, os.Stdout)
	if err != nil {
		fmt.Fprintf(app.Eout, "%s\n", err)
		os.Exit(1)
	}
	defer cli.CloseFile(outputFName, app.In)

	// Process Options
	if generateMarkdownDocs {
		app.GenerateMarkdownDocs(app.Out)
		os.Exit(0)
	}
	if showHelp || showExamples {
		if len(args) > 0 {
			fmt.Println(app.Help(args...))
		} else {
			app.Usage(app.Out)
		}
		os.Exit(0)
	}
	if showVersion {
		fmt.Println(app.Version())
		os.Exit(0)
	}
	if showLicense {
		fmt.Println(app.License())
		os.Exit(0)
	}

	// Required configuration, let Env overide options if not options are defaults
	if apiURL == "" {
		if apiURLEnv == "" {
			fmt.Fprintf(app.Eout, "EPrint URL not provided, -api ..., 'export EPRINT_URL=...'\n")
			os.Exit(1)
		}
		apiURL = apiURLEnv
	}
	if datasetName == "" {
		if datasetNameEnv == "" {
			fmt.Fprintf(app.Eout, "Missing dataset (e.g. --dataset ..., 'export DATASET=...') name\n")
			os.Exit(1)
		}
		datasetName = datasetNameEnv
	}
	if suppressNote == false && suppressNoteEnv == true {
		suppressNote = true
	}

	// This will read in the settings from the app
	// and configure access to the EPrints API
	if u, err := url.Parse(apiURL); err == nil {
		if strings.HasSuffix(u.Path, "/rest/eprint") == true {
			u.Path = strings.TrimSuffix(u.Path, "/rest/eprint")
			apiURL = u.String()
		}
	} else {
		fmt.Fprintf(app.Eout, "%s\n", err)
		os.Exit(1)
	}
	api, err := eprinttools.New(apiURL, datasetName, suppressNote, authMethod, userName, userSecret)
	if err != nil {
		fmt.Fprintf(app.Eout, "%s\n", err)
		os.Exit(1)
	}

	log.Printf("(pid %d) %s %s", thisProcessID, appName, eprinttools.Version)
	log.Printf("(pid %d) Harvesting from %s", thisProcessID, apiURL)
	t0 := time.Now()
	switch {
	case exportEPrintsKeyList != "":
		log.Printf("(pid %d) Export started, %s", thisProcessID, t0)
		if err := harvest.ExportEPrintsKeyList(api, strings.Split(exportEPrintsKeyList, ","), exportSaveKeys, verbose); err != nil {
			log.Fatalf("(pid %d) %s", thisProcessID, err)
		}
	case exportEPrintsModified != "":
		s := exportEPrintsModified
		e := time.Now().Format("2006-01-02")
		if strings.Contains(s, ",") {
			p := strings.SplitN(s, ",", 2)
			s, e = p[0], p[1]
		}
		start, err := time.Parse("2006-01-02", s)
		if err != nil {
			log.Fatalf("(pid %d) %s", thisProcessID, err)
		}
		end, err := time.Parse("2006-01-02", e)
		if err != nil {
			log.Fatalf("(pid %d) %s", thisProcessID, err)
		}
		log.Printf("(pid %d) Export from %s to %s, started %s", thisProcessID, start.Format("2006-01-02"), end.Format("2006-01-02"), t0.Format("2006-01-02 15:04:05 MST"))
		if err := harvest.ExportModifiedEPrints(api, start, end, exportSaveKeys, verbose); err != nil {
			log.Fatalf("(pid %d) %s", thisProcessID, err)
		}
	case exportEPrints != "":
		exportNo := -1
		if exportEPrints != "all" {
			exportNo, err = strconv.Atoi(exportEPrints)
			if err != nil {
				log.Fatalf("(pid %d) Export count should be %q or an integer, %s", thisProcessID, exportEPrints, err)
			}
		}
		log.Printf("(pid %d) Export started, %s", thisProcessID, t0)
		if err := harvest.ExportEPrints(api, exportNo, exportSaveKeys, verbose); err != nil {
			log.Fatalf("(pid %d) %s", thisProcessID, err)
		}
	default:
		if uris, err := api.ListEPrintsURI(); err != nil {
			log.Fatalf("(pid %d) %s", thisProcessID, err)
		} else {
			fmt.Fprintf(app.Out, strings.Join(uris, "\n"))
		}
	}
	log.Printf("(pid %d) Export completed, running time %s", thisProcessID, time.Now().Sub(t0).Round(time.Second))
	os.Exit(0)
}
<|endoftext|>


<commit_before>// Copyright © 2017 Michael Lihs
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package cmd

import (
	"fmt"
	"errors"

	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

// groupCmd represents the group command
var groupCmd = &cobra.Command{
	Use:   "group",
	Short: "Manage Gitlab Groups",
	Long: `Show, create, update and delete Gitlab groups.`,
	Run: func(cmd *cobra.Command, args []string) {
		// TODO how can we make Cobra do this
		fmt.Println("use one of the subcommands: get")
	},
}

var groupGetCmd = &cobra.Command{
	Use: "get",
	Short: "Get detailed information for a group",
	Long: `Get detailed information for a group identified by either ID or the namespace / path of the group`,
	RunE: func(cmd *cobra.Command, args []string) error {
		if id == "" {
			return errors.New("Required parameter `-i` or `--id` not given. Exiting.")
		}
		// TODO do something useful with the repsonse
		group, _, err := gitlabClient.Groups.GetGroup(id)
		if err != nil {
			return err
		}
		err = OutputJson(group)
		return err
	},
}

func init() {
	initGroupGetCommand()
	RootCmd.AddCommand(groupCmd)
}

func initGroupGetCommand() {
	groupGetCmd.PersistentFlags().StringVarP(&id, "id", "i", "", "(required) Either ID or namespace of group")
	viper.BindPFlag("id", groupGetCmd.PersistentFlags().Lookup("id"))
	groupCmd.AddCommand(groupGetCmd)
}
<commit_msg>add group create command<commit_after>// Copyright © 2017 Michael Lihs
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package cmd

import (
	"fmt"
	"errors"

	"github.com/spf13/cobra"
	"github.com/spf13/viper"
	"github.com/xanzy/go-gitlab"
)

// groupCmd represents the group command
var groupCmd = &cobra.Command{
	Use:   "group",
	Short: "Manage Gitlab Groups",
	Long: `Show, create, update and delete Gitlab groups.`,
	Run: func(cmd *cobra.Command, args []string) {
		// TODO how can we make Cobra do this
		fmt.Println("use one of the subcommands: get")
	},
}

var groupGetCmd = &cobra.Command{
	Use: "get",
	Short: "Get detailed information for a group",
	Long: `Get detailed information for a group identified by either ID or the namespace / path of the group`,
	RunE: func(cmd *cobra.Command, args []string) error {
		if id == "" {
			return errors.New("Required parameter `-i` or `--id` not given. Exiting.")
		}
		// TODO do something useful with the response
		group, _, err := gitlabClient.Groups.GetGroup(id)
		if err != nil {
			return err
		}
		err = OutputJson(group)
		return err
	},
}

var groupCreateCommand = &cobra.Command{
	Use: "create",
	Short: "Create a new group",
	Long: `Create a new group for the given parameters`,
	RunE: func(cmd *cobra.Command, args []string) error {
		if name == "" {
			return errors.New("Required parameter `-n` or `--name` not given. Exiting.")
		}
		group, _, err := gitlabClient.Groups.CreateGroup(&gitlab.CreateGroupOptions{Name: &name, Path: &name})
		if err != nil {
			return err
		}
		err = OutputJson(group)
		return err
	},
}

func init() {
	initGroupGetCommand()
	initGroupCreateCommand()
	RootCmd.AddCommand(groupCmd)
}

func initGroupGetCommand() {
	groupGetCmd.PersistentFlags().StringVarP(&id, "id", "i", "", "(required) Either ID or namespace of group")
	viper.BindPFlag("id", groupGetCmd.PersistentFlags().Lookup("id"))
	groupCmd.AddCommand(groupGetCmd)
}

func initGroupCreateCommand() {
	groupCreateCommand.PersistentFlags().StringVarP(&name, "name", "n", "", "(required) name of the new group")
	viper.BindPFlag("name", groupCreateCommand.PersistentFlags().Lookup("name"))
	groupCmd.AddCommand(groupCreateCommand)
}
<|endoftext|>


<commit_before>package cmd

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

	"github.com/mobingilabs/mocli/pkg/cli"
	"github.com/mobingilabs/mocli/pkg/util"
	"github.com/spf13/cobra"
)

var loginCmd = &cobra.Command{
	Use:   "login",
	Short: "",
	Long:  `Placeholder for the documentation.`,
	Run:   login,
}

type authPayload struct {
	ClientId     string `json:"client_id,omitempty"`
	ClientSecret string `json:"client_secret,omitempty"`
	GrantType    string `json:"grant_type,omitempty"`
	Username     string `json:"username,omitempty"`
	Password     string `json:"password,omitempty"`
}

func init() {
	rootCmd.AddCommand(loginCmd)
	loginCmd.Flags().StringP("client-id", "i", "", "client id")
	loginCmd.Flags().StringP("client-secret", "s", "", "client secret")
	loginCmd.Flags().StringP("grant-type", "g", "client_credentials", "grant type (valid values: 'client_credentials', 'password')")
}

func login(cmd *cobra.Command, args []string) {
	if util.GetCliStringFlag(cmd, "client-id") == "" {
		log.Println("Client id not provided. See `help login` for more information.")
		os.Exit(1)
	}

	if util.GetCliStringFlag(cmd, "client-secret") == "" {
		log.Println("Client secret not provided. See `help login` for more information.")
		os.Exit(1)
	}

	var m map[string]interface{}
	var user, pass string
	var p *authPayload
	c := cli.New()

	if util.GetCliStringFlag(cmd, "grant-type") == "client_credentials" {
		p = &authPayload{
			ClientId:     util.GetCliStringFlag(cmd, "client-id"),
			ClientSecret: util.GetCliStringFlag(cmd, "client-secret"),
			GrantType:    util.GetCliStringFlag(cmd, "grant-type"),
		}
	}

	if util.GetCliStringFlag(cmd, "grant-type") == "password" {
		user, pass = util.GetUserPassword()
		fmt.Println("\n")
		p = &authPayload{
			ClientId:     util.GetCliStringFlag(cmd, "client-id"),
			ClientSecret: util.GetCliStringFlag(cmd, "client-secret"),
			GrantType:    util.GetCliStringFlag(cmd, "grant-type"),
			Username:     user,
			Password:     pass,
		}
	}

	// should not be nil when `grant_type` is valid
	if p == nil {
		util.PrintErrorAndExit("Invalid argument(s). See `help` for more information.", 1)
	}

	resp, body, errs := c.PostJSON(c.RootUrl+"/access_token", p)
	if errs != nil {
		log.Println("Error(s):", errs)
		os.Exit(1)
	}

	err := json.Unmarshal(body, &m)
	if err != nil {
		util.PrintErrorAndExit(err.Error(), 1)
	}

	serr := util.BuildRequestError(resp, m)
	if serr != "" {
		util.PrintErrorAndExit(serr, 1)
	}

	token, found := m["access_token"]
	if !found {
		util.PrintErrorAndExit("Internal error.", 1)
	}

	// always overwrite file
	util.SaveToken(fmt.Sprintf("%s", token))
	log.Println("Login successful.")
}
<commit_msg>Update login help.<commit_after>package cmd

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

	"github.com/mobingilabs/mocli/pkg/cli"
	"github.com/mobingilabs/mocli/pkg/util"
	"github.com/spf13/cobra"
)

var loginCmd = &cobra.Command{
	Use:   "login",
	Short: "Login to Mobingi API.",
	Long:  `login to Mobingi API.`,
	Run:   login,
}

type authPayload struct {
	ClientId     string `json:"client_id,omitempty"`
	ClientSecret string `json:"client_secret,omitempty"`
	GrantType    string `json:"grant_type,omitempty"`
	Username     string `json:"username,omitempty"`
	Password     string `json:"password,omitempty"`
}

func init() {
	rootCmd.AddCommand(loginCmd)
	loginCmd.Flags().StringP("client-id", "i", "", "client id")
	loginCmd.Flags().StringP("client-secret", "s", "", "client secret")
	loginCmd.Flags().StringP("grant-type", "g", "client_credentials", "grant type (valid values: 'client_credentials', 'password')")
}

func login(cmd *cobra.Command, args []string) {
	if util.GetCliStringFlag(cmd, "client-id") == "" {
		log.Println("Client id not provided. See `help login` for more information.")
		os.Exit(1)
	}

	if util.GetCliStringFlag(cmd, "client-secret") == "" {
		log.Println("Client secret not provided. See `help login` for more information.")
		os.Exit(1)
	}

	var m map[string]interface{}
	var user, pass string
	var p *authPayload
	c := cli.New()

	if util.GetCliStringFlag(cmd, "grant-type") == "client_credentials" {
		p = &authPayload{
			ClientId:     util.GetCliStringFlag(cmd, "client-id"),
			ClientSecret: util.GetCliStringFlag(cmd, "client-secret"),
			GrantType:    util.GetCliStringFlag(cmd, "grant-type"),
		}
	}

	if util.GetCliStringFlag(cmd, "grant-type") == "password" {
		user, pass = util.GetUserPassword()
		fmt.Println("\n")
		p = &authPayload{
			ClientId:     util.GetCliStringFlag(cmd, "client-id"),
			ClientSecret: util.GetCliStringFlag(cmd, "client-secret"),
			GrantType:    util.GetCliStringFlag(cmd, "grant-type"),
			Username:     user,
			Password:     pass,
		}
	}

	// should not be nil when `grant_type` is valid
	if p == nil {
		util.PrintErrorAndExit("Invalid argument(s). See `help` for more information.", 1)
	}

	resp, body, errs := c.PostJSON(c.RootUrl+"/access_token", p)
	if errs != nil {
		log.Println("Error(s):", errs)
		os.Exit(1)
	}

	err := json.Unmarshal(body, &m)
	if err != nil {
		util.PrintErrorAndExit(err.Error(), 1)
	}

	serr := util.BuildRequestError(resp, m)
	if serr != "" {
		util.PrintErrorAndExit(serr, 1)
	}

	token, found := m["access_token"]
	if !found {
		util.PrintErrorAndExit("Internal error.", 1)
	}

	// always overwrite file
	util.SaveToken(fmt.Sprintf("%s", token))
	log.Println("Login successful.")
}
<|endoftext|>


<commit_before>package rc

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
	"os"
	"strings"

	"github.com/ncw/rclone/cmd"
	"github.com/ncw/rclone/fs"
	"github.com/ncw/rclone/fs/fshttp"
	"github.com/ncw/rclone/fs/rc"
	"github.com/pkg/errors"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
)

var (
	noOutput = false
	url      = "http://localhost:5572/"
)

func init() {
	cmd.Root.AddCommand(commandDefintion)
	commandDefintion.Flags().BoolVarP(&noOutput, "no-output", "", noOutput, "If set don't output the JSON result.")
	commandDefintion.Flags().StringVarP(&url, "url", "", url, "URL to connect to rclone remote control.")
}

var commandDefintion = &cobra.Command{
	Use:   "rc commands parameter",
	Short: `Run a command against a running rclone.`,
	Long: `
This runs a command against a running rclone.  By default it will use
that specified in the --rc-addr command.

Arguments should be passed in as parameter=value.

The result will be returned as a JSON object by default.

Use "rclone rc list" to see a list of all possible commands.`,
	Run: func(command *cobra.Command, args []string) {
		cmd.CheckArgs(0, 1E9, command, args)
		cmd.Run(false, false, command, func() error {
			if len(args) == 0 {
				return list()
			}
			return run(args)
		})
	},
}

// do a call from (path, in) to (out, err).
//
// if err is set, out may be a valid error return or it may be nil
func doCall(path string, in rc.Params) (out rc.Params, err error) {
	// Do HTTP request
	client := fshttp.NewClient(fs.Config)
	url := url
	// set the user use --rc-addr as well as --url
	if rcAddrFlag := pflag.Lookup("rc-addr"); rcAddrFlag != nil && rcAddrFlag.Changed {
		url = rcAddrFlag.Value.String()
		if strings.HasPrefix(url, ":") {
			url = "localhost" + url
		}
		url = "http://" + url + "/"
	}
	if !strings.HasSuffix(url, "/") {
		url += "/"
	}
	url += path
	data, err := json.Marshal(in)
	if err != nil {
		return nil, errors.Wrap(err, "failed to encode JSON")
	}
	resp, err := client.Post(url, "application/json", bytes.NewBuffer(data))
	if err != nil {
		return nil, errors.Wrap(err, "connection failed")
	}
	defer fs.CheckClose(resp.Body, &err)

	// Parse output
	out = make(rc.Params)
	err = json.NewDecoder(resp.Body).Decode(&out)
	if err != nil {
		return nil, errors.Wrap(err, "failed to decode JSON")
	}

	// Check we got 200 OK
	if resp.StatusCode != http.StatusOK {
		err = errors.Errorf("operation %q failed: %v", path, out["error"])
	}

	return out, err
}

// Run the remote control command passed in
func run(args []string) (err error) {
	path := strings.Trim(args[0], "/")

	// parse input
	in := make(rc.Params)
	for _, param := range args[1:] {
		equals := strings.IndexRune(param, '=')
		if equals < 0 {
			return errors.Errorf("No '=' found in parameter %q", param)
		}
		key, value := param[:equals], param[equals+1:]
		in[key] = value
	}

	// Do the call
	out, callErr := doCall(path, in)

	// Write the JSON blob to stdout if required
	if out != nil && !noOutput {
		err := rc.WriteJSON(os.Stdout, out)
		if err != nil {
			return errors.Wrap(err, "failed to output JSON")
		}
	}

	return callErr
}

// List the available commands to stdout
func list() error {
	list, err := doCall("rc/list", nil)
	if err != nil {
		return errors.Wrap(err, "failed to list")
	}
	commands, ok := list["commands"].([]interface{})
	if !ok {
		return errors.New("bad JSON")
	}
	for _, command := range commands {
		info, ok := command.(map[string]interface{})
		if !ok {
			return errors.New("bad JSON")
		}
		fmt.Printf("### %s: %s\n\n", info["Path"], info["Title"])
		fmt.Printf("%s\n\n", info["Help"])
	}
	return nil
}
<commit_msg>rc: return error from remote on failure<commit_after>package rc

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"strings"

	"github.com/ncw/rclone/cmd"
	"github.com/ncw/rclone/fs"
	"github.com/ncw/rclone/fs/fshttp"
	"github.com/ncw/rclone/fs/rc"
	"github.com/pkg/errors"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
)

var (
	noOutput = false
	url      = "http://localhost:5572/"
)

func init() {
	cmd.Root.AddCommand(commandDefintion)
	commandDefintion.Flags().BoolVarP(&noOutput, "no-output", "", noOutput, "If set don't output the JSON result.")
	commandDefintion.Flags().StringVarP(&url, "url", "", url, "URL to connect to rclone remote control.")
}

var commandDefintion = &cobra.Command{
	Use:   "rc commands parameter",
	Short: `Run a command against a running rclone.`,
	Long: `
This runs a command against a running rclone.  By default it will use
that specified in the --rc-addr command.

Arguments should be passed in as parameter=value.

The result will be returned as a JSON object by default.

Use "rclone rc" to see a list of all possible commands.`,
	Run: func(command *cobra.Command, args []string) {
		cmd.CheckArgs(0, 1E9, command, args)
		cmd.Run(false, false, command, func() error {
			if len(args) == 0 {
				return list()
			}
			return run(args)
		})
	},
}

// do a call from (path, in) to (out, err).
//
// if err is set, out may be a valid error return or it may be nil
func doCall(path string, in rc.Params) (out rc.Params, err error) {
	// Do HTTP request
	client := fshttp.NewClient(fs.Config)
	url := url
	// set the user use --rc-addr as well as --url
	if rcAddrFlag := pflag.Lookup("rc-addr"); rcAddrFlag != nil && rcAddrFlag.Changed {
		url = rcAddrFlag.Value.String()
		if strings.HasPrefix(url, ":") {
			url = "localhost" + url
		}
		url = "http://" + url + "/"
	}
	if !strings.HasSuffix(url, "/") {
		url += "/"
	}
	url += path
	data, err := json.Marshal(in)
	if err != nil {
		return nil, errors.Wrap(err, "failed to encode JSON")
	}
	resp, err := client.Post(url, "application/json", bytes.NewBuffer(data))
	if err != nil {
		return nil, errors.Wrap(err, "connection failed")
	}
	defer fs.CheckClose(resp.Body, &err)

	if resp.StatusCode != http.StatusOK {
		var body []byte
		body, err = ioutil.ReadAll(resp.Body)
		var bodyString string
		if err == nil {
			bodyString = string(body)
		} else {
			bodyString = err.Error()
		}
		bodyString = strings.TrimSpace(bodyString)
		return nil, errors.Errorf("Failed to read rc response: %s: %s", resp.Status, bodyString)
	}

	// Parse output
	out = make(rc.Params)
	err = json.NewDecoder(resp.Body).Decode(&out)
	if err != nil {
		return nil, errors.Wrap(err, "failed to decode JSON")
	}

	// Check we got 200 OK
	if resp.StatusCode != http.StatusOK {
		err = errors.Errorf("operation %q failed: %v", path, out["error"])
	}

	return out, err
}

// Run the remote control command passed in
func run(args []string) (err error) {
	path := strings.Trim(args[0], "/")

	// parse input
	in := make(rc.Params)
	for _, param := range args[1:] {
		equals := strings.IndexRune(param, '=')
		if equals < 0 {
			return errors.Errorf("No '=' found in parameter %q", param)
		}
		key, value := param[:equals], param[equals+1:]
		in[key] = value
	}

	// Do the call
	out, callErr := doCall(path, in)

	// Write the JSON blob to stdout if required
	if out != nil && !noOutput {
		err := rc.WriteJSON(os.Stdout, out)
		if err != nil {
			return errors.Wrap(err, "failed to output JSON")
		}
	}

	return callErr
}

// List the available commands to stdout
func list() error {
	list, err := doCall("rc/list", nil)
	if err != nil {
		return errors.Wrap(err, "failed to list")
	}
	commands, ok := list["commands"].([]interface{})
	if !ok {
		return errors.New("bad JSON")
	}
	for _, command := range commands {
		info, ok := command.(map[string]interface{})
		if !ok {
			return errors.New("bad JSON")
		}
		fmt.Printf("### %s: %s\n\n", info["Path"], info["Title"])
		fmt.Printf("%s\n\n", info["Help"])
	}
	return nil
}
<|endoftext|>