<commit_before>package sirius

import (
	"github.com/kayex/sirius/slack"
	"golang.org/x/net/context"
)

const EMOJI = "⚡" // The high voltage/lightning bolt emoji (:zap: in Slack)

type Service struct {
	loader  ExtensionLoader
	clients map[string]*CancelClient
	ctx     context.Context
}

type CancelClient struct {
	Client
	Cancel context.CancelFunc
	ctx    context.Context
}

func (c *Client) WithCancel(ctx context.Context, cancel context.CancelFunc) *CancelClient {
	return &CancelClient{
		Client: *c,
		Cancel: cancel,
		ctx:    ctx,
	}
}

func (c *CancelClient) Start() {
	c.Client.Start(c.ctx)
}

func NewService(l ExtensionLoader) *Service {
	return &Service{
		loader:  l,
		clients: make(map[string]*CancelClient),
	}
}

func (s *Service) Start(ctx context.Context, users []User) {
	s.ctx = ctx

	for _, u := range users {
		u := u
		cl := s.createClient(&u)
		s.clients[u.ID.String()] = cl

		go cl.Start()
	}

	select {
	case <-s.ctx.Done():
		break
	}
}

func (s *Service) AddUser(u *User) {
	cl := s.createClient(u)
	s.clients[u.ID.String()] = cl

	go cl.Start()

	<-cl.Ready
	s.notify(cl)
}

func (s *Service) DropUser(id slack.ID) bool {
	if cl, ok := s.clients[id.String()]; ok {
		cl.Cancel()

		return true
	}

	return false
}

func (s *Service) stopClient(id slack.ID) {
	if ex, ok := s.clients[id.String()]; ok {
		ex.Cancel()
	}
}

func (s *Service) createClient(u *User) *CancelClient {
	return NewClient(ClientConfig{
		user:   u,
		loader: s.loader,
	}).WithCancel(context.WithCancel(s.ctx))
}

func (s *Service) notify(cl *CancelClient) {
	conf := EMOJI + " " + slack.Italic("Configuration loaded successfully.")

	if len(cl.user.Configurations) == 0 {
		conf += slack.Quote("No extensions activated.")
	} else {
		for _, cfg := range cl.user.Configurations {
			conf += "\n" + slack.Quote(string(cfg.EID))
		}
	}

	cl.conn.Send(&Message{
		Text:    conf,
		Channel: cl.conn.SelfChan(),
	})
}
<commit_msg>Attach notify() method to client<commit_after>package sirius

import (
	"github.com/kayex/sirius/slack"
	"golang.org/x/net/context"
)

const EMOJI = "⚡" // The high voltage/lightning bolt emoji (:zap: in Slack)

type Service struct {
	loader  ExtensionLoader
	clients map[string]*CancelClient
	ctx     context.Context
}

type CancelClient struct {
	Client
	Cancel context.CancelFunc
	ctx    context.Context
}

func (c *Client) WithCancel(ctx context.Context, cancel context.CancelFunc) *CancelClient {
	return &CancelClient{
		Client: *c,
		Cancel: cancel,
		ctx:    ctx,
	}
}

func (c *CancelClient) Start() {
	c.Client.Start(c.ctx)
}

func NewService(l ExtensionLoader) *Service {
	return &Service{
		loader:  l,
		clients: make(map[string]*CancelClient),
	}
}

func (s *Service) Start(ctx context.Context, users []User) {
	s.ctx = ctx

	for _, u := range users {
		u := u
		cl := s.createClient(&u)
		s.clients[u.ID.String()] = cl

		go cl.Start()
	}

	select {
	case <-s.ctx.Done():
		break
	}
}

func (s *Service) AddUser(u *User) {
	cl := s.createClient(u)
	s.clients[u.ID.String()] = cl

	go cl.Start()

	<-cl.Ready
	cl.notify()
}

func (s *Service) DropUser(id slack.ID) bool {
	if cl, ok := s.clients[id.String()]; ok {
		cl.Cancel()

		return true
	}

	return false
}

func (s *Service) stopClient(id slack.ID) {
	if ex, ok := s.clients[id.String()]; ok {
		ex.Cancel()
	}
}

func (s *Service) createClient(u *User) *CancelClient {
	return NewClient(ClientConfig{
		user:   u,
		loader: s.loader,
	}).WithCancel(context.WithCancel(s.ctx))
}

func (c *Client) notify() {
	conf := EMOJI + " " + slack.Italic("Configuration loaded successfully.")

	if len(c.user.Configurations) == 0 {
		conf += slack.Quote("No extensions activated.")
	} else {
		for _, cfg := range c.user.Configurations {
			conf += "\n" + slack.Quote(string(cfg.EID))
		}
	}

	c.conn.Send(&Message{
		Text:    conf,
		Channel: c.conn.SelfChan(),
	})
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/docker/docker/pkg/reexec"
	"github.com/mrosset/util/file"
	"gopkg.in/urfave/cli.v2"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"syscall"
)

const (
	BIND_RO = syscall.MS_BIND | syscall.MS_RDONLY | syscall.MS_REC
	BIND_RW = syscall.MS_BIND | syscall.MS_REC
)

var (
	viabin          = filepath.Join(os.Getenv("GOPATH"), "bin/via")
	containCommands = []*cli.Command{
		&cli.Command{
			Name:   "enter",
			Usage:  "enter via build namespace",
			Action: contain,
		},
	}
)

func init() {
	reexec.Register("init", initialize)
	if reexec.Init() {
		os.Exit(0)
	}
	app.Commands = append(app.Commands, containCommands...)
}

func linksh(root string) error {
	var (
		source = filepath.Join(config.Prefix, "bin", "bash")
		bin    = filepath.Join(root, "bin")
		target = filepath.Join(bin, "sh")
	)
	if err := os.MkdirAll(bin, 0755); err != nil {
		return err
	}
	return os.Link(source, target)
}

func bindbin(root string) error {
	var (
		source = filepath.Join(config.Prefix, "bin")
		target = filepath.Join(root, "bin")
	)
	if err := os.MkdirAll(target, 0755); err != nil {
		return err
	}
	return syscall.Mount(
		source,
		target,
		"",
		BIND_RO,
		"",
	)
}

// instead of linking, bind sh to bash to avoid cross linking across
// devices
func bindsh(root string) error {
	var (
		source = filepath.Join(config.Prefix, "bin", "bash")
		bin    = filepath.Join(root, "bin")
		target = filepath.Join(bin, "sh")
	)
	if err := os.MkdirAll(bin, 0755); err != nil {
		return err
	}
	if err := file.Touch(target); err != nil {
		return err
	}
	return syscall.Mount(
		source,
		target,
		"",
		BIND_RO,
		"",
	)
}

func initialize() {
	root, err := ioutil.TempDir("", "via-build")
	if err != nil {
		elog.Fatal(err)
	}
	// set hostname
	if err := syscall.Sethostname([]byte("via-build")); err != nil {
		elog.Fatalf("could not set hostname: %s", err)
	}
	if err := os.MkdirAll(root, 0700); err != nil {
		elog.Fatal(err)
	}
	// setup all our mounts
	if err := mount(root); err != nil {
		elog.Fatal(err)
	}
	// bind
	if err := bindsh(root); err != nil {
		elog.Fatal(err)
	}
	// finally pivot our root
	if err := pivot(root); err != nil {
		elog.Fatal(err)
	}
	run()
}
func run() {
	var (
		path = "/bin/sh"
		args = []string{}
	)

	switch {
	case len(os.Args) >= 2 && os.Args[1] == "build":
		path = viabin
		args = append([]string{"via"}, os.Args[1:]...)
	case len(os.Args) >= 2 && os.Args[1] == "contain":
		path = "/bin/sh"
		args = []string{}
	default:
		elog.Fatalf("can not handle arguments %v", os.Args)
	}

	cmd := &exec.Cmd{
		Path:   path,
		Args:   args,
		Stdin:  os.Stdin,
		Stdout: os.Stdout,
		Stderr: os.Stderr,
		Env: []string{
			fmt.Sprintf("TERM=%s", os.Getenv("TERM")),
			fmt.Sprintf("HOME=%s", os.Getenv("HOME")),
			fmt.Sprintf("GOPATH=%s", os.Getenv("GOPATH")),
			fmt.Sprintf("PATH=/bin:%s/bin:/home/mrosset/gocode/bin", config.Prefix),
			"PS1=-[via-build]- # ",
		},
		SysProcAttr: &syscall.SysProcAttr{
			Cloneflags: syscall.CLONE_NEWUSER,
			UidMappings: []syscall.SysProcIDMap{
				{
					ContainerID: 1000,
					HostID:      os.Getuid(),
					Size:        1,
				},
			},
			GidMappings: []syscall.SysProcIDMap{
				{
					ContainerID: 1001,
					HostID:      os.Getgid(),
					Size:        1,
				},
			},
		},
	}
	if err := cmd.Run(); err != nil {
		elog.Fatal(err)
	}
}

func contain(ctx *cli.Context) error {
	var (
		args = []string{}
	)
	if len(os.Args) > 1 && os.Args[1] == "build" {
		args = []string{"init", "build", "-real"}
	} else {
		args = []string{"init", "contain"}
	}
	// maybe there is a better way to chain down flags?
	for _, f := range ctx.FlagNames() {
		args = append(args, fmt.Sprintf("-%s", f))
	}
	args = append(args, ctx.Args().Slice()...)
	cmd := reexec.Command(args...)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	cmd.SysProcAttr = &syscall.SysProcAttr{
		Cloneflags: syscall.CLONE_NEWNS |
			syscall.CLONE_NEWUTS |
			syscall.CLONE_NEWIPC |
			syscall.CLONE_NEWPID |
			syscall.CLONE_NEWUSER,
		UidMappings: []syscall.SysProcIDMap{
			{
				ContainerID: 0,
				HostID:      os.Getuid(),
				Size:        1,
			},
		},
		GidMappings: []syscall.SysProcIDMap{
			{
				ContainerID: 0,
				HostID:      os.Getgid(),
				Size:        1,
			},
		},
	}
	if err := cmd.Run(); err != nil {
		return err
	}
	return nil
}

type FileSystem struct {
	Source string
	Type   string
	Target string
	Flags  int
	Data   string
	MakeFn func(string) error
}

func (fs FileSystem) Mount(root string) error {
	target := filepath.Join(root, fs.Target)
	if err := os.MkdirAll(target, 0755); err != nil {
		return err
	}
	return syscall.Mount(
		fs.Source,
		target,
		fs.Type,
		uintptr(fs.Flags),
		fs.Data,
	)
}

func mkdir(path string) error {
	return os.MkdirAll(path, 0755)
}

func busybox(root string) error {
	bin := filepath.Join(root, "bin")
	if err := os.MkdirAll(bin, 0755); err != nil {
		return err
	}
	bpath := "/bin/busybox"
	cmd := exec.Cmd{
		Path:   bpath,
		Args:   []string{"busybox", "--install", "-s", bin},
		Stderr: os.Stderr,
		Stdout: os.Stdout,
	}
	if err := cmd.Run(); err != nil {
		return err
	}
	out, err := os.OpenFile(filepath.Join(bin, "busybox"), os.O_RDWR|os.O_CREATE, 0755)
	if err != nil {
		return err
	}
	defer out.Close()
	return file.Copy(out, bpath)
}

func bind(source, root string) error {
	target := filepath.Join(root, source)
	stat, err := os.Stat(source)
	if err != nil {
		return err
	}
	if stat.IsDir() {
		os.MkdirAll(target, 0755)
	} else {
		dir := filepath.Dir(target)
		os.MkdirAll(dir, 0755)
		if err := file.Touch(target); err != nil {
			return err
		}
	}
	return syscall.Mount(
		source,
		target,
		"",
		BIND_RO,
		"",
	)
}

func mount(root string) error {
	// our binds
	binds := []string{
		"/dev",
		"/etc/resolv.conf",
		"/etc/ssl",
		"/etc/passwd",
		os.ExpandEnv("$HOME/.ccache"),
		config.Cache.String(),
		config.Plans,
		config.Repo,
		config.Prefix,
		viabin,
	}
	// our filesystems
	fs := []FileSystem{
		{
			Source: "proc",
			Target: "/proc",
			Type:   "proc",
		},
		{
			Source: "tmpfs",
			Target: "/tmp",
			Type:   "tmpfs",
		},
	}
	// mount our binds
	for _, source := range binds {
		if err := bind(source, root); err != nil {
			elog.Printf("binding %s to %s", source, filepath.Join(root, source))
			return err
		}
	}
	// mount our filesystems
	for _, m := range fs {
		if err := m.Mount(root); err != nil {
			elog.Printf("mounting %s to %s", m.Source, filepath.Join(root, m.Source))
			return err
		}
	}
	return nil
}

func pivot(newroot string) error {
	oldroot := filepath.Join(newroot, "/.root")

	// bind mount newroot to itself - this is a slight hack
	// needed to work around a pivot_root requirement
	if err := syscall.Mount(
		newroot,
		newroot,
		"",
		BIND_RO,
		"",
	); err != nil {
		return err
	}

	// create oldroot directory
	if err := os.MkdirAll(oldroot, 0700); err != nil {
		return err
	}

	// call pivot_root
	if err := syscall.PivotRoot(newroot, oldroot); err != nil {
		return err
	}

	// ensure current working directory is set to new root
	if err := os.Chdir("/"); err != nil {
		return err
	}

	// umount oldroot, which now lives at /.pivot_root
	oldroot = "/.root"
	if err := syscall.Unmount(
		oldroot,
		syscall.MNT_DETACH,
	); err != nil {
		return err
	}

	return os.RemoveAll(oldroot)
}
<commit_msg>/bin is populated with busybox<commit_after>package main

import (
	"fmt"
	"github.com/docker/docker/pkg/reexec"
	"github.com/mrosset/util/file"
	"gopkg.in/urfave/cli.v2"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"syscall"
)

const (
	BIND_RO = syscall.MS_BIND | syscall.MS_RDONLY | syscall.MS_REC
	BIND_RW = syscall.MS_BIND | syscall.MS_REC
)

var (
	viabin          = filepath.Join(os.Getenv("GOPATH"), "bin/via")
	containCommands = []*cli.Command{
		&cli.Command{
			Name:   "enter",
			Usage:  "enter build namespace",
			Action: contain,
		},
	}
)

func init() {
	reexec.Register("init", initialize)
	if reexec.Init() {
		os.Exit(0)
	}
	app.Commands = append(app.Commands, containCommands...)
}

func linksh(root string) error {
	var (
		source = filepath.Join(config.Prefix, "bin", "bash")
		bin    = filepath.Join(root, "bin")
		target = filepath.Join(bin, "sh")
	)
	if err := os.MkdirAll(bin, 0755); err != nil {
		return err
	}
	return os.Link(source, target)
}

func bindbin(root string) error {
	var (
		source = filepath.Join(config.Prefix, "bin")
		target = filepath.Join(root, "bin")
	)
	if err := os.MkdirAll(target, 0755); err != nil {
		return err
	}
	return syscall.Mount(
		source,
		target,
		"",
		BIND_RO,
		"",
	)
}

// instead of linking, bind sh to bash to avoid cross linking across
// devices
func bindsh(root string) error {
	var (
		source = filepath.Join(config.Prefix, "bin", "bash")
		bin    = filepath.Join(root, "bin")
		target = filepath.Join(bin, "sh")
	)
	if err := os.MkdirAll(bin, 0755); err != nil {
		return err
	}
	if err := file.Touch(target); err != nil {
		return err
	}
	return syscall.Mount(
		source,
		target,
		"",
		BIND_RO,
		"",
	)
}

func initialize() {
	root, err := ioutil.TempDir("", "via-build")
	if err != nil {
		elog.Fatal(err)
	}
	// set hostname
	if err := syscall.Sethostname([]byte("via-build")); err != nil {
		elog.Fatalf("could not set hostname: %s", err)
	}
	if err := os.MkdirAll(root, 0700); err != nil {
		elog.Fatal(err)
	}
	// setup all our mounts
	if err := mount(root); err != nil {
		elog.Fatal(err)
	}
	if err := busybox(root); err != nil {
		elog.Fatal(err)
	}
	// bind sh
	// if err := bindsh(root); err != nil {
	//	elog.Fatal(err)
	// }
	// finally pivot our root
	if err := pivot(root); err != nil {
		elog.Fatal(err)
	}
	run()
}
func run() {
	var (
		path = "/bin/sh"
		args = []string{}
	)

	switch {
	case len(os.Args) >= 2 && os.Args[1] == "build":
		path = viabin
		args = append([]string{"via"}, os.Args[1:]...)
	case len(os.Args) >= 2 && os.Args[1] == "contain":
		path = "/bin/sh"
		args = []string{}
	default:
		elog.Fatalf("can not handle arguments %v", os.Args)
	}

	cmd := &exec.Cmd{
		Path:   path,
		Args:   args,
		Stdin:  os.Stdin,
		Stdout: os.Stdout,
		Stderr: os.Stderr,
		Env: []string{
			fmt.Sprintf("TERM=%s", os.Getenv("TERM")),
			fmt.Sprintf("HOME=%s", os.Getenv("HOME")),
			fmt.Sprintf("GOPATH=%s", os.Getenv("GOPATH")),
			fmt.Sprintf("CFLAGS=%s", config.Env["CFLAGS"]),
			fmt.Sprintf("LDFLAGS=%s", config.Env["LDFLAGS"]),
			fmt.Sprintf("PATH=%s/bin:/bin:/home/mrosset/gocode/bin", config.Prefix),
			"PS1=-[via-build]- # ",
		},
		SysProcAttr: &syscall.SysProcAttr{
			Cloneflags: syscall.CLONE_NEWUSER,
			UidMappings: []syscall.SysProcIDMap{
				{
					ContainerID: 1000,
					HostID:      os.Getuid(),
					Size:        1,
				},
			},
			GidMappings: []syscall.SysProcIDMap{
				{
					ContainerID: 1001,
					HostID:      os.Getgid(),
					Size:        1,
				},
			},
		},
		Dir: os.Getenv("HOME"),
	}
	if err := cmd.Run(); err != nil {
		elog.Fatal(err)
	}
}

func contain(ctx *cli.Context) error {
	var (
		args = []string{}
	)
	if len(os.Args) > 1 && os.Args[1] == "build" {
		args = []string{"init", "build", "-real"}
	} else {
		args = []string{"init", "contain"}
	}
	// maybe there is a better way to chain down flags?
	for _, f := range ctx.FlagNames() {
		args = append(args, fmt.Sprintf("-%s", f))
	}
	args = append(args, ctx.Args().Slice()...)
	cmd := reexec.Command(args...)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	cmd.SysProcAttr = &syscall.SysProcAttr{
		Cloneflags: syscall.CLONE_NEWNS |
			syscall.CLONE_NEWUTS |
			syscall.CLONE_NEWIPC |
			syscall.CLONE_NEWPID |
			syscall.CLONE_NEWUSER,
		UidMappings: []syscall.SysProcIDMap{
			{
				ContainerID: 0,
				HostID:      os.Getuid(),
				Size:        1,
			},
		},
		GidMappings: []syscall.SysProcIDMap{
			{
				ContainerID: 0,
				HostID:      os.Getgid(),
				Size:        1,
			},
		},
	}
	if err := cmd.Run(); err != nil {
		return err
	}
	return nil
}

type FileSystem struct {
	Source string
	Type   string
	Target string
	Flags  int
	Data   string
	MakeFn func(string) error
}

func (fs FileSystem) Mount(root string) error {
	target := filepath.Join(root, fs.Target)
	if err := os.MkdirAll(target, 0755); err != nil {
		return err
	}
	return syscall.Mount(
		fs.Source,
		target,
		fs.Type,
		uintptr(fs.Flags),
		fs.Data,
	)
}

func mkdir(path string) error {
	return os.MkdirAll(path, 0755)
}

func busybox(root string) error {
	bin := filepath.Join(root, "bin")
	if err := os.MkdirAll(bin, 0755); err != nil {
		return err
	}
	bpath := filepath.Join(config.Prefix, "bin", "busybox")
	cmd := exec.Cmd{
		Path:   bpath,
		Args:   []string{"busybox", "--install", "-s", bin},
		Stderr: os.Stderr,
		Stdout: os.Stdout,
	}
	if err := cmd.Run(); err != nil {
		return err
	}
	out, err := os.OpenFile(filepath.Join(bin, "busybox"), os.O_RDWR|os.O_CREATE, 0755)
	if err != nil {
		return err
	}
	defer out.Close()
	return file.Copy(out, bpath)
}

func bind(source, root string) error {
	target := filepath.Join(root, source)
	stat, err := os.Stat(source)
	if err != nil {
		return err
	}
	if stat.IsDir() {
		os.MkdirAll(target, 0755)
	} else {
		dir := filepath.Dir(target)
		os.MkdirAll(dir, 0755)
		if err := file.Touch(target); err != nil {
			return err
		}
	}
	return syscall.Mount(
		source,
		target,
		"",
		BIND_RO,
		"",
	)
}

func mount(root string) error {
	// our binds
	binds := []string{
		"/dev",
		"/etc/resolv.conf",
		"/etc/ssl",
		"/etc/passwd",
		os.ExpandEnv("$HOME/.ccache"),
		config.Cache.String(),
		config.Plans,
		config.Repo,
		config.Prefix,
		viabin,
	}
	// our filesystems
	fs := []FileSystem{
		{
			Source: "proc",
			Target: "/proc",
			Type:   "proc",
		},
		{
			Source: "tmpfs",
			Target: "/tmp",
			Type:   "tmpfs",
		},
	}
	// mount our binds
	for _, source := range binds {
		if err := bind(source, root); err != nil {
			elog.Printf("binding %s to %s", source, filepath.Join(root, source))
			return err
		}
	}
	// mount our filesystems
	for _, m := range fs {
		if err := m.Mount(root); err != nil {
			elog.Printf("mounting %s to %s", m.Source, filepath.Join(root, m.Source))
			return err
		}
	}
	return nil
}

func pivot(newroot string) error {
	oldroot := filepath.Join(newroot, "/.root")

	// bind mount newroot to itself - this is a slight hack
	// needed to work around a pivot_root requirement
	if err := syscall.Mount(
		newroot,
		newroot,
		"",
		BIND_RO,
		"",
	); err != nil {
		return err
	}

	// create oldroot directory
	if err := os.MkdirAll(oldroot, 0700); err != nil {
		return err
	}

	// call pivot_root
	if err := syscall.PivotRoot(newroot, oldroot); err != nil {
		return err
	}

	// ensure current working directory is set to new root
	if err := os.Chdir("/"); err != nil {
		return err
	}

	// umount oldroot, which now lives at /.pivot_root
	oldroot = "/.root"
	if err := syscall.Unmount(
		oldroot,
		syscall.MNT_DETACH,
	); err != nil {
		return err
	}

	return os.RemoveAll(oldroot)
}
<|endoftext|>


<commit_before>package fakku

import (
	"encoding/json"
	"fmt"
	"strconv"
)

type Attribute struct {
	Attribute     string `json:"attribute"`
	AttributeLink string `json:"attribute_link"`
}
type Content struct {
	Name        string
	Url         string
	Description string
	Language    string
	Category    string
	Date        float64
	FileSize    float64
	Favorites   float64
	Comments    float64
	Pages       float64
	Poster      string
	PosterUrl   string
	Tags        []*Attribute `json:"content_tags"`
	Translators []*Attribute `json:"content_translators"`
	Series      []*Attribute `json:"content_series"`
	Artists     []*Attribute `json:"content_artists"`
	Images      struct {
		Cover  string
		Sample string
	}
}

func (c *Content) UnmarshalJSON(b []byte) error {
	var f interface{}
	json.Unmarshal(b, &f)
	m := f.(map[string]interface{})

	contents := m["content"]
	v := contents.(map[string]interface{})

	c.populateContent(v)

	return nil
}

func (c *Content) populateContent(v map[string]interface{}) {
	c.Name = v["content_name"].(string)
	c.Url = v["content_url"].(string)
	c.Description = v["content_description"].(string)
	c.Language = v["content_language"].(string)
	c.Category = v["content_category"].(string)
	c.Date = v["content_date"].(float64)
	c.FileSize = v["content_filesize"].(float64)
	c.Favorites = v["content_favorites"].(float64)
	c.Comments = v["content_comments"].(float64)
	c.Pages = v["content_pages"].(float64)
	c.Poster = v["content_poster"].(string)
	c.PosterUrl = v["content_poster_url"].(string)
	c.Tags = constructAttributeFields(v, "content_tags")
	c.Translators = constructAttributeFields(v, "content_translators")
	c.Series = constructAttributeFields(v, "content_series")
	c.Artists = constructAttributeFields(v, "content_artists")

	tmp := v["content_images"]
	z := tmp.(map[string]interface{})
	c.Images.Cover = z["cover"].(string)
	c.Images.Sample = z["sample"].(string)
}

func constructAttributeFields(c map[string]interface{}, field string) []*Attribute {
	tmp := c[field].([]interface{})
	size := len(tmp)
	attrs := make([]*Attribute, size)
	for i := 0; i < size; i++ {
		attrs[i] = NewAttribute(tmp[i].(map[string]interface{}))
	}
	return attrs
}

func PaginateString(s string, page uint) string {
	return fmt.Sprintf("%s/page/%d", s, page)
}

type ContentApiFunction struct {
	Category string
	Name     string
}

func (a ContentApiFunction) ConstructApiFunction() string {
	return fmt.Sprintf("%s/%s/%s", ApiHeader, a.Category, a.Name)
}

type ContentCommentApiFunction struct {
	ContentApiFunction
	TopComments bool
	Page        uint
}

func (a ContentCommentApiFunction) ConstructApiFunction() string {
	base := fmt.Sprintf("%s/comments", a.ContentApiFunction.ConstructApiFunction())
	if a.TopComments {
		return fmt.Sprintf("%s/top", base)
	} else {
		if a.Page == 0 {
			return base
		} else {
			return PaginateString(base, a.Page)
		}
	}
}

func GetContentInformation(category, name string) (*Content, error) {
	var c Content
	q := ContentApiFunction{Category: category, Name: name}
	err := ApiCall(q, &c)
	if err != nil {
		return nil, err
	} else {
		return &c, nil
	}
}
func getContentCommentsGeneric(url ApiFunction) (*Comments, error) {
	var c Comments
	if err := ApiCall(url, &c); err != nil {
		return nil, err
	} else {
		return &c, nil
	}
}
func GetContentComments(category, name string) (*Comments, error) {
	url := ContentCommentApiFunction{
		ContentApiFunction: ContentApiFunction{
			Category: category,
			Name:     name,
		},
	}
	return getContentCommentsGeneric(url)
}

func GetContentCommentsPage(category, name string, page uint) (*Comments, error) {
	url := ContentCommentApiFunction{
		ContentApiFunction: ContentApiFunction{
			Category: category,
			Name:     name,
		},
		Page: page,
	}
	return getContentCommentsGeneric(url)
}

func GetContentTopComments(category, name string) (*Comments, error) {
	url := ContentCommentApiFunction{
		ContentApiFunction: ContentApiFunction{
			Category: category,
			Name:     name,
		},
		TopComments: true,
	}
	return getContentCommentsGeneric(url)
}

type Comment struct {
	Id         float64 `json:"comment_id"`
	AttachedId string  `json:"comment_attached_id"`
	Poster     string  `json:"comment_poster"`
	PosterUrl  string  `json:"comment_poster_url"`
	Reputation float64 `json:"comment_reputation"`
	Text       string  `json:"comment_text"`
	Date       float64 `json:"comment_date"`
}

func NewAttribute(c map[string]interface{}) *Attribute {
	return &Attribute{
		Attribute:     c["attribute"].(string),
		AttributeLink: c["attribute_link"].(string),
	}
}

func (a *Attribute) String() string {
	return a.Attribute
}

type Comments struct {
	Comments   []*Comment `json:"comments"`
	PageNumber float64    `json:"page"`
	Total      float64    `json:"total"`
	Pages      float64    `json:"pages"`
}

type ReadOnlineContent struct {
	Content *Content `json:"content"`
	Pages   []*Page  `json:"pages"`
}

func (r *ReadOnlineContent) UnmarshalJSON(b []byte) error {
	var f interface{}
	if err := json.Unmarshal(b, &r.Content); err != nil {
		return err
	}
	json.Unmarshal(b, &f)
	m := f.(map[string]interface{})
	pages := m["pages"]
	v := pages.(map[string]interface{})
	r.Pages = make([]*Page, len(v))
	for i := 0; i < len(v); i++ {
		ind := strconv.Itoa(i + 1)
		r.Pages[i] = NewPage(ind, v[ind].(map[string]interface{}))
	}
	return nil
}

type Page struct {
	Id    string
	Thumb string
	Image string
}

func NewPage(id string, c map[string]interface{}) *Page {
	return &Page{
		Id:    id,
		Thumb: c["thumb"].(string),
		Image: c["image"].(string),
	}
}

type ContentReadOnlineApiFunction struct {
	ContentApiFunction
}

func (a ContentReadOnlineApiFunction) ConstructApiFunction() string {
	return fmt.Sprintf("%s/read", a.ContentApiFunction.ConstructApiFunction())
}

func GetContentReadOnline(category, name string) (*ReadOnlineContent, error) {
	var c ReadOnlineContent
	url := ContentReadOnlineApiFunction{
		ContentApiFunction: ContentApiFunction{
			Category: category,
			Name:     name,
		},
	}
	if err := ApiCall(url, &c); err != nil {
		return nil, err
	} else {
		return &c, nil
	}
}

func GetContentDownloads(category, name string) (*DownloadContent, error) {
	var c DownloadContent
	url := ContentDownloadsApiFunction{
		ContentApiFunction: ContentApiFunction{
			Category: category,
			Name:     name,
		},
	}
	if err := ApiCall(url, &c); err != nil {
		return nil, err
	} else {
		return &c, nil
	}
}

type ContentDownloadsApiFunction struct {
	ContentApiFunction
}

func (a ContentDownloadsApiFunction) ConstructApiFunction() string {
	return fmt.Sprintf("%s/download", a.ContentApiFunction.ConstructApiFunction())
}

type DownloadContent struct {
	Downloads []*Download `json:"downloads"`
	Total     uint        `json:"total"`
}
type Download struct {
	Type          string  `json:"download_type"`
	Url           string  `json:"download_url"`
	Info          string  `json:"download_info"`
	DownloadCount float64 `json:"download_count"`
	Time          float64 `json:"download_time"`
	Poster        string  `json:"download_poster"`
	PosterUrl     string  `json:"download_poster_url"`
}

type ContentRelatedApiFunction struct {
	ContentApiFunction
	Page uint
}

func (a ContentRelatedApiFunction) ConstructApiFunction() string {
	base := fmt.Sprintf("%s/related", a.ContentApiFunction.ConstructApiFunction())
	fmt.Println(base)
	if a.Page == 0 {
		return base
	} else {
		return PaginateString(base, a.Page)
	}
}

type RelatedContent struct {
	Related []*Content `json:"related"`
	Total   uint       `json:"total"`
	Pages   uint       `json:"pages"`
}

func GetRelatedContentAll(category, name string) (*RelatedContent, error) {
	return GetRelatedContent(category, name, 0)
}

func GetRelatedContent(category, name string, page uint) (*RelatedContent, error) {
	var c RelatedContent
	url := ContentRelatedApiFunction{
		ContentApiFunction: ContentApiFunction{
			Category: category,
			Name:     name,
		},
		Page: page,
	}
	if err := ApiCall(url, &c); err != nil {
		return nil, err
	} else {
		return &c, nil
	}
}

func (c *RelatedContent) UnmarshalJSON(b []byte) error {
	// slightly different
	var f interface{}
	json.Unmarshal(b, &f)
	m := f.(map[string]interface{})
	related := m["related"]
	v := related.([]interface{})
	c.Related = make([]*Content, len(v))
	for i := 0; i < len(v); i++ {
		var q Content
		q.populateContent(v[i].(map[string]interface{}))
		c.Related[i] = &q
	}
	c.Total = uint(m["total"].(float64))
	c.Pages = uint(m["pages"].(float64))
	return nil
}
<commit_msg>constructAttributeFields now performs error checking<commit_after>package fakku

import (
	"encoding/json"
	"fmt"
	"strconv"
)

type Attribute struct {
	Attribute     string `json:"attribute"`
	AttributeLink string `json:"attribute_link"`
}
type Content struct {
	Name        string
	Url         string
	Description string
	Language    string
	Category    string
	Date        float64
	FileSize    float64
	Favorites   float64
	Comments    float64
	Pages       float64
	Poster      string
	PosterUrl   string
	Tags        []*Attribute `json:"content_tags"`
	Translators []*Attribute `json:"content_translators"`
	Series      []*Attribute `json:"content_series"`
	Artists     []*Attribute `json:"content_artists"`
	Images      struct {
		Cover  string
		Sample string
	}
}

func (c *Content) UnmarshalJSON(b []byte) error {
	var f interface{}
	json.Unmarshal(b, &f)
	m := f.(map[string]interface{})

	contents := m["content"]
	v := contents.(map[string]interface{})

	c.populateContent(v)

	return nil
}

func (c *Content) populateContent(v map[string]interface{}) {
	c.Name = v["content_name"].(string)
	c.Url = v["content_url"].(string)
	c.Description = v["content_description"].(string)
	c.Language = v["content_language"].(string)
	c.Category = v["content_category"].(string)
	c.Date = v["content_date"].(float64)
	c.FileSize = v["content_filesize"].(float64)
	c.Favorites = v["content_favorites"].(float64)
	c.Comments = v["content_comments"].(float64)
	c.Pages = v["content_pages"].(float64)
	c.Poster = v["content_poster"].(string)
	c.PosterUrl = v["content_poster_url"].(string)
	c.Tags = constructAttributeFields(v, "content_tags")
	c.Translators = constructAttributeFields(v, "content_translators")
	c.Series = constructAttributeFields(v, "content_series")
	c.Artists = constructAttributeFields(v, "content_artists")

	tmp := v["content_images"]
	z := tmp.(map[string]interface{})
	c.Images.Cover = z["cover"].(string)
	c.Images.Sample = z["sample"].(string)
}

func constructAttributeFields(c map[string]interface{}, field string) []*Attribute {
	try, ok := c[field]
	if !ok {
		return nil
	}
	tmp := try.([]interface{})
	size := len(tmp)
	attrs := make([]*Attribute, size)
	for i := 0; i < size; i++ {
		attrs[i] = NewAttribute(tmp[i].(map[string]interface{}))
	}
	return attrs
}

func PaginateString(s string, page uint) string {
	return fmt.Sprintf("%s/page/%d", s, page)
}

type ContentApiFunction struct {
	Category string
	Name     string
}

func (a ContentApiFunction) ConstructApiFunction() string {
	return fmt.Sprintf("%s/%s/%s", ApiHeader, a.Category, a.Name)
}

type ContentCommentApiFunction struct {
	ContentApiFunction
	TopComments bool
	Page        uint
}

func (a ContentCommentApiFunction) ConstructApiFunction() string {
	base := fmt.Sprintf("%s/comments", a.ContentApiFunction.ConstructApiFunction())
	if a.TopComments {
		return fmt.Sprintf("%s/top", base)
	} else {
		if a.Page == 0 {
			return base
		} else {
			return PaginateString(base, a.Page)
		}
	}
}

func GetContentInformation(category, name string) (*Content, error) {
	var c Content
	q := ContentApiFunction{Category: category, Name: name}
	err := ApiCall(q, &c)
	if err != nil {
		return nil, err
	} else {
		return &c, nil
	}
}
func getContentCommentsGeneric(url ApiFunction) (*Comments, error) {
	var c Comments
	if err := ApiCall(url, &c); err != nil {
		return nil, err
	} else {
		return &c, nil
	}
}
func GetContentComments(category, name string) (*Comments, error) {
	url := ContentCommentApiFunction{
		ContentApiFunction: ContentApiFunction{
			Category: category,
			Name:     name,
		},
	}
	return getContentCommentsGeneric(url)
}

func GetContentCommentsPage(category, name string, page uint) (*Comments, error) {
	url := ContentCommentApiFunction{
		ContentApiFunction: ContentApiFunction{
			Category: category,
			Name:     name,
		},
		Page: page,
	}
	return getContentCommentsGeneric(url)
}

func GetContentTopComments(category, name string) (*Comments, error) {
	url := ContentCommentApiFunction{
		ContentApiFunction: ContentApiFunction{
			Category: category,
			Name:     name,
		},
		TopComments: true,
	}
	return getContentCommentsGeneric(url)
}

type Comment struct {
	Id         float64 `json:"comment_id"`
	AttachedId string  `json:"comment_attached_id"`
	Poster     string  `json:"comment_poster"`
	PosterUrl  string  `json:"comment_poster_url"`
	Reputation float64 `json:"comment_reputation"`
	Text       string  `json:"comment_text"`
	Date       float64 `json:"comment_date"`
}

func NewAttribute(c map[string]interface{}) *Attribute {
	return &Attribute{
		Attribute:     c["attribute"].(string),
		AttributeLink: c["attribute_link"].(string),
	}
}

func (a *Attribute) String() string {
	return a.Attribute
}

type Comments struct {
	Comments   []*Comment `json:"comments"`
	PageNumber float64    `json:"page"`
	Total      float64    `json:"total"`
	Pages      float64    `json:"pages"`
}

type ReadOnlineContent struct {
	Content *Content `json:"content"`
	Pages   []*Page  `json:"pages"`
}

func (r *ReadOnlineContent) UnmarshalJSON(b []byte) error {
	var f interface{}
	if err := json.Unmarshal(b, &r.Content); err != nil {
		return err
	}
	json.Unmarshal(b, &f)
	m := f.(map[string]interface{})
	pages := m["pages"]
	v := pages.(map[string]interface{})
	r.Pages = make([]*Page, len(v))
	for i := 0; i < len(v); i++ {
		ind := strconv.Itoa(i + 1)
		r.Pages[i] = NewPage(ind, v[ind].(map[string]interface{}))
	}
	return nil
}

type Page struct {
	Id    string
	Thumb string
	Image string
}

func NewPage(id string, c map[string]interface{}) *Page {
	return &Page{
		Id:    id,
		Thumb: c["thumb"].(string),
		Image: c["image"].(string),
	}
}

type ContentReadOnlineApiFunction struct {
	ContentApiFunction
}

func (a ContentReadOnlineApiFunction) ConstructApiFunction() string {
	return fmt.Sprintf("%s/read", a.ContentApiFunction.ConstructApiFunction())
}

func GetContentReadOnline(category, name string) (*ReadOnlineContent, error) {
	var c ReadOnlineContent
	url := ContentReadOnlineApiFunction{
		ContentApiFunction: ContentApiFunction{
			Category: category,
			Name:     name,
		},
	}
	if err := ApiCall(url, &c); err != nil {
		return nil, err
	} else {
		return &c, nil
	}
}

func GetContentDownloads(category, name string) (*DownloadContent, error) {
	var c DownloadContent
	url := ContentDownloadsApiFunction{
		ContentApiFunction: ContentApiFunction{
			Category: category,
			Name:     name,
		},
	}
	if err := ApiCall(url, &c); err != nil {
		return nil, err
	} else {
		return &c, nil
	}
}

type ContentDownloadsApiFunction struct {
	ContentApiFunction
}

func (a ContentDownloadsApiFunction) ConstructApiFunction() string {
	return fmt.Sprintf("%s/download", a.ContentApiFunction.ConstructApiFunction())
}

type DownloadContent struct {
	Downloads []*Download `json:"downloads"`
	Total     uint        `json:"total"`
}
type Download struct {
	Type          string  `json:"download_type"`
	Url           string  `json:"download_url"`
	Info          string  `json:"download_info"`
	DownloadCount float64 `json:"download_count"`
	Time          float64 `json:"download_time"`
	Poster        string  `json:"download_poster"`
	PosterUrl     string  `json:"download_poster_url"`
}

type ContentRelatedApiFunction struct {
	ContentApiFunction
	Page uint
}

func (a ContentRelatedApiFunction) ConstructApiFunction() string {
	base := fmt.Sprintf("%s/related", a.ContentApiFunction.ConstructApiFunction())
	if a.Page == 0 {
		return base
	} else {
		return PaginateString(base, a.Page)
	}
}

type RelatedContent struct {
	Related []*Content `json:"related"`
	Total   uint       `json:"total"`
	Pages   uint       `json:"pages"`
}

func GetRelatedContentAll(category, name string) (*RelatedContent, error) {
	return GetRelatedContent(category, name, 0)
}

func GetRelatedContent(category, name string, page uint) (*RelatedContent, error) {
	var c RelatedContent
	url := ContentRelatedApiFunction{
		ContentApiFunction: ContentApiFunction{
			Category: category,
			Name:     name,
		},
		Page: page,
	}
	if err := ApiCall(url, &c); err != nil {
		return nil, err
	} else {
		return &c, nil
	}
}

func (c *RelatedContent) UnmarshalJSON(b []byte) error {
	// slightly different
	var f interface{}
	json.Unmarshal(b, &f)
	m := f.(map[string]interface{})
	related := m["related"]
	v := related.([]interface{})
	c.Related = make([]*Content, len(v))
	for i := 0; i < len(v); i++ {
		var q Content
		q.populateContent(v[i].(map[string]interface{}))
		c.Related[i] = &q
	}
	c.Total = uint(m["total"].(float64))
	c.Pages = uint(m["pages"].(float64))
	return nil
}
<|endoftext|>


<commit_before>package chuper

import (
	"net/url"

	"github.com/PuerkitoBio/fetchbot"
)

type Context struct {
	*fetchbot.Context
	C Cache
}

func (c *Context) Cache() Cache {
	return c.C
}

func (c *Context) Queue() *fetchbot.Queue {
	return c.Q
}

func (c *Context) URL() *url.URL {
	return c.Cmd.URL()
}

func (c *Context) SourceURL() *url.URL {
	switch cmd := c.Cmd.(type) {
	case Cmd:
		return cmd.SourceURL()
	case CmdBasicAuth:
		return cmd.SourceURL()
	default:
		return nil
	}
}
<commit_msg>Cmd is a pointer.<commit_after>package chuper

import (
	"net/url"

	"github.com/PuerkitoBio/fetchbot"
)

type Context struct {
	*fetchbot.Context
	C Cache
}

func (c *Context) Cache() Cache {
	return c.C
}

func (c *Context) Queue() *fetchbot.Queue {
	return c.Q
}

func (c *Context) URL() *url.URL {
	return c.Cmd.URL()
}

func (c *Context) SourceURL() *url.URL {
	switch cmd := c.Cmd.(type) {
	case *Cmd:
		return cmd.SourceURL()
	case *CmdBasicAuth:
		return cmd.SourceURL()
	default:
		return nil
	}
}
<|endoftext|>


<commit_before>package core

import "net/http"

// Context contains all the data needed during the serving flow.
// It contains the standard "http.ResponseWriter" and "*http.Request".
// You can pass data through handlers thanks to the Data field.
type Context struct {
	ResponseWriter http.ResponseWriter
	Request        *http.Request
	Data           map[string]interface{} // Generic field to pass arbitrary data through the stack.
	index          int                    // Keeps the actual handler index.
	written        bool                   // A flag to know if the response has been written.
}

// Next calls the next handler in the stack, but only if the response is not already written.
func (c *Context) Next() {
	if !c.written {
		c.index++
		handlers[c.index](c)
	}
}

// contextWriter is a binder that sets the c.written flag on first write.
type contextWriter struct {
	http.ResponseWriter
	context *Context
}

// Write sets the context's "writte" flag before writing the response.
func (w contextWriter) Write(p []byte) (int, error) {
	w.context.written = true
	return w.ResponseWriter.Write(p)
}
<commit_msg>Fix comment typo<commit_after>package core

import "net/http"

// Context contains all the data needed during the serving flow.
// It contains the standard "http.ResponseWriter" and "*http.Request".
// You can pass data through handlers thanks to the Data field.
type Context struct {
	ResponseWriter http.ResponseWriter
	Request        *http.Request
	Data           map[string]interface{} // Generic field to pass arbitrary data through the stack.
	index          int                    // Keeps the actual handler index.
	written        bool                   // A flag to know if the response has been written.
}

// Next calls the next handler in the stack, but only if the response is not already written.
func (c *Context) Next() {
	if !c.written {
		c.index++
		handlers[c.index](c)
	}
}

// contextWriter is a binder that sets the c.written flag on first write.
type contextWriter struct {
	http.ResponseWriter
	context *Context
}

// Write sets the context's "written" flag before writing the response.
func (w contextWriter) Write(p []byte) (int, error) {
	w.context.written = true
	return w.ResponseWriter.Write(p)
}
<|endoftext|>


<commit_before>// Copyright © 2017 Aqua Security Software Ltd. <info@aquasec.com>
//
// 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 (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"

	"github.com/aquasecurity/kube-bench/check"
	"github.com/golang/glog"
	"github.com/spf13/viper"
)

var (
	errmsgs string
)

func runChecks(nodetype check.NodeType) {
	var summary check.Summary

	def := loadConfig(nodetype)
	in, err := ioutil.ReadFile(def)
	if err != nil {
		exitWithError(fmt.Errorf("error opening %s controls file: %v", nodetype, err))
	}

	glog.V(1).Info(fmt.Sprintf("Using benchmark file: %s\n", def))

	// Get the set of exectuables and config files we care about on this type of node.
	typeConf := viper.Sub(string(nodetype))
	binmap, err := getBinaries(typeConf)

	// Checks that the executables we need for the node type are running.
	if err != nil {
		exitWithError(err)
	}

	confmap := getConfigFiles(typeConf)
	svcmap := getServiceFiles(typeConf)
	kubeconfmap := getKubeConfigFiles(typeConf)

	// Variable substitutions. Replace all occurrences of variables in controls files.
	s := string(in)
	s = makeSubstitutions(s, "bin", binmap)
	s = makeSubstitutions(s, "conf", confmap)
	s = makeSubstitutions(s, "svc", svcmap)
	s = makeSubstitutions(s, "kubeconfig", kubeconfmap)

	controls, err := check.NewControls(nodetype, []byte(s))
	if err != nil {
		exitWithError(fmt.Errorf("error setting up %s controls: %v", nodetype, err))
	}

	if groupList != "" && checkList == "" {
		ids := cleanIDs(groupList)
		summary = controls.RunGroup(ids...)
	} else if checkList != "" && groupList == "" {
		ids := cleanIDs(checkList)
		summary = controls.RunChecks(ids...)
	} else if checkList != "" && groupList != "" {
		exitWithError(fmt.Errorf("group option and check option can't be used together"))
	} else {
		summary = controls.RunGroup()
	}

	// if we successfully ran some tests and it's json format, ignore the warnings
	if (summary.Fail > 0 || summary.Warn > 0 || summary.Pass > 0 || summary.Info > 0) && jsonFmt {
		out, err := controls.JSON()
		if err != nil {
			exitWithError(fmt.Errorf("failed to output in JSON format: %v", err))
		}

		fmt.Println(string(out))
	} else {
		// if we want to store in PostgreSQL, convert to JSON and save it
		if (summary.Fail > 0 || summary.Warn > 0 || summary.Pass > 0 || summary.Info > 0) && pgSQL {
			out, err := controls.JSON()
			if err != nil {
				exitWithError(fmt.Errorf("failed to output in JSON format: %v", err))
			}

			savePgsql(string(out))
		} else {
			prettyPrint(controls, summary)
		}
	}
}

// colorPrint outputs the state in a specific colour, along with a message string
func colorPrint(state check.State, s string) {
	colors[state].Printf("[%s] ", state)
	fmt.Printf("%s", s)
}

// prettyPrint outputs the results to stdout in human-readable format
func prettyPrint(r *check.Controls, summary check.Summary) {
	// Print check results.
	if !noResults {
		colorPrint(check.INFO, fmt.Sprintf("%s %s\n", r.ID, r.Text))
		for _, g := range r.Groups {
			colorPrint(check.INFO, fmt.Sprintf("%s %s\n", g.ID, g.Text))
			for _, c := range g.Checks {
				colorPrint(c.State, fmt.Sprintf("%s %s\n", c.ID, c.Text))
			}
		}

		fmt.Println()
	}

	// Print remediations.
	if !noRemediations {
		if summary.Fail > 0 || summary.Warn > 0 {
			colors[check.WARN].Printf("== Remediations ==\n")
			for _, g := range r.Groups {
				for _, c := range g.Checks {
					if c.State == check.FAIL || c.State == check.WARN {
						fmt.Printf("%s %s\n", c.ID, c.Remediation)
					}
				}
			}
			fmt.Println()
		}
	}

	// Print summary setting output color to highest severity.
	if !noSummary {
		var res check.State
		if summary.Fail > 0 {
			res = check.FAIL
		} else if summary.Warn > 0 {
			res = check.WARN
		} else {
			res = check.PASS
		}

		colors[res].Printf("== Summary ==\n")
		fmt.Printf("%d checks PASS\n%d checks FAIL\n%d checks WARN\n%d checks INFO\n",
			summary.Pass, summary.Fail, summary.Warn, summary.Info,
		)
	}
}

// loadConfig finds the correct config dir based on the kubernetes version,
// merges any specific config.yaml file found with the main config
// and returns the benchmark file to use.
func loadConfig(nodetype check.NodeType) string {
	var file string
	var err error

	switch nodetype {
	case check.MASTER:
		file = masterFile
	case check.NODE:
		file = nodeFile
	case check.FEDERATED:
		file = federatedFile
	}

	runningVersion := ""
	if kubeVersion == "" {
		runningVersion, err = getKubeVersion()
		if err != nil {
			exitWithError(fmt.Errorf("Version check failed: %s\nAlternatively, you can specify the version with --version", err))
		}
	}
	path, err := getConfigFilePath(kubeVersion, runningVersion, file)
	if err != nil {
		exitWithError(fmt.Errorf("can't find %s controls file in %s: %v", nodetype, cfgDir, err))
	}

	// Merge kubernetes version specific config if any.
	viper.SetConfigFile(path + "/config.yaml")
	err = viper.MergeInConfig()
	if err != nil {
		if os.IsNotExist(err) {
			glog.V(2).Info(fmt.Sprintf("No version-specific config.yaml file in %s", path))
		} else {
			exitWithError(fmt.Errorf("couldn't read config file %s: %v", path+"/config.yaml", err))
		}
	} else {
		glog.V(1).Info(fmt.Sprintf("Using config file: %s\n", viper.ConfigFileUsed()))
	}
	return filepath.Join(path, file)
}

// isMaster verify if master components are running on the node.
func isMaster() bool {
	_ = loadConfig(check.MASTER)
	glog.V(2).Info("Checking if the current node is running master components")
	masterConf := viper.Sub(string(check.MASTER))
	if _, err := getBinaries(masterConf); err != nil {
		glog.V(2).Info(err)
		return false
	}
	return true
}
<commit_msg>Don't assume master if 0 master binaries specified<commit_after>// Copyright © 2017 Aqua Security Software Ltd. <info@aquasec.com>
//
// 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 (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"

	"github.com/aquasecurity/kube-bench/check"
	"github.com/golang/glog"
	"github.com/spf13/viper"
)

var (
	errmsgs string
)

func runChecks(nodetype check.NodeType) {
	var summary check.Summary

	def := loadConfig(nodetype)
	in, err := ioutil.ReadFile(def)
	if err != nil {
		exitWithError(fmt.Errorf("error opening %s controls file: %v", nodetype, err))
	}

	glog.V(1).Info(fmt.Sprintf("Using benchmark file: %s\n", def))

	// Get the set of exectuables and config files we care about on this type of node.
	typeConf := viper.Sub(string(nodetype))
	binmap, err := getBinaries(typeConf)

	// Checks that the executables we need for the node type are running.
	if err != nil {
		exitWithError(err)
	}

	confmap := getConfigFiles(typeConf)
	svcmap := getServiceFiles(typeConf)
	kubeconfmap := getKubeConfigFiles(typeConf)

	// Variable substitutions. Replace all occurrences of variables in controls files.
	s := string(in)
	s = makeSubstitutions(s, "bin", binmap)
	s = makeSubstitutions(s, "conf", confmap)
	s = makeSubstitutions(s, "svc", svcmap)
	s = makeSubstitutions(s, "kubeconfig", kubeconfmap)

	controls, err := check.NewControls(nodetype, []byte(s))
	if err != nil {
		exitWithError(fmt.Errorf("error setting up %s controls: %v", nodetype, err))
	}

	if groupList != "" && checkList == "" {
		ids := cleanIDs(groupList)
		summary = controls.RunGroup(ids...)
	} else if checkList != "" && groupList == "" {
		ids := cleanIDs(checkList)
		summary = controls.RunChecks(ids...)
	} else if checkList != "" && groupList != "" {
		exitWithError(fmt.Errorf("group option and check option can't be used together"))
	} else {
		summary = controls.RunGroup()
	}

	// if we successfully ran some tests and it's json format, ignore the warnings
	if (summary.Fail > 0 || summary.Warn > 0 || summary.Pass > 0 || summary.Info > 0) && jsonFmt {
		out, err := controls.JSON()
		if err != nil {
			exitWithError(fmt.Errorf("failed to output in JSON format: %v", err))
		}

		fmt.Println(string(out))
	} else {
		// if we want to store in PostgreSQL, convert to JSON and save it
		if (summary.Fail > 0 || summary.Warn > 0 || summary.Pass > 0 || summary.Info > 0) && pgSQL {
			out, err := controls.JSON()
			if err != nil {
				exitWithError(fmt.Errorf("failed to output in JSON format: %v", err))
			}

			savePgsql(string(out))
		} else {
			prettyPrint(controls, summary)
		}
	}
}

// colorPrint outputs the state in a specific colour, along with a message string
func colorPrint(state check.State, s string) {
	colors[state].Printf("[%s] ", state)
	fmt.Printf("%s", s)
}

// prettyPrint outputs the results to stdout in human-readable format
func prettyPrint(r *check.Controls, summary check.Summary) {
	// Print check results.
	if !noResults {
		colorPrint(check.INFO, fmt.Sprintf("%s %s\n", r.ID, r.Text))
		for _, g := range r.Groups {
			colorPrint(check.INFO, fmt.Sprintf("%s %s\n", g.ID, g.Text))
			for _, c := range g.Checks {
				colorPrint(c.State, fmt.Sprintf("%s %s\n", c.ID, c.Text))
			}
		}

		fmt.Println()
	}

	// Print remediations.
	if !noRemediations {
		if summary.Fail > 0 || summary.Warn > 0 {
			colors[check.WARN].Printf("== Remediations ==\n")
			for _, g := range r.Groups {
				for _, c := range g.Checks {
					if c.State == check.FAIL || c.State == check.WARN {
						fmt.Printf("%s %s\n", c.ID, c.Remediation)
					}
				}
			}
			fmt.Println()
		}
	}

	// Print summary setting output color to highest severity.
	if !noSummary {
		var res check.State
		if summary.Fail > 0 {
			res = check.FAIL
		} else if summary.Warn > 0 {
			res = check.WARN
		} else {
			res = check.PASS
		}

		colors[res].Printf("== Summary ==\n")
		fmt.Printf("%d checks PASS\n%d checks FAIL\n%d checks WARN\n%d checks INFO\n",
			summary.Pass, summary.Fail, summary.Warn, summary.Info,
		)
	}
}

// loadConfig finds the correct config dir based on the kubernetes version,
// merges any specific config.yaml file found with the main config
// and returns the benchmark file to use.
func loadConfig(nodetype check.NodeType) string {
	var file string
	var err error

	switch nodetype {
	case check.MASTER:
		file = masterFile
	case check.NODE:
		file = nodeFile
	case check.FEDERATED:
		file = federatedFile
	}

	runningVersion := ""
	if kubeVersion == "" {
		runningVersion, err = getKubeVersion()
		if err != nil {
			exitWithError(fmt.Errorf("Version check failed: %s\nAlternatively, you can specify the version with --version", err))
		}
	}
	path, err := getConfigFilePath(kubeVersion, runningVersion, file)
	if err != nil {
		exitWithError(fmt.Errorf("can't find %s controls file in %s: %v", nodetype, cfgDir, err))
	}

	// Merge kubernetes version specific config if any.
	viper.SetConfigFile(path + "/config.yaml")
	err = viper.MergeInConfig()
	if err != nil {
		if os.IsNotExist(err) {
			glog.V(2).Info(fmt.Sprintf("No version-specific config.yaml file in %s", path))
		} else {
			exitWithError(fmt.Errorf("couldn't read config file %s: %v", path+"/config.yaml", err))
		}
	} else {
		glog.V(1).Info(fmt.Sprintf("Using config file: %s\n", viper.ConfigFileUsed()))
	}
	return filepath.Join(path, file)
}

// isMaster verify if master components are running on the node.
func isMaster() bool {
	_ = loadConfig(check.MASTER)
	glog.V(2).Info("Checking if the current node is running master components")
	masterConf := viper.Sub(string(check.MASTER))
	components, err := getBinaries(masterConf)

	if err != nil {
		glog.V(2).Info(err)
		return false
	}
	if len(components) == 0 {
		glog.V(2).Info("No master binaries specified")
		return false
	}
	return true
}
<|endoftext|>


<commit_before>// Copyright © 2016 Daniel Ackermann <ackermann.d@gmail.com>
//
// 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 (
	"bytes"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"regexp"
	"strings"

	"github.com/ackermannd/clifmt"
	"github.com/spf13/cobra"
)

var branch string
var remoteOnly bool

// gitCoCmd represents the git-co command
var gitCoCmd = &cobra.Command{
	Use:   "git-co <service name> [<service name> <service name> ...]",
	Short: "Checkout specific branches for the given services",
	Long:  `Takes information from Buildpaths of the given services and checks out the given branch. If local changes are represent, they'll be stashed`,
	RunE: func(cmd *cobra.Command, args []string) error {
		if composeFile == "" {
			return errors.New("No docker-compose file set, either set CFT_COMPOSE environment variable or supply via flag")
		}
		if branch == "" {
			return errors.New("No branch name given")
		}

		cf, err := os.Open(composeFile)
		if err != nil {
			return err
		}
		defer cf.Close()

		if len(args) == 0 {
			if force == false {
				if !confirm("No service name given, this will iterate through all services and tries to check out the remote branch if it exists. Continue? [y/n]") {
					os.Exit(0)
				}
			}
			tmpComposeFolder := strings.Split(composeFile, "/")
			cmd := exec.Command("docker-compose", "config", "--services")
			cmd.Dir = "/" + strings.Join(tmpComposeFolder[1:len(tmpComposeFolder)-1], "/")
			tmp, _ := cmd.Output()
			args = strings.Split(string(tmp), "\n")
			args = args[0 : len(args)-1]
		}

		cfd, _ := ioutil.ReadAll(cf)
		origData := string(cfd)
		clifmt.Settings.Intendation = " "
		for _, sv := range args {
			service := extractService(sv, origData)

			checkReg := regexp.MustCompile("build:(.*)")
			folder := strings.TrimSpace(checkReg.ReplaceAllString(checkReg.FindString(service), "$1"))

			var stderr bytes.Buffer

			fmt.Println("Stashing changes in " + folder)
			cmd := exec.Command("git", "stash")
			cmd.Dir = folder
			cmd.Stderr = &stderr
			_, err := cmd.Output()
			if err != nil {
				return errors.New(err.Error() + ": " + stderr.String())
			}

			stderr.Reset()
			clifmt.Println("Checking if remote origin exists")
			cmd = exec.Command("git", "remote", "show", "origin")
			cmd.Dir = folder
			cmd.Stderr = &stderr
			_, err = cmd.Output()
			if err != nil && err.Error() != "exit status 128" {
				return errors.New(err.Error() + ": " + stderr.String())
			}
			if err != nil && err.Error() == "exit status 128" {
				if remoteOnly {
					clifmt.Println("No remote origin available")
					continue
				}
				clifmt.Println("No remote origin available, creating local branch")
				cmd = exec.Command("git", "checkout", "-B", branch)
				var stdout bytes.Buffer
				stderr.Reset()
				cmd.Dir = folder
				cmd.Stderr = &stderr
				cmd.Stdout = &stdout

				err = cmd.Run()
				if err != nil {
					return errors.New(err.Error() + ": " + stderr.String())
				}
				if stdout.String() != "" {
					clifmt.Println(strings.Replace(stdout.String(), "\n", "\n    ", -1))
				}

				if stderr.String() != "" {
					clifmt.Println(strings.Replace(stderr.String(), "\n", "\n    ", -1))
				}
				continue
			} else {
				stderr.Reset()
				clifmt.Println("Fetching remote")
				cmd = exec.Command("git", "fetch", "--all")
				cmd.Dir = folder
				cmd.Stderr = &stderr
				_, err = cmd.Output()
				if err != nil {
					return errors.New(err.Error() + ": " + stderr.String())
				}
				stderr.Reset()
				clifmt.Println("Checking if branch exists in remote")
				cmd = exec.Command("git", "ls-remote", "--heads", "--exit-code", "origin", branch)
				cmd.Dir = folder
				cmd.Stderr = &stderr
				_, err = cmd.Output()
				if err != nil {
					if err.Error() != "exit status 2" {
						return errors.New(err.Error() + ": " + stderr.String())
					}
					if remoteOnly {
						clifmt.Println("Branch not available on remote")
						continue
					}
					clifmt.Println("Branch not available on remote, switchting to local branch")
					cmd = exec.Command("git", "checkout", "-B", branch, "develop")
					var stdout bytes.Buffer
					stderr.Reset()
					cmd.Dir = folder
					cmd.Stderr = &stderr
					cmd.Stdout = &stdout

					err = cmd.Run()
					if err != nil {
						return errors.New(err.Error() + ": " + stderr.String())
					}
					if stdout.String() != "" {
						clifmt.Println(strings.Replace(stdout.String(), "\n", "\n    ", -1))
					}

					if stderr.String() != "" {
						clifmt.Println(strings.Replace(stderr.String(), "\n", "\n    ", -1))
					}
					continue
				}
				clifmt.Println("Checking out branch origin/" + branch)
				cmd = exec.Command("git", "checkout", "-B", branch, "--track", "origin/"+branch)
				var stdout bytes.Buffer
				stderr.Reset()
				cmd.Dir = folder
				cmd.Stderr = &stderr
				cmd.Stdout = &stdout

				err = cmd.Run()
				if err != nil {
					return errors.New(err.Error() + ": " + stderr.String())
				}
				if stdout.String() != "" {
					clifmt.Println(strings.Replace(stdout.String(), "\n", "\n    ", -1))
				}

				if stderr.String() != "" {
					clifmt.Println(strings.Replace(stderr.String(), "\n", "\n    ", -1))
				}
			}
		}
		return nil
	},
}

func init() {
	RootCmd.AddCommand(gitCoCmd)
	gitCoCmd.Flags().StringVarP(&branch, "branch", "b", "", "the branch which should be checked out from the remote origin")
	gitCoCmd.Flags().BoolVarP(&remoteOnly, "remoteOnly", "r", false, "when no service names are given, only check out given branch if it exists in remote origin ")
}
<commit_msg>- removed unnecessary else indentation<commit_after>// Copyright © 2016 Daniel Ackermann <ackermann.d@gmail.com>
//
// 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 (
	"bytes"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"regexp"
	"strings"

	"github.com/ackermannd/clifmt"
	"github.com/spf13/cobra"
)

var branch string
var remoteOnly bool

// gitCoCmd represents the git-co command
var gitCoCmd = &cobra.Command{
	Use:   "git-co <service name> [<service name> <service name> ...]",
	Short: "Checkout specific branches for the given services",
	Long:  `Takes information from Buildpaths of the given services and checks out the given branch. If local changes are represent, they'll be stashed`,
	RunE: func(cmd *cobra.Command, args []string) error {
		if composeFile == "" {
			return errors.New("No docker-compose file set, either set CFT_COMPOSE environment variable or supply via flag")
		}
		if branch == "" {
			return errors.New("No branch name given")
		}

		cf, err := os.Open(composeFile)
		if err != nil {
			return err
		}
		defer cf.Close()

		if len(args) == 0 {
			if force == false {
				if !confirm("No service name given, this will iterate through all services and tries to check out the remote branch if it exists. Continue? [y/n]") {
					os.Exit(0)
				}
			}
			tmpComposeFolder := strings.Split(composeFile, "/")
			cmd := exec.Command("docker-compose", "config", "--services")
			cmd.Dir = "/" + strings.Join(tmpComposeFolder[1:len(tmpComposeFolder)-1], "/")
			tmp, _ := cmd.Output()
			args = strings.Split(string(tmp), "\n")
			args = args[0 : len(args)-1]
		}

		cfd, _ := ioutil.ReadAll(cf)
		origData := string(cfd)
		clifmt.Settings.Intendation = " "
		for _, sv := range args {
			service := extractService(sv, origData)

			checkReg := regexp.MustCompile("build:(.*)")
			folder := strings.TrimSpace(checkReg.ReplaceAllString(checkReg.FindString(service), "$1"))

			var stderr bytes.Buffer

			fmt.Println("Stashing changes in " + folder)
			cmd := exec.Command("git", "stash")
			cmd.Dir = folder
			cmd.Stderr = &stderr
			_, err := cmd.Output()
			if err != nil {
				return errors.New(err.Error() + ": " + stderr.String())
			}

			stderr.Reset()
			clifmt.Println("Checking if remote origin exists")
			cmd = exec.Command("git", "remote", "show", "origin")
			cmd.Dir = folder
			cmd.Stderr = &stderr
			_, err = cmd.Output()
			if err != nil && err.Error() != "exit status 128" {
				return errors.New(err.Error() + ": " + stderr.String())
			}
			if err != nil && err.Error() == "exit status 128" {
				if remoteOnly {
					clifmt.Println("No remote origin available")
					continue
				}
				clifmt.Println("No remote origin available, creating local branch")
				cmd = exec.Command("git", "checkout", "-B", branch)
				var stdout bytes.Buffer
				stderr.Reset()
				cmd.Dir = folder
				cmd.Stderr = &stderr
				cmd.Stdout = &stdout

				err = cmd.Run()
				if err != nil {
					return errors.New(err.Error() + ": " + stderr.String())
				}
				if stdout.String() != "" {
					clifmt.Println(strings.Replace(stdout.String(), "\n", "\n    ", -1))
				}

				if stderr.String() != "" {
					clifmt.Println(strings.Replace(stderr.String(), "\n", "\n    ", -1))
				}
				continue
			}

			stderr.Reset()
			clifmt.Println("Fetching remote")
			cmd = exec.Command("git", "fetch", "--all")
			cmd.Dir = folder
			cmd.Stderr = &stderr
			_, err = cmd.Output()
			if err != nil {
				return errors.New(err.Error() + ": " + stderr.String())
			}
			stderr.Reset()
			clifmt.Println("Checking if branch exists in remote")
			cmd = exec.Command("git", "ls-remote", "--heads", "--exit-code", "origin", branch)
			cmd.Dir = folder
			cmd.Stderr = &stderr
			_, err = cmd.Output()
			if err != nil {
				if err.Error() != "exit status 2" {
					return errors.New(err.Error() + ": " + stderr.String())
				}
				if remoteOnly {
					clifmt.Println("Branch not available on remote")
					continue
				}
				clifmt.Println("Branch not available on remote, switchting to local branch")
				cmd = exec.Command("git", "checkout", "-B", branch, "develop")
				var stdout bytes.Buffer
				stderr.Reset()
				cmd.Dir = folder
				cmd.Stderr = &stderr
				cmd.Stdout = &stdout

				err = cmd.Run()
				if err != nil {
					return errors.New(err.Error() + ": " + stderr.String())
				}
				if stdout.String() != "" {
					clifmt.Println(strings.Replace(stdout.String(), "\n", "\n    ", -1))
				}

				if stderr.String() != "" {
					clifmt.Println(strings.Replace(stderr.String(), "\n", "\n    ", -1))
				}
				continue
			}
			clifmt.Println("Checking out branch origin/" + branch)
			cmd = exec.Command("git", "checkout", "-B", branch, "--track", "origin/"+branch)
			var stdout bytes.Buffer
			stderr.Reset()
			cmd.Dir = folder
			cmd.Stderr = &stderr
			cmd.Stdout = &stdout

			err = cmd.Run()
			if err != nil {
				return errors.New(err.Error() + ": " + stderr.String())
			}
			if stdout.String() != "" {
				clifmt.Println(strings.Replace(stdout.String(), "\n", "\n    ", -1))
			}

			if stderr.String() != "" {
				clifmt.Println(strings.Replace(stderr.String(), "\n", "\n    ", -1))
			}
		}
		return nil
	},
}

func init() {
	RootCmd.AddCommand(gitCoCmd)
	gitCoCmd.Flags().StringVarP(&branch, "branch", "b", "", "the branch which should be checked out from the remote origin")
	gitCoCmd.Flags().BoolVarP(&remoteOnly, "remoteOnly", "r", false, "when no service names are given, only check out given branch if it exists in remote origin ")
}
<|endoftext|>


<commit_before>// Copyright 2013 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package cmd

import (
	"errors"
	"fmt"
	"io/ioutil"
	"regexp"
	"strings"
	"syscall"
)

type target struct{}

func (t *target) Info() *Info {
	desc := `Retrieve current target (tsuru server)

Displays the current target.
`
	return &Info{
		Name:    "target",
		Usage:   "target",
		Desc:    desc,
		MinArgs: 0,
	}
}

func (t *target) Run(ctx *Context, client Doer) error {
	var target string
	if len(ctx.Args) > 0 {
		fmt.Fprintf(ctx.Stdout, "To set a new target use target-add\n")
		return nil
	}
	target = readTarget()
	fmt.Fprintf(ctx.Stdout, "Current target is %s\n", target)
	return nil
}

const DefaultTarget = "http://tsuru.plataformas.glb.com:8080"

func readTarget() string {
	targetPath, _ := joinWithUserDir(".tsuru_target")
	if f, err := filesystem().Open(targetPath); err == nil {
		defer f.Close()
		if b, err := ioutil.ReadAll(f); err == nil {
			return strings.TrimSpace(string(b))
		}
	}
	return DefaultTarget
}

func GetUrl(path string) string {
	var prefix string
	target := readTarget()
	if m, _ := regexp.MatchString("^https?://", target); !m {
		prefix = "http://"
	}
	return prefix + target + path
}

func writeTarget(t string) error {
	targetPath, err := joinWithUserDir(".tsuru_target")
	if err != nil {
		return err
	}
	targetFile, err := filesystem().OpenFile(targetPath, syscall.O_WRONLY|syscall.O_CREAT|syscall.O_TRUNC, 0600)
	if err != nil {
		return err
	}
	defer targetFile.Close()
	t = strings.TrimRight(t, "/")
	content := []byte(t)
	n, err := targetFile.Write(content)
	if n != len(content) || err != nil {
		return errors.New("Failed to write the target file")
	}
	return nil
}

type targetAdd struct{}

func (t *targetAdd) Info() *Info {
	desc := `Add a new target on target-list (tsuru server)
`
	return &Info{
		Name:    "target-add",
		Usage:   "target-add <label> <target>",
		Desc:    desc,
		MinArgs: 2,
	}
}

func (t *targetAdd) Run(ctx *Context, client Doer) error {
	var target string
	var label string

	if len(ctx.Args) != 2 {
		return errors.New("Invalid arguments")
	}

	label = ctx.Args[0]
	target = ctx.Args[1]

	err := writeOnTargetList(label, target)

	if err != nil {
		return err
	}

	fmt.Fprintf(ctx.Stdout, "New target %s -> %s added to target-list\n", label, target)

	return nil

}

func resetTargetList() error {
	targetsPath, err := joinWithUserDir(".tsuru_targets")
	if err != nil {
		return err
	}
	targetsFile, err := filesystem().OpenFile(targetsPath, syscall.O_WRONLY|syscall.O_CREAT|syscall.O_TRUNC, 0600)
	if err != nil {
		return err
	}
	targetsFile.Truncate(0)
	defer targetsFile.Close()

	return nil
}

func writeOnTargetList(label string, target string) error {
	label = strings.TrimSpace(label)
	target = strings.TrimSpace(target)

	targetExist, err := checkIfTargetLabelExists(label)
	if err != nil {
		return err
	}
	if targetExist {
		return errors.New("Target label provided already exist")
	}

	targetsPath, err := joinWithUserDir(".tsuru_targets")
	if err != nil {
		return err
	}

	targetsFile, err := filesystem().OpenFile(targetsPath, syscall.O_RDWR|syscall.O_CREAT|syscall.O_APPEND, 0600)
	if err != nil {
		return err
	}

	defer targetsFile.Close()
	var content = label + "\t" + target + "\n"
	n, err := targetsFile.WriteString(content)
	if n != len(content) || err != nil {
		return errors.New("Failed to write the target file")
	}

	return nil
}

func checkIfTargetLabelExists(label string) (bool, error) {
	targets, err := getTargets()
	if err != nil {
		return false, err
	}

	_, exists := targets[label]
	if exists {
		return true, nil
	}

	return false, nil

}

func getTargets() (map[string]string, error) {
	var targets = map[string]string{}

	targetsPath, err := joinWithUserDir(".tsuru_targets")
	if err != nil {
		return targets, err
	}

	if f, err := filesystem().Open(targetsPath); err == nil {
		defer f.Close()
		if b, err := ioutil.ReadAll(f); err == nil {
			var targetLines = strings.Split(strings.TrimSpace(string(b)), "\n")

			for i := range targetLines {
				var targetSplt = strings.Split(targetLines[i], "\t")

				if len(targetSplt) == 2 {
					targets[targetSplt[0]] = targetSplt[1]
				}
			}
		}
	}

	return targets, nil
}

type targetList struct{}

func (t *targetList) Info() *Info {
	desc := `List all targets (tsuru server)
`
	return &Info{
		Name:    "target-list",
		Usage:   "target-list",
		Desc:    desc,
		MinArgs: 0,
	}
}

func (t *targetList) Run(ctx *Context, client Doer) error {

	table := NewTable()
	targets, err := getTargets()

	if err != nil {
		return err
	}

	for label, target := range targets {
		table.AddRow(Row{label, target})
	}

	fmt.Fprintf(ctx.Stdout, table.String())

	return nil
}

type targetRemove struct{}

func (t *targetRemove) Info() *Info {
	desc := `Remove a target from target-list (tsuru server)
`
	return &Info{
		Name:    "target-remove",
		Usage:   "target-remove",
		Desc:    desc,
		MinArgs: 1,
	}
}

func (t *targetRemove) Run(ctx *Context, client Doer) error {
	if len(ctx.Args) != 1 {
		return errors.New("Invalid arguments")
	}

	targetLabelToRemove := strings.TrimSpace(ctx.Args[0])

	targets, err := getTargets()

	if err != nil {
		return err
	}

	for label, _ := range targets {
		if label == targetLabelToRemove {
			delete(targets, label)
		}
	}

	err = resetTargetList()
	if err != nil {
		return err
	}

	for label, target := range targets {
		writeOnTargetList(label, target)
	}

	return nil
}

type targetSet struct{}

func (t *targetSet) Info() *Info {
	desc := `Change current target (tsuru server)
`
	return &Info{
		Name:    "target-set",
		Usage:   "target-set <label>",
		Desc:    desc,
		MinArgs: 1,
	}
}

func (t *targetSet) Run(ctx *Context, client Doer) error {
	if len(ctx.Args) != 1 {
		return errors.New("Invalid arguments")
	}

	targetLabelToSet := strings.TrimSpace(ctx.Args[0])

	labelExist, err := checkIfTargetLabelExists(targetLabelToSet)

	if !labelExist {
		return errors.New("Target not found")
	}

	targets, err := getTargets()

	if err != nil {
		return err
	}

	for label, target := range targets {
		if label == targetLabelToSet {
			err = writeTarget(target)

			if err != nil {
				return err
			}

			fmt.Fprintf(ctx.Stdout, "New target is %s -> %s\n", label, target)
		}
	}

	return nil
}
<commit_msg>cmd/target.go: gofmt -s -w -l .<commit_after>// Copyright 2013 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package cmd

import (
	"errors"
	"fmt"
	"io/ioutil"
	"regexp"
	"strings"
	"syscall"
)

type target struct{}

func (t *target) Info() *Info {
	desc := `Retrieve current target (tsuru server)

Displays the current target.
`
	return &Info{
		Name:    "target",
		Usage:   "target",
		Desc:    desc,
		MinArgs: 0,
	}
}

func (t *target) Run(ctx *Context, client Doer) error {
	var target string
	if len(ctx.Args) > 0 {
		fmt.Fprintf(ctx.Stdout, "To set a new target use target-add\n")
		return nil
	}
	target = readTarget()
	fmt.Fprintf(ctx.Stdout, "Current target is %s\n", target)
	return nil
}

const DefaultTarget = "http://tsuru.plataformas.glb.com:8080"

func readTarget() string {
	targetPath, _ := joinWithUserDir(".tsuru_target")
	if f, err := filesystem().Open(targetPath); err == nil {
		defer f.Close()
		if b, err := ioutil.ReadAll(f); err == nil {
			return strings.TrimSpace(string(b))
		}
	}
	return DefaultTarget
}

func GetUrl(path string) string {
	var prefix string
	target := readTarget()
	if m, _ := regexp.MatchString("^https?://", target); !m {
		prefix = "http://"
	}
	return prefix + target + path
}

func writeTarget(t string) error {
	targetPath, err := joinWithUserDir(".tsuru_target")
	if err != nil {
		return err
	}
	targetFile, err := filesystem().OpenFile(targetPath, syscall.O_WRONLY|syscall.O_CREAT|syscall.O_TRUNC, 0600)
	if err != nil {
		return err
	}
	defer targetFile.Close()
	t = strings.TrimRight(t, "/")
	content := []byte(t)
	n, err := targetFile.Write(content)
	if n != len(content) || err != nil {
		return errors.New("Failed to write the target file")
	}
	return nil
}

type targetAdd struct{}

func (t *targetAdd) Info() *Info {
	desc := `Add a new target on target-list (tsuru server)
`
	return &Info{
		Name:    "target-add",
		Usage:   "target-add <label> <target>",
		Desc:    desc,
		MinArgs: 2,
	}
}

func (t *targetAdd) Run(ctx *Context, client Doer) error {
	var target string
	var label string

	if len(ctx.Args) != 2 {
		return errors.New("Invalid arguments")
	}

	label = ctx.Args[0]
	target = ctx.Args[1]

	err := writeOnTargetList(label, target)

	if err != nil {
		return err
	}

	fmt.Fprintf(ctx.Stdout, "New target %s -> %s added to target-list\n", label, target)

	return nil

}

func resetTargetList() error {
	targetsPath, err := joinWithUserDir(".tsuru_targets")
	if err != nil {
		return err
	}
	targetsFile, err := filesystem().OpenFile(targetsPath, syscall.O_WRONLY|syscall.O_CREAT|syscall.O_TRUNC, 0600)
	if err != nil {
		return err
	}
	targetsFile.Truncate(0)
	defer targetsFile.Close()

	return nil
}

func writeOnTargetList(label string, target string) error {
	label = strings.TrimSpace(label)
	target = strings.TrimSpace(target)

	targetExist, err := checkIfTargetLabelExists(label)
	if err != nil {
		return err
	}
	if targetExist {
		return errors.New("Target label provided already exist")
	}

	targetsPath, err := joinWithUserDir(".tsuru_targets")
	if err != nil {
		return err
	}

	targetsFile, err := filesystem().OpenFile(targetsPath, syscall.O_RDWR|syscall.O_CREAT|syscall.O_APPEND, 0600)
	if err != nil {
		return err
	}

	defer targetsFile.Close()
	var content = label + "\t" + target + "\n"
	n, err := targetsFile.WriteString(content)
	if n != len(content) || err != nil {
		return errors.New("Failed to write the target file")
	}

	return nil
}

func checkIfTargetLabelExists(label string) (bool, error) {
	targets, err := getTargets()
	if err != nil {
		return false, err
	}

	_, exists := targets[label]
	if exists {
		return true, nil
	}

	return false, nil

}

func getTargets() (map[string]string, error) {
	var targets = map[string]string{}

	targetsPath, err := joinWithUserDir(".tsuru_targets")
	if err != nil {
		return targets, err
	}

	if f, err := filesystem().Open(targetsPath); err == nil {
		defer f.Close()
		if b, err := ioutil.ReadAll(f); err == nil {
			var targetLines = strings.Split(strings.TrimSpace(string(b)), "\n")

			for i := range targetLines {
				var targetSplt = strings.Split(targetLines[i], "\t")

				if len(targetSplt) == 2 {
					targets[targetSplt[0]] = targetSplt[1]
				}
			}
		}
	}

	return targets, nil
}

type targetList struct{}

func (t *targetList) Info() *Info {
	desc := `List all targets (tsuru server)
`
	return &Info{
		Name:    "target-list",
		Usage:   "target-list",
		Desc:    desc,
		MinArgs: 0,
	}
}

func (t *targetList) Run(ctx *Context, client Doer) error {

	table := NewTable()
	targets, err := getTargets()

	if err != nil {
		return err
	}

	for label, target := range targets {
		table.AddRow(Row{label, target})
	}

	fmt.Fprintf(ctx.Stdout, table.String())

	return nil
}

type targetRemove struct{}

func (t *targetRemove) Info() *Info {
	desc := `Remove a target from target-list (tsuru server)
`
	return &Info{
		Name:    "target-remove",
		Usage:   "target-remove",
		Desc:    desc,
		MinArgs: 1,
	}
}

func (t *targetRemove) Run(ctx *Context, client Doer) error {
	if len(ctx.Args) != 1 {
		return errors.New("Invalid arguments")
	}

	targetLabelToRemove := strings.TrimSpace(ctx.Args[0])

	targets, err := getTargets()

	if err != nil {
		return err
	}

	for label := range targets {
		if label == targetLabelToRemove {
			delete(targets, label)
		}
	}

	err = resetTargetList()
	if err != nil {
		return err
	}

	for label, target := range targets {
		writeOnTargetList(label, target)
	}

	return nil
}

type targetSet struct{}

func (t *targetSet) Info() *Info {
	desc := `Change current target (tsuru server)
`
	return &Info{
		Name:    "target-set",
		Usage:   "target-set <label>",
		Desc:    desc,
		MinArgs: 1,
	}
}

func (t *targetSet) Run(ctx *Context, client Doer) error {
	if len(ctx.Args) != 1 {
		return errors.New("Invalid arguments")
	}

	targetLabelToSet := strings.TrimSpace(ctx.Args[0])

	labelExist, err := checkIfTargetLabelExists(targetLabelToSet)

	if !labelExist {
		return errors.New("Target not found")
	}

	targets, err := getTargets()

	if err != nil {
		return err
	}

	for label, target := range targets {
		if label == targetLabelToSet {
			err = writeTarget(target)

			if err != nil {
				return err
			}

			fmt.Fprintf(ctx.Stdout, "New target is %s -> %s\n", label, target)
		}
	}

	return nil
}
<|endoftext|>


<commit_before>//
// Package ep is a collection of structures and functions for working with the EPrints REST API
//
// @author R. S. Doiel, <rsdoiel@caltech.edu>
//
// Copyright (c) 2017, 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 (
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"os"
	"path"
	"strconv"
	"strings"
	"time"

	// Caltech Library Packages
	"github.com/caltechlibrary/cli"
	"github.com/caltechlibrary/ep"
)

var (
	// cli help text
	usage = `USAGE %s [OPTIONS] [EP_EPRINTS_URL|ONE_OR_MORE_EPRINT_ID]`

	description = `
SYNOPSIS

%s wraps the REST API for EPrints 3.3 or better. It can return a list
of uri, a JSON view of the XML presentation as well as generates feeds
and web pages.

CONFIGURATION

%s can be configured with following environment variables

EP_EPRINTS_URL the URL to your EPrints installation

EP_DATASET the dataset and collection name for exporting, site building, and content retrieval`

	examples = `
EXAMPLE

    %s -export all

Would export the entire EPrints repository public content defined by the
environment virables EP_API_URL, EP_DATASET.

    %s -export 2000

Would export 2000 EPrints from the repository with the heighest ID values.
`

	// Standard Options
	showHelp    bool
	showVersion bool
	showLicense bool
	outputFName string

	// App Options
	useAPI      bool
	prettyPrint bool

	apiURL      string
	datasetName string

	updatedSince       string
	exportEPrints      string
	exportEPrintsSince string
	feedSize           int

	authMethod string
	userName   string
	userSecret string
)

func init() {
	// Setup options
	feedSize = ep.DefaultFeedSize

	flag.BoolVar(&showHelp, "h", false, "display help")
	flag.BoolVar(&showHelp, "help", false, "display help")
	flag.BoolVar(&showLicense, "l", false, "display license")
	flag.BoolVar(&showLicense, "license", false, "display license")
	flag.BoolVar(&showVersion, "v", false, "display version")
	flag.BoolVar(&showVersion, "version", false, "display version")
	flag.StringVar(&outputFName, "o", "", "output filename (logging)")
	flag.StringVar(&outputFName, "output", "", "output filename (logging)")

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

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

	flag.BoolVar(&prettyPrint, "p", false, "pretty print JSON output")
	flag.BoolVar(&prettyPrint, "pretty", false, "pretty print JSON output")
	flag.BoolVar(&useAPI, "read-api", false, "read the contents from the API without saving in the database")
	flag.StringVar(&exportEPrints, "export", "", "export N EPrints from highest ID to lowest")
	flag.StringVar(&exportEPrintsSince, "export-since", "", "export  EPrints from a given date to present (e.g. 2017-07-01)")
	flag.StringVar(&updatedSince, "updated-since", "", "list EPrint IDs updated since a given date (e.g 2017-07-01)")
}

func check(cfg *cli.Config, key, value string) string {
	if value == "" {
		log.Fatalf("Missing %s_%s", cfg.EnvPrefix, strings.ToUpper(key))
		return ""
	}
	return value
}

func main() {
	appName := path.Base(os.Args[0])
	flag.Parse()
	args := flag.Args()

	// Populate cfg from the environment
	cfg := cli.New(appName, appName, fmt.Sprintf(ep.LicenseText, appName, ep.Version), ep.Version)
	cfg.UsageText = fmt.Sprintf(usage, appName)
	cfg.DescriptionText = fmt.Sprintf(description, appName, appName)
	cfg.ExampleText = fmt.Sprintf(examples, appName, appName)

	// Handle the default options
	if showHelp == true {
		fmt.Println(cfg.Usage())
		os.Exit(0)
	}
	if showVersion == true {
		fmt.Println(cfg.Version())
		os.Exit(0)
	}
	if showLicense == true {
		fmt.Println(cfg.License())
		os.Exit(0)
	}

	out, err := cli.Create(outputFName, os.Stdout)
	if err != nil {
		fmt.Fprint(os.Stderr, "%s\n", err)
		os.Exit(1)
	}
	defer cli.CloseFile(outputFName, out)

	// Log to out
	log.SetOutput(out)

	// Required configuration
	apiURL = check(cfg, "eprint_url", cfg.MergeEnv("eprint_url", apiURL))
	datasetName = check(cfg, "dataset", cfg.MergeEnv("dataset", datasetName))

	// Optional configuration
	authMethod = cfg.MergeEnv("auth_method", authMethod)
	userName = cfg.MergeEnv("username", userName)
	userSecret = cfg.MergeEnv("password", userSecret)

	// This will read in any settings from the environment
	api, err := ep.New(cfg)
	if err != nil {
		log.Fatal(err)
	}

	if exportEPrints != "" {
		t0 := time.Now()
		exportNo := -1
		if exportEPrints != "all" {
			exportNo, err = strconv.Atoi(exportEPrints)
			if err != nil {
				log.Fatalf("Export count should be %q or an integer, %s", exportEPrints, err)
			}
		}
		log.Printf("%s %s", appName, ep.Version)
		log.Printf("Export started, %s", t0)
		if err := api.ExportEPrints(exportNo); err != nil {
			log.Printf("%s", err)
			os.Exit(1)
		}
		log.Printf("Export completed, running time %s", time.Now().Sub(t0))
		os.Exit(0)
	}
	if exportEPrintsSince != "" {
		start, err := time.Parse("2006-01-02", exportEPrintsSince)
		if err != nil {
			log.Printf("%s", err)
			os.Exit(1)
		}
		end := time.Now()
		t0 := time.Now()
		log.Printf("%s %s", appName, ep.Version)
		log.Printf("Export from %s to %s, started %s", start.Format("2006-01-02"), end.Format("2006-01-02"), t0)
		if err := api.ExportModifiedEPrints(start, end); err != nil {
			log.Printf("%s", err)
			os.Exit(1)
		}
		log.Printf("Export completed, running time %s", time.Now().Sub(t0))
		os.Exit(0)
	}

	//
	// Generate JSON output
	//
	var (
		src  []byte
		data interface{}
	)
	switch {
	case updatedSince != "":
		// date should be formatted YYYY-MM-DD, 2006-01-02
		end := time.Now()
		start, err := time.Parse("2006-01-02", updatedSince)
		if err != nil {
			fmt.Fprintf(os.Stderr, "updated since %q, %s", updatedSince, err)
			os.Exit(1)
		}
		data, err = api.ListModifiedEPrintURI(start, end)
	case useAPI == true:
		if len(args) == 1 {
			data, _, err = api.GetEPrint(args[0])
		} else {
			data, err = api.ListEPrintsURI()
		}
	default:
		if len(args) == 1 {
			data, err = api.Get(args[0])
		} else if len(args) > 1 {
			records := []*ep.Record{}
			for _, id := range args {
				if rec, err := api.Get(id); err == nil {
					records = append(records, rec)
				} else {
					fmt.Fprintf(os.Stderr, "Can't read EPrint id %s, %s\n", id, err)
				}
			}
			data = records
		} else {
			data, err = api.ListID(0, -1)
		}
	}
	if err != nil {
		log.Fatal(err)
	}

	if prettyPrint == true {
		src, _ = json.MarshalIndent(data, "", "    ")
	} else {
		src, _ = json.Marshal(data)
	}
	fmt.Printf("%s", src)
}
<commit_msg>Quick Save<commit_after>//
// Package ep is a collection of structures and functions for working with the EPrints REST API
//
// @author R. S. Doiel, <rsdoiel@caltech.edu>
//
// Copyright (c) 2017, 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 (
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"os"
	"path"
	"strconv"
	"strings"
	"time"

	// Caltech Library Packages
	"github.com/caltechlibrary/cli"
	"github.com/caltechlibrary/ep"
)

var (
	// cli help text
	usage = `USAGE %s [OPTIONS] [EP_EPRINTS_URL|ONE_OR_MORE_EPRINT_ID]`

	description = `
SYNOPSIS

%s wraps the REST API for EPrints 3.3 or better. It can return a list
of uri, a JSON view of the XML presentation as well as generates feeds
and web pages.

CONFIGURATION

%s can be configured with following environment variables

EP_EPRINTS_URL the URL to your EPrints installation

EP_DATASET the dataset and collection name for exporting, site building, and content retrieval`

	examples = `
EXAMPLE

    %s -export all

Would export the entire EPrints repository public content defined by the
environment virables EP_API_URL, EP_DATASET.

    %s -export 2000

Would export 2000 EPrints from the repository with the heighest ID values.
`

	// Standard Options
	showHelp    bool
	showVersion bool
	showLicense bool
	outputFName string

	// App Options
	useAPI      bool
	prettyPrint bool

	apiURL      string
	datasetName string

	updatedSince       string
	exportEPrints      string
	exportEPrintsSince string
	feedSize           int

	authMethod string
	userName   string
	userSecret string
)

func init() {
	// Setup options
	feedSize = ep.DefaultFeedSize

	flag.BoolVar(&showHelp, "h", false, "display help")
	flag.BoolVar(&showHelp, "help", false, "display help")
	flag.BoolVar(&showLicense, "l", false, "display license")
	flag.BoolVar(&showLicense, "license", false, "display license")
	flag.BoolVar(&showVersion, "v", false, "display version")
	flag.BoolVar(&showVersion, "version", false, "display version")
	flag.StringVar(&outputFName, "o", "", "output filename (logging)")
	flag.StringVar(&outputFName, "output", "", "output filename (logging)")

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

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

	flag.BoolVar(&prettyPrint, "p", false, "pretty print JSON output")
	flag.BoolVar(&prettyPrint, "pretty", false, "pretty print JSON output")
	flag.BoolVar(&useAPI, "read-api", false, "read the contents from the API without saving in the database")
	flag.StringVar(&exportEPrints, "export", "", "export N EPrints from highest ID to lowest")
	flag.StringVar(&exportEPrintsSince, "export-since", "", "export  EPrints from a given date to present (e.g. 2017-07-01)")
	flag.StringVar(&updatedSince, "updated-since", "", "list EPrint IDs updated since a given date (e.g 2017-07-01)")
}

func check(cfg *cli.Config, key, value string) string {
	if value == "" {
		log.Fatalf("Missing %s_%s", cfg.EnvPrefix, strings.ToUpper(key))
		return ""
	}
	return value
}

func main() {
	appName := path.Base(os.Args[0])
	flag.Parse()
	args := flag.Args()

	// Populate cfg from the environment
	cfg := cli.New(appName, appName, fmt.Sprintf(ep.LicenseText, appName, ep.Version), ep.Version)
	cfg.UsageText = fmt.Sprintf(usage, appName)
	cfg.DescriptionText = fmt.Sprintf(description, appName, appName)
	cfg.ExampleText = fmt.Sprintf(examples, appName, appName)

	// Handle the default options
	if showHelp == true {
		fmt.Println(cfg.Usage())
		os.Exit(0)
	}
	if showVersion == true {
		fmt.Println(cfg.Version())
		os.Exit(0)
	}
	if showLicense == true {
		fmt.Println(cfg.License())
		os.Exit(0)
	}

	out, err := cli.Create(outputFName, os.Stdout)
	if err != nil {
		fmt.Fprint(os.Stderr, "%s\n", err)
		os.Exit(1)
	}
	defer cli.CloseFile(outputFName, out)

	// Log to out
	log.SetOutput(out)

	// Required configuration
	apiURL = check(cfg, "eprint_url", cfg.MergeEnv("eprint_url", apiURL))
	datasetName = check(cfg, "dataset", cfg.MergeEnv("dataset", datasetName))

	// Optional configuration
	authMethod = cfg.MergeEnv("auth_method", authMethod)
	userName = cfg.MergeEnv("username", userName)
	userSecret = cfg.MergeEnv("password", userSecret)

	// This will read in any settings from the environment
	api, err := ep.New(cfg)
	if err != nil {
		log.Fatal(err)
	}

	if exportEPrints != "" {
		t0 := time.Now()
		exportNo := -1
		if exportEPrints != "all" {
			exportNo, err = strconv.Atoi(exportEPrints)
			if err != nil {
				log.Fatalf("Export count should be %q or an integer, %s", exportEPrints, err)
			}
		}
		log.Printf("%s %s", appName, ep.Version)
		log.Printf("Export started, %s", t0)
		if err := api.ExportEPrints(exportNo); err != nil {
			log.Printf("%s", err)
			os.Exit(1)
		}
		log.Printf("Export completed, running time %s", time.Now().Sub(t0))
		os.Exit(0)
	}
	if exportEPrintsSince != "" {
		start, err := time.Parse("2006-01-02", exportEPrintsSince)
		if err != nil {
			log.Printf("%s", err)
			os.Exit(1)
		}
		end := time.Now()
		t0 := time.Now()
		log.Printf("%s %s", appName, ep.Version)
		log.Printf("Export from %s to %s, started %s", start.Format("2006-01-02"), end.Format("2006-01-02"), t0.Format("2006-01-02 15:04:05 MST"))
		if err := api.ExportModifiedEPrints(start, end); err != nil {
			log.Printf("%s", err)
			os.Exit(1)
		}
		log.Printf("Export completed, running time %s", time.Now().Sub(t0))
		os.Exit(0)
	}

	//
	// Generate JSON output
	//
	var (
		src  []byte
		data interface{}
	)
	switch {
	case updatedSince != "":
		// date should be formatted YYYY-MM-DD, 2006-01-02
		end := time.Now()
		start, err := time.Parse("2006-01-02", updatedSince)
		if err != nil {
			fmt.Fprintf(os.Stderr, "updated since %q, %s", updatedSince, err)
			os.Exit(1)
		}
		data, err = api.ListModifiedEPrintURI(start, end)
	case useAPI == true:
		if len(args) == 1 {
			data, _, err = api.GetEPrint(args[0])
		} else {
			data, err = api.ListEPrintsURI()
		}
	default:
		if len(args) == 1 {
			data, err = api.Get(args[0])
		} else if len(args) > 1 {
			records := []*ep.Record{}
			for _, id := range args {
				if rec, err := api.Get(id); err == nil {
					records = append(records, rec)
				} else {
					fmt.Fprintf(os.Stderr, "Can't read EPrint id %s, %s\n", id, err)
				}
			}
			data = records
		} else {
			data, err = api.ListID(0, -1)
		}
	}
	if err != nil {
		log.Fatal(err)
	}

	if prettyPrint == true {
		src, _ = json.MarshalIndent(data, "", "    ")
	} else {
		src, _ = json.Marshal(data)
	}
	fmt.Printf("%s", src)
}
<|endoftext|>