<commit_before>// Package main is located in the cmd/ponzu directory and contains the code to build
// and operate the command line interface (CLI) to manage Ponzu systems. Here,
// you will find the code that is used to create new Ponzu projects, generate
// code for content types and other files, build Ponzu binaries and run servers.
package main

import (
	"errors"
	"fmt"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"

	_ "github.com/ponzu-cms/ponzu/content"
	"github.com/ponzu-cms/ponzu/system/admin"
	"github.com/ponzu-cms/ponzu/system/api"
	"github.com/ponzu-cms/ponzu/system/api/analytics"
	"github.com/ponzu-cms/ponzu/system/db"
	"github.com/ponzu-cms/ponzu/system/tls"

	"github.com/spf13/cobra"
)

var (
	port      int
	httpsport int
	https     bool
	devhttps  bool
	cli       bool

	// for ponzu internal / core development
	dev   bool
	fork  string
	gocmd string
	year  = fmt.Sprintf("%d", time.Now().Year())
)

var rootCmd = &cobra.Command{
	Use: "ponzu",
	Long: `Ponzu is an open-source HTTP server framework and CMS, released under
the BSD-3-Clause license.
(c) 2016 - ` + year + ` Boss Sauce Creative, LLC`,
}

var runCmd = &cobra.Command{
	Use:   "run [flags] <service(,service)>",
	Short: "starts the 'ponzu' HTTP server for the JSON API and or Admin System.",
	Long: `Starts the 'ponzu' HTTP server for the JSON API, Admin System, or both.
The segments, separated by a comma, describe which services to start, either
'admin' (Admin System / CMS backend) or 'api' (JSON API), and, optionally,
if the server should utilize TLS encryption - served over HTTPS, which is
automatically managed using Let's Encrypt (https://letsencrypt.org)

Defaults to 'run -port=8080 admin,api' (running Admin & API on port 8080, without TLS)

Note:
Admin and API cannot run on separate processes unless you use a copy of the
database, since the first process to open it receives a lock. If you intend
to run the Admin and API on separate processes, you must call them with the
'ponzu' command independently.`,
	Example: `$ ponzu run
(or)
$ ponzu run --port=8080 --https admin,api
(or)
$ ponzu run admin
(or)
$ ponzu run --port=8888 api`,
	RunE: func(cmd *cobra.Command, args []string) error {
		var addTLS string
		if https {
			addTLS = "--https"
		} else {
			addTLS = "--https=false"
		}

		if devhttps {
			addTLS = "--devhttps"
		}

		var services string
		if len(args) > 0 {
			services = args[0]
		} else {
			services = "admin,api"
		}

		name := buildOutputName()
		buildPathName := strings.Join([]string{".", name}, string(filepath.Separator))
		serve := exec.Command(buildPathName,
			fmt.Sprintf("--port=%d", port),
			fmt.Sprintf("--https-port=%d", httpsport),
			addTLS,
			"serve",
			services,
		)
		serve.Stderr = os.Stderr
		serve.Stdout = os.Stdout

		return serve.Run()
	},
}

// ErrWrongOrMissingService informs a user that the services to run must be
// explicitly specified when serve is called
var ErrWrongOrMissingService = errors.New("To execute 'ponzu serve', " +
	"you must specify which service to run.")

var serveCmd = &cobra.Command{
	Use:     "serve [flags] <service,service>",
	Aliases: []string{"s"},
	Short:   "actually run the server (serve is wrapped by the run command)",
	Hidden:  true,
	RunE: func(cmd *cobra.Command, args []string) error {
		if len(args) == 0 {
			return ErrWrongOrMissingService
		}

		db.Init()
		defer db.Close()

		analytics.Init()
		defer analytics.Close()

		services := strings.Split(args[0], ",")

		for _, service := range services {
			if service == "api" {
				api.Run()
			} else if service == "admin" {
				admin.Run()
			} else {
				return ErrWrongOrMissingService
			}
		}

		// save the https port the system is listening on
		err := db.PutConfig("https_port", fmt.Sprintf("%d", httpsport))
		if err != nil {
			log.Fatalln("System failed to save config. Please try to run again.", err)
		}

		// cannot run production HTTPS and development HTTPS together
		if devhttps {
			fmt.Println("Enabling self-signed HTTPS... [DEV]")

			go tls.EnableDev()
			fmt.Println("Server listening on https://localhost:10443 for requests... [DEV]")
			fmt.Println("----")
			fmt.Println("If your browser rejects HTTPS requests, try allowing insecure connections on localhost.")
			fmt.Println("on Chrome, visit chrome://flags/#allow-insecure-localhost")

		} else if https {
			fmt.Println("Enabling HTTPS...")

			go tls.Enable()
			fmt.Printf("Server listening on :%s for HTTPS requests...\n", db.ConfigCache("https_port").(string))
		}

		// save the https port the system is listening on so internal system can make
		// HTTP api calls while in dev or production w/o adding more cli flags
		err = db.PutConfig("http_port", fmt.Sprintf("%d", port))
		if err != nil {
			log.Fatalln("System failed to save config. Please try to run again.", err)
		}

		fmt.Printf("Server listening on :%d for HTTP requests...\n", port)
		fmt.Println("\nvisit `/admin` to get started.")
		log.Fatalln(http.ListenAndServe(fmt.Sprintf(":%d", port), nil))
		return nil
	},
}

func init() {
	for _, cmd := range []*cobra.Command{runCmd, serveCmd} {
		cmd.Flags().IntVar(&port, "port", 8080, "port for ponzu to bind its HTTP listener")
		cmd.Flags().IntVar(&httpsport, "https-port", 443, "port for ponzu to bind its HTTPS listener")
		cmd.Flags().BoolVar(&https, "https", false, "enable automatic TLS/SSL certificate management")
		cmd.Flags().BoolVar(&devhttps, "dev-https", false, "[dev environment] enable automatic TLS/SSL certificate management")
	}

	RegisterCmdlineCommand(runCmd)
	RegisterCmdlineCommand(serveCmd)

	pflags := rootCmd.PersistentFlags()
	pflags.StringVar(&gocmd, "gocmd", "go", "custom go command if using beta or new release of Go")
}

func main() {
	if err := rootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}

func execAndWait(command string, arg ...string) error {
	cmd := exec.Command(command, arg...)
	cmd.Stderr = os.Stderr
	cmd.Stdout = os.Stdout

	err := cmd.Start()
	if err != nil {
		return err

	}
	return cmd.Wait()
}
<commit_msg>fix for run with --dev-https, out of order<commit_after>// Package main is located in the cmd/ponzu directory and contains the code to build
// and operate the command line interface (CLI) to manage Ponzu systems. Here,
// you will find the code that is used to create new Ponzu projects, generate
// code for content types and other files, build Ponzu binaries and run servers.
package main

import (
	"errors"
	"fmt"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"

	_ "github.com/ponzu-cms/ponzu/content"
	"github.com/ponzu-cms/ponzu/system/admin"
	"github.com/ponzu-cms/ponzu/system/api"
	"github.com/ponzu-cms/ponzu/system/api/analytics"
	"github.com/ponzu-cms/ponzu/system/db"
	"github.com/ponzu-cms/ponzu/system/tls"

	"github.com/spf13/cobra"
)

var (
	port      int
	httpsport int
	https     bool
	devhttps  bool
	cli       bool

	// for ponzu internal / core development
	dev   bool
	fork  string
	gocmd string
	year  = fmt.Sprintf("%d", time.Now().Year())
)

var rootCmd = &cobra.Command{
	Use: "ponzu",
	Long: `Ponzu is an open-source HTTP server framework and CMS, released under
the BSD-3-Clause license.
(c) 2016 - ` + year + ` Boss Sauce Creative, LLC`,
}

var runCmd = &cobra.Command{
	Use:   "run [flags] <service(,service)>",
	Short: "starts the 'ponzu' HTTP server for the JSON API and or Admin System.",
	Long: `Starts the 'ponzu' HTTP server for the JSON API, Admin System, or both.
The segments, separated by a comma, describe which services to start, either
'admin' (Admin System / CMS backend) or 'api' (JSON API), and, optionally,
if the server should utilize TLS encryption - served over HTTPS, which is
automatically managed using Let's Encrypt (https://letsencrypt.org)

Defaults to 'run -port=8080 admin,api' (running Admin & API on port 8080, without TLS)

Note:
Admin and API cannot run on separate processes unless you use a copy of the
database, since the first process to open it receives a lock. If you intend
to run the Admin and API on separate processes, you must call them with the
'ponzu' command independently.`,
	Example: `$ ponzu run
(or)
$ ponzu run --port=8080 --https admin,api
(or)
$ ponzu run admin
(or)
$ ponzu run --port=8888 api`,
	RunE: func(cmd *cobra.Command, args []string) error {
		var addTLS string
		if https {
			addTLS = "--https"
		} else {
			addTLS = "--https=false"
		}

		if devhttps {
			addTLS = "--dev-https"
		}

		var services string
		if len(args) > 0 {
			services = args[0]
		} else {
			services = "admin,api"
		}

		name := buildOutputName()
		buildPathName := strings.Join([]string{".", name}, string(filepath.Separator))
		serve := exec.Command(buildPathName,
			"serve",
			services,
			fmt.Sprintf("--port=%d", port),
			fmt.Sprintf("--https-port=%d", httpsport),
			addTLS,
		)
		serve.Stderr = os.Stderr
		serve.Stdout = os.Stdout

		return serve.Run()
	},
}

// ErrWrongOrMissingService informs a user that the services to run must be
// explicitly specified when serve is called
var ErrWrongOrMissingService = errors.New("To execute 'ponzu serve', " +
	"you must specify which service to run.")

var serveCmd = &cobra.Command{
	Use:     "serve [flags] <service,service>",
	Aliases: []string{"s"},
	Short:   "actually run the server (serve is wrapped by the run command)",
	Hidden:  true,
	RunE: func(cmd *cobra.Command, args []string) error {
		if len(args) == 0 {
			return ErrWrongOrMissingService
		}

		db.Init()
		defer db.Close()

		analytics.Init()
		defer analytics.Close()

		services := strings.Split(args[0], ",")

		for _, service := range services {
			if service == "api" {
				api.Run()
			} else if service == "admin" {
				admin.Run()
			} else {
				return ErrWrongOrMissingService
			}
		}

		// save the https port the system is listening on
		err := db.PutConfig("https_port", fmt.Sprintf("%d", httpsport))
		if err != nil {
			log.Fatalln("System failed to save config. Please try to run again.", err)
		}

		// cannot run production HTTPS and development HTTPS together
		if devhttps {
			fmt.Println("Enabling self-signed HTTPS... [DEV]")

			go tls.EnableDev()
			fmt.Println("Server listening on https://localhost:10443 for requests... [DEV]")
			fmt.Println("----")
			fmt.Println("If your browser rejects HTTPS requests, try allowing insecure connections on localhost.")
			fmt.Println("on Chrome, visit chrome://flags/#allow-insecure-localhost")

		} else if https {
			fmt.Println("Enabling HTTPS...")

			go tls.Enable()
			fmt.Printf("Server listening on :%s for HTTPS requests...\n", db.ConfigCache("https_port").(string))
		}

		// save the https port the system is listening on so internal system can make
		// HTTP api calls while in dev or production w/o adding more cli flags
		err = db.PutConfig("http_port", fmt.Sprintf("%d", port))
		if err != nil {
			log.Fatalln("System failed to save config. Please try to run again.", err)
		}

		fmt.Printf("Server listening on :%d for HTTP requests...\n", port)
		fmt.Println("\nvisit `/admin` to get started.")
		log.Fatalln(http.ListenAndServe(fmt.Sprintf(":%d", port), nil))
		return nil
	},
}

func init() {
	for _, cmd := range []*cobra.Command{runCmd, serveCmd} {
		cmd.Flags().IntVar(&port, "port", 8080, "port for ponzu to bind its HTTP listener")
		cmd.Flags().IntVar(&httpsport, "https-port", 443, "port for ponzu to bind its HTTPS listener")
		cmd.Flags().BoolVar(&https, "https", false, "enable automatic TLS/SSL certificate management")
		cmd.Flags().BoolVar(&devhttps, "dev-https", false, "[dev environment] enable automatic TLS/SSL certificate management")
	}

	RegisterCmdlineCommand(runCmd)
	RegisterCmdlineCommand(serveCmd)

	pflags := rootCmd.PersistentFlags()
	pflags.StringVar(&gocmd, "gocmd", "go", "custom go command if using beta or new release of Go")
}

func main() {
	if err := rootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}

func execAndWait(command string, arg ...string) error {
	cmd := exec.Command(command, arg...)
	cmd.Stderr = os.Stderr
	cmd.Stdout = os.Stdout

	err := cmd.Start()
	if err != nil {
		return err

	}
	return cmd.Wait()
}
<|endoftext|>


<commit_before>/*
seqls - list directory contents, rolled up into file sequences
*/
package main

import (
	"bufio"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
	"sync"
	"text/tabwriter"
	"time"

	"github.com/MichaelTJones/walk"
	"github.com/jessevdk/go-flags"
	"github.com/justinfx/gofileseq"
)

var opts struct {
	Recurse   bool `short:"r" long:"recurse" description:"recursively scan all sub-directories"`
	AllFiles  bool `short:"a" long:"all" description:"list all files, including those without frame patterns"`
	LongList  bool `short:"l" long:"long" description:"long listing; include extra stat information"`
	AbsPath   bool `short:"f" long:"full" description:"show absolute paths"`
	HumanSize bool `short:"H" long:"human" description:"when using long listing, show human-readable file size units"`
	Quiet     bool `short:"q" long:"quiet" description:"Don't print errors encountered when reading the file system"`
}

const (
	Version   = fileseq.Version
	DateFmt   = `Jan _2 15:04`
	ErrorPath = `Error: Failed reading path`
)

var (
	// number of goroutines to spawn for processing directories
	// and building FileSequence results
	numWorkers = 50

	errOut io.Writer = os.Stderr
)

func init() {
	// If $GOMAXPROCS isn't set, use the full capacity of the machine.
	// For small machines, use at least 4 threads.
	if os.Getenv("GOMAXPROCS") == "" {
		n := runtime.NumCPU()
		if n < 4 {
			n = 4
		}
		runtime.GOMAXPROCS(n)
	}
}

var usage = fmt.Sprintf(`[options] [path [...]]

Version: %s

List directory contents, rolled up into file sequences.

One or more paths may be provided. If no path is provided, the current
working directory will be scanned.

Only files are shown in listing results.
`, Version)

func main() {
	parser := flags.NewParser(&opts, flags.HelpFlag|flags.PrintErrors)
	parser.Name = "seqls"
	parser.Usage = usage
	roots, err := parser.Parse()

	if err != nil {
		os.Exit(1)
	}

	if opts.Quiet {
		errOut = ioutil.Discard
	}

	if len(roots) == 0 {
		// Use the current directory if specific dirs were not passed
		roots = []string{"."}
	}

	var wg sync.WaitGroup

	pathChan := make(chan string)
	seqChan := make(chan fileseq.FileSequences)

	// fmt.Printf("launching %d workers\n", numWorkers)

	var listerFn func(string) (fileseq.FileSequences, error)
	if opts.AllFiles {
		listerFn = fileseq.ListFiles
	} else {
		listerFn = fileseq.FindSequencesOnDisk
	}

	// Start the workers to find sequences
	for i := 0; i < numWorkers; i++ {
		wg.Add(1)
		go func() {
			for path := range pathChan {
				seqs, err := listerFn(path)
				if err != nil {
					// Bail out of the app for any path error
					fmt.Fprintf(errOut, "%s %q: %s\n", ErrorPath, path, err)
					continue
				}
				seqChan <- seqs
			}
			wg.Done()
		}()
	}

	// Load the root paths into the source channel
	unique := cleanDirs(roots)
	go func() {
		if opts.Recurse {
			loadRecursive(unique, pathChan)
		} else {
			for r := range unique {
				pathChan <- r
			}
		}
		close(pathChan)
	}()

	// Will close the output channel when no more source
	// paths are being added
	go func() {
		wg.Wait()
		close(seqChan)
	}()

	// Pull out all processed sequences and print
	var w io.Writer
	if opts.LongList {
		w = tabwriter.NewWriter(os.Stdout, 5, 0, 2, ' ', 0)
	} else {
		w = bufio.NewWriter(os.Stdout)
	}

	var printer func(io.Writer, *fileseq.FileSequence)
	if opts.LongList {
		printer = printLongListing
	} else {
		printer = printShortListing
	}

	// Start processing the results that are feeding in the channel
	for seqs := range seqChan {
		for _, s := range seqs {
			printer(w, s)
		}
	}

	if opts.LongList {
		// Flush the tabwriter buffer
		w.(*tabwriter.Writer).Flush()
	}
}

// Parallel walk the root paths and populate the path
// channel for the worker routines to consume.
func loadRecursive(roots uniquePaths, out chan string) {
	walkFn := func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return nil
		}

		if info.IsDir() {
			out <- path

		} else if info, err = os.Stat(path); err == nil && info.IsDir() {
			out <- path
		}

		return nil
	}
	for r := range roots {
		r := r
		if err := walk.Walk(r, walkFn); err != nil {
			if err != filepath.SkipDir {
				fmt.Fprintf(errOut, "%s %q: %s\n", ErrorPath, r, err)
			}
		}
	}
}

type uniquePaths map[string]struct{}

// Take a list of paths and reduce them to cleaned
// and unique paths.
func cleanDirs(paths []string) uniquePaths {
	u := make(uniquePaths)
	var (
		fi  os.FileInfo
		err error
	)
	for _, p := range paths {
		p := strings.TrimSpace(filepath.Clean(p))
		if p == "" {
			continue
		}
		if fi, err = os.Stat(p); err != nil {
			fmt.Fprintf(errOut, "%s %q: %s\n", ErrorPath, p, err)
			continue
		}
		if !fi.IsDir() {
			continue
		}
		u[p] = struct{}{}
	}
	return u
}

func printShortListing(w io.Writer, fs *fileseq.FileSequence) {
	str := fs.String()
	if opts.AbsPath {
		abs, err := filepath.Abs(str)
		if err == nil {
			str = abs
		}
	}
	fmt.Fprintln(w, str)
}

func printLongListing(w io.Writer, fs *fileseq.FileSequence) {
	var (
		err      error
		byteSize int64
		stat     os.FileInfo
		str      string
	)

	count := fs.Len()
	if count == 1 {
		// Only a single file
		str = fs.Index(0)
		stat, err = os.Stat(str)
		if err == nil {
			byteSize = stat.Size()
		}

	} else {
		str = fs.String()
		// For a sequence of files, we want to get the most
		// recent modtime, as well as the total size of the
		// combined files.
		mod := time.Unix(0, 0)
		var thisStat os.FileInfo
		var thisStr string
		for i := 0; i < count; i++ {
			thisStr = fs.Index(i)
			thisStat, err = os.Stat(thisStr)
			if err != nil {
				continue
			}
			byteSize += thisStat.Size()
			if thisStat.ModTime().After(mod) {
				stat = thisStat
				mod = thisStat.ModTime()
			}
		}
	}

	if opts.AbsPath {
		abs, err := filepath.Abs(str)
		if err == nil {
			str = abs
		}
	}

	if err != nil {
		fmt.Println(str)
		fmt.Fprintf(errOut, "%s: %s\n", ErrorPath, err.Error())
		return
	}

	var size interface{}
	if opts.HumanSize {
		size = ByteSize(byteSize)
	} else {
		size = byteSize
	}

	printDetails(w, str, stat, size)
}

type ByteSize float64

const (
	_           = iota // ignore first value by assigning to blank identifier
	KB ByteSize = 1 << (10 * iota)
	MB
	GB
	TB
)

func (b ByteSize) String() string {
	switch {
	case b >= TB:
		return fmt.Sprintf("%.1fT", b/TB)
	case b >= GB:
		return fmt.Sprintf("%.1fG", b/GB)
	case b >= MB:
		return fmt.Sprintf("%.1fM", b/MB)
	case b >= KB:
		return fmt.Sprintf("%.1fK", b/KB)
	case b == 0:
		return strconv.Itoa(0)
	}
	return fmt.Sprintf("%.0f", b)
}
<commit_msg>Flush the buffered stdout before app exit<commit_after>/*
seqls - list directory contents, rolled up into file sequences
*/
package main

import (
	"bufio"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
	"sync"
	"text/tabwriter"
	"time"

	"github.com/MichaelTJones/walk"
	"github.com/jessevdk/go-flags"
	"github.com/justinfx/gofileseq"
)

var opts struct {
	Recurse   bool `short:"r" long:"recurse" description:"recursively scan all sub-directories"`
	AllFiles  bool `short:"a" long:"all" description:"list all files, including those without frame patterns"`
	LongList  bool `short:"l" long:"long" description:"long listing; include extra stat information"`
	AbsPath   bool `short:"f" long:"full" description:"show absolute paths"`
	HumanSize bool `short:"H" long:"human" description:"when using long listing, show human-readable file size units"`
	Quiet     bool `short:"q" long:"quiet" description:"Don't print errors encountered when reading the file system"`
}

const (
	Version   = fileseq.Version
	DateFmt   = `Jan _2 15:04`
	ErrorPath = `Error: Failed reading path`
)

var (
	// number of goroutines to spawn for processing directories
	// and building FileSequence results
	numWorkers = 50

	errOut io.Writer = os.Stderr
)

func init() {
	// If $GOMAXPROCS isn't set, use the full capacity of the machine.
	// For small machines, use at least 4 threads.
	if os.Getenv("GOMAXPROCS") == "" {
		n := runtime.NumCPU()
		if n < 4 {
			n = 4
		}
		runtime.GOMAXPROCS(n)
	}
}

var usage = fmt.Sprintf(`[options] [path [...]]

Version: %s

List directory contents, rolled up into file sequences.

One or more paths may be provided. If no path is provided, the current
working directory will be scanned.

Only files are shown in listing results.
`, Version)

func main() {
	parser := flags.NewParser(&opts, flags.HelpFlag|flags.PrintErrors)
	parser.Name = "seqls"
	parser.Usage = usage
	roots, err := parser.Parse()

	if err != nil {
		os.Exit(1)
	}

	if opts.Quiet {
		errOut = ioutil.Discard
	}

	if len(roots) == 0 {
		// Use the current directory if specific dirs were not passed
		roots = []string{"."}
	}

	var wg sync.WaitGroup

	pathChan := make(chan string)
	seqChan := make(chan fileseq.FileSequences)

	// fmt.Printf("launching %d workers\n", numWorkers)

	var listerFn func(string) (fileseq.FileSequences, error)
	if opts.AllFiles {
		listerFn = fileseq.ListFiles
	} else {
		listerFn = fileseq.FindSequencesOnDisk
	}

	// Start the workers to find sequences
	for i := 0; i < numWorkers; i++ {
		wg.Add(1)
		go func() {
			for path := range pathChan {
				seqs, err := listerFn(path)
				if err != nil {
					// Bail out of the app for any path error
					fmt.Fprintf(errOut, "%s %q: %s\n", ErrorPath, path, err)
					continue
				}
				seqChan <- seqs
			}
			wg.Done()
		}()
	}

	// Load the root paths into the source channel
	unique := cleanDirs(roots)
	go func() {
		if opts.Recurse {
			loadRecursive(unique, pathChan)
		} else {
			for r := range unique {
				pathChan <- r
			}
		}
		close(pathChan)
	}()

	// Will close the output channel when no more source
	// paths are being added
	go func() {
		wg.Wait()
		close(seqChan)
	}()

	// Pull out all processed sequences and print
	var w io.Writer
	if opts.LongList {
		w = tabwriter.NewWriter(os.Stdout, 5, 0, 2, ' ', 0)
	} else {
		w = bufio.NewWriter(os.Stdout)
	}

	var printer func(io.Writer, *fileseq.FileSequence)
	if opts.LongList {
		printer = printLongListing
	} else {
		printer = printShortListing
	}

	// Start processing the results that are feeding in the channel
	for seqs := range seqChan {
		for _, s := range seqs {
			printer(w, s)
		}
	}

	if opts.LongList {
		// Flush the tabwriter buffer
		w.(*tabwriter.Writer).Flush()
	} else {
		w.(*bufio.Writer).Flush()
	}
}

// Parallel walk the root paths and populate the path
// channel for the worker routines to consume.
func loadRecursive(roots uniquePaths, out chan string) {
	walkFn := func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return nil
		}

		if info.IsDir() {
			out <- path

		} else if info, err = os.Stat(path); err == nil && info.IsDir() {
			out <- path
		}

		return nil
	}
	for r := range roots {
		r := r
		if err := walk.Walk(r, walkFn); err != nil {
			if err != filepath.SkipDir {
				fmt.Fprintf(errOut, "%s %q: %s\n", ErrorPath, r, err)
			}
		}
	}
}

type uniquePaths map[string]struct{}

// Take a list of paths and reduce them to cleaned
// and unique paths.
func cleanDirs(paths []string) uniquePaths {
	u := make(uniquePaths)
	var (
		fi  os.FileInfo
		err error
	)
	for _, p := range paths {
		p := strings.TrimSpace(filepath.Clean(p))
		if p == "" {
			continue
		}
		if fi, err = os.Stat(p); err != nil {
			fmt.Fprintf(errOut, "%s %q: %s\n", ErrorPath, p, err)
			continue
		}
		if !fi.IsDir() {
			continue
		}
		u[p] = struct{}{}
	}
	return u
}

func printShortListing(w io.Writer, fs *fileseq.FileSequence) {
	str := fs.String()
	if opts.AbsPath {
		abs, err := filepath.Abs(str)
		if err == nil {
			str = abs
		}
	}
	fmt.Fprintln(w, str)
}

func printLongListing(w io.Writer, fs *fileseq.FileSequence) {
	var (
		err      error
		byteSize int64
		stat     os.FileInfo
		str      string
	)

	count := fs.Len()
	if count == 1 {
		// Only a single file
		str = fs.Index(0)
		stat, err = os.Stat(str)
		if err == nil {
			byteSize = stat.Size()
		}

	} else {
		str = fs.String()
		// For a sequence of files, we want to get the most
		// recent modtime, as well as the total size of the
		// combined files.
		mod := time.Unix(0, 0)
		var thisStat os.FileInfo
		var thisStr string
		for i := 0; i < count; i++ {
			thisStr = fs.Index(i)
			thisStat, err = os.Stat(thisStr)
			if err != nil {
				continue
			}
			byteSize += thisStat.Size()
			if thisStat.ModTime().After(mod) {
				stat = thisStat
				mod = thisStat.ModTime()
			}
		}
	}

	if opts.AbsPath {
		abs, err := filepath.Abs(str)
		if err == nil {
			str = abs
		}
	}

	if err != nil {
		fmt.Println(str)
		fmt.Fprintf(errOut, "%s: %s\n", ErrorPath, err.Error())
		return
	}

	var size interface{}
	if opts.HumanSize {
		size = ByteSize(byteSize)
	} else {
		size = byteSize
	}

	printDetails(w, str, stat, size)
}

type ByteSize float64

const (
	_           = iota // ignore first value by assigning to blank identifier
	KB ByteSize = 1 << (10 * iota)
	MB
	GB
	TB
)

func (b ByteSize) String() string {
	switch {
	case b >= TB:
		return fmt.Sprintf("%.1fT", b/TB)
	case b >= GB:
		return fmt.Sprintf("%.1fG", b/GB)
	case b >= MB:
		return fmt.Sprintf("%.1fM", b/MB)
	case b >= KB:
		return fmt.Sprintf("%.1fK", b/KB)
	case b == 0:
		return strconv.Itoa(0)
	}
	return fmt.Sprintf("%.0f", b)
}
<|endoftext|>


<commit_before>/* Copyright (c) 2015, Daniel Martí <mvdan@mvdan.cc> */
/* See LICENSE for licensing information */

package main

import (
	"bufio"
	"fmt"
	"os"

	"github.com/mvdan/xurls"
)

func main() {
	re := xurls.All
	scanner := bufio.NewScanner(os.Stdin)
	scanner.Split(bufio.ScanWords)
	for scanner.Scan() {
		word := scanner.Text()
		matches := re.FindAllString(word, -1)
		for _, match := range matches {
			fmt.Println(match)
		}
	}
}
<commit_msg>Add strict flag (fixes #2)<commit_after>/* Copyright (c) 2015, Daniel Martí <mvdan@mvdan.cc> */
/* See LICENSE for licensing information */

package main

import (
	"bufio"
	"flag"
	"fmt"
	"os"

	"github.com/mvdan/xurls"
)

var strict = flag.Bool("s", false, "match urls with scheme only (strict)")

func main() {
	flag.Parse()
	re := xurls.All
	if *strict {
		re = xurls.AllStrict
	}
	scanner := bufio.NewScanner(os.Stdin)
	scanner.Split(bufio.ScanWords)
	for scanner.Scan() {
		word := scanner.Text()
		matches := re.FindAllString(word, -1)
		for _, match := range matches {
			fmt.Println(match)
		}
	}
}
<|endoftext|>


<commit_before>package util

import (
	bigv "bigv.io/client/lib"
	"bigv.io/client/util/log"
	auth3 "bytemark.co.uk/auth3/client"
	"fmt"
	"net"
	"net/url"
	"os"
	"runtime"
	"strings"
	"syscall"
)

type UserRequestedExit struct{}

func (e *UserRequestedExit) Error() string {
	return "User requested exit"
}

// ExitCode is a named type for the E_* constants which are used as exit codes.
type ExitCode int

const (
	// E_USAGE_DISPLAYED is returned when some usage info / help page was displayed. Unsure whether it should == E_SUCCESS or not
	E_USAGE_DISPLAYED ExitCode = 0
	// E_SUCCESS is used to say everything went well
	E_SUCCESS = 0
	// E_TRAPPED_INTERRUPT is the exit code returned when an unexpected interrupt like SIGUSR1 was trapped
	E_TRAPPED_INTERRUPT = -1
	// E_CANT_READ_CONFIG is the exit code returned when we couldn't read a config variable from the disk for some reason
	E_CANT_READ_CONFIG = 3
	// E_CANT_WRITE_CONFIG is the exit code returned when we couldn't write a config variable to the disk for some reason
	E_CANT_WRITE_CONFIG = 4
	// E_USER_EXIT is the exit code returned when the user's action caused the program to terminate (usually by saying no to a prompt)
	E_USER_EXIT = 5
	// E_WONT_DELETE_NONEMPTY is the exit code returned when the user's requested that a group be deleted when it still had virtual machines in
	E_WONT_DELETE_NONEMPTY = 6
	// E_PEBKAC is the exit code returned when the user entered a malformed command, name, or flag.
	E_PEBKAC = 7
	// E_SUBPROCESS_FAILED is the exit code returned when the client attempted to run a subprocess (e.g. ssh, a browser or a vpn client) but couldn't
	E_SUBPROCESS_FAILED = 8

	// E_UNKNOWN_ERROR is the exit code returned when we got an error we couldn't deal with.
	E_UNKNOWN_ERROR = 49

	// E_CANT_CONNECT_AUTH is the exit code returned when we were unable to establish an HTTP connection to the auth endpoint.
	E_CANT_CONNECT_AUTH = 50
	// E_CANT_CONNECT_BIGV is the exit code returned when we were unable to establish an HTTP connection to the BigV endpoint.
	E_CANT_CONNECT_BIGV = 150

	// E_AUTH_REPORTED_ERROR is the exit code returned when the auth server reported an internal error.
	E_AUTH_REPORTED_ERROR = 51
	// E_BIGV_REPORTED_ERROR is the exit code returned when the BigV server reported an internal error.
	E_BIGV_REPORTED_ERROR = 152

	// E_CANT_PARSE_AUTH is the exit code returned when the auth server returned something we were unable to parse.
	E_CANT_PARSE_AUTH = 52
	// E_CANT_PARSE_BIGV is the exit code returned when the BigV server returned something we were unable to parse.
	E_CANT_PARSE_BIGV = 152

	// E_CREDENTIALS_INVALID is the exit code returned when the auth server says your credentials contain invalid characters.
	E_CREDENTIALS_INVALID = 53
	// E_CREDENTIALS_WRONG is the exit code returned when the auth server says your credentials don't match a user in its database.
	E_CREDENTIALS_WRONG = 54

	// E_NOT_AUTHORIZED_BIGV is the exit code returned when the BigV server says you haven't got permission to do that.
	E_NOT_AUTHORIZED_BIGV = 155

	// E_NOT_FOUND_BIGV is the exit code returned when the BigV server says you do not have permission to see the object you are trying to view, or that it does not exist.
	E_NOT_FOUND_BIGV = 156

	// E_UNKNOWN_AUTH is the exit code returned when we get an unexpected error from the auth server.
	E_UNKNOWN_AUTH = 149
	// E_UNKNOWN_BIGV is the exit code returned when we get an unexpected error from the BigV server.
	E_UNKNOWN_BIGV = 249
)

// HelpForExitCodes prints readable information on what the various exit codes do.
func HelpForExitCodes() ExitCode {
	log.Logf(`bigv exit code list:

Exit code ranges:
    All these ranges are inclusive (i.e. 0-99 means numbers from 0 to 99, including 0 and 99.)

      0- 49: local problems
     50-149: problem talking to auth.
    150-249: problem talking to BigV.
    250-255: interrupts & signals

    Exit codes between 50 and 249 with the same tens and units have the same meaning but for a different endpoint

  0 -  49 Exit codes:

    0
	Nothing went wrong and I feel great!

    3
	Couldn't read a file from config directory

    4
	Couldn't write a file to config directory
    5
	The user caused the program to exit (usually by saying "no" to Yes/no prompts)
    6
	The user requested a non-empty group be deleted
    7
	The program was called with malformed arguments
    8
	Attempting to execute a subprocess failed

 50 - 249 Exit codes:

     50 / 150
        Unable to establish a connection to auth/BigV endpoint

     51 / 151
        Auth endpoint reported an internal error

     52 / 152
        Unable to parse output from auth endpoint (probably implies a protocol mismatch - try updating go-bigv)

     53
	Your credentials were rejected for containing invalid characters or fields.

     54
	Your credentials did not match any user on file - check you entered them correctly

    155
	Your user account doesn't have authorisation to perform that action

    156
        Something couldn't be found on BigV. This could be due to the following reasons:
            * It doesn't exist
	    * Your user account doesn't have authorisation to see it
	    * Protocol mismatch between the BigV endpoint and go-bigv.

    149 / 249

        An unknown error fell out of the auth / bigv library.

250 - 255 Exit codes:

    255
	Trapped an interrupt signal, so exited.
`)
	return E_USAGE_DISPLAYED
}

func ProcessError(err error, message ...string) ExitCode {
	trace := make([]byte, 0, 4096)
	runtime.Stack(trace, false)

	log.Debug(1, "ProcessError called. Dumping arguments and stacktrace", os.Args, trace)
	if len(message) > 0 {
		log.Error(message)
	} else if err == nil {
		return E_SUCCESS
	}
	errorMessage := "Unknown error"
	exitCode := ExitCode(E_UNKNOWN_ERROR)
	if err != nil {
		switch err.(type) {
		case *auth3.Error:
			// TODO(telyn): I feel like this entire chunk should be in bytemark.co.uk/auth3/client
			authErr, _ := err.(*auth3.Error)
			switch authErr.Err.(type) {
			case *url.Error:
				urlErr, _ := authErr.Err.(*url.Error)
				if urlErr.Error != nil {
					if opError, ok := urlErr.Err.(*net.OpError); ok {
						errorMessage = fmt.Sprintf("Couldn't connect to the auth server: %v", opError.Err)
					} else {
						errorMessage = fmt.Sprintf("Couldn't connect to the auth server: %T %v\r\nPlease file a bug report quoting this message.", urlErr.Err, urlErr.Err)
					}
				} else {
					errorMessage = fmt.Sprintf("Couldn't connect to the auth server: %v", urlErr)
				}
				exitCode = E_CANT_CONNECT_AUTH
			default:
				errorMessage = fmt.Sprintf("Couldn't create auth session - internal error of type %T: %v", authErr.Err, authErr.Err)
				exitCode = E_UNKNOWN_AUTH
			}
		case *url.Error:
			urlErr, _ := err.(*url.Error)
			if urlErr.Error != nil {
				if opError, ok := urlErr.Err.(*net.OpError); ok {
					errorMessage = fmt.Sprintf("Couldn't connect to the BigV api server: %v", opError.Err)
				} else {
					errorMessage = fmt.Sprintf("Couldn't connect to the BigV api server: %T %v\r\nPlease file a bug report quoting this message.", urlErr.Err, urlErr.Err)
				}
			} else {
				errorMessage = fmt.Sprintf("Couldn't connect to the BigV api server: %v", urlErr)
			}
		case *SubprocessFailedError:
			errorMessage = err.Error()
			exitCode = E_SUBPROCESS_FAILED
		case bigv.NotAuthorizedError:
			errorMessage = err.Error()
			exitCode = E_NOT_AUTHORIZED_BIGV

		case bigv.NotFoundError:
			errorMessage = err.Error()
			exitCode = E_NOT_FOUND_BIGV
		case *UserRequestedExit:
			errorMessage = ""
			exitCode = E_USER_EXIT
		case syscall.Errno:
			errno, _ := err.(*syscall.Errno)
			errorMessage = fmt.Sprintf("A command we tried to execute failed. The operating system gave us the error code %d", errno)
			exitCode = E_UNKNOWN_ERROR
		default:
			e := err.Error()
			if strings.Contains(e, "Badly-formed parameters") {
				exitCode = E_CREDENTIALS_INVALID
				errorMessage = "The supplied credentials contained invalid characters - please try again"
			} else if strings.Contains(e, "Bad login credentials") {
				exitCode = E_CREDENTIALS_WRONG
				errorMessage = "A user account with those credentials could not be found. Check your details and try again"

			}
		}

		if _, ok := err.(bigv.BigVError); ok && exitCode == E_UNKNOWN_ERROR {
			errorMessage = fmt.Sprintf("Unknown error from BigV client library.%s", err.Error())
			exitCode = E_UNKNOWN_BIGV
		}
	} else {
		exitCode = 0
	}

	if exitCode == E_UNKNOWN_ERROR {
		log.Errorf("Unknown error of type %T: %s.\r\nPlease send a bug report containing %s to support@bytemark.co.uk.\r\n", err, err, log.LogFile.Name())
	} else if len(message) == 0 { // the message (passed as argument) is shadowed by errorMessage (made in this function)
		log.Log(errorMessage)

	}
	return exitCode
}
<commit_msg>Sort out ProcessError's backtrace<commit_after>package util

import (
	bigv "bigv.io/client/lib"
	"bigv.io/client/util/log"
	auth3 "bytemark.co.uk/auth3/client"
	"fmt"
	"net"
	"net/url"
	"os"
	"runtime"
	"strings"
	"syscall"
)

type UserRequestedExit struct{}

func (e *UserRequestedExit) Error() string {
	return "User requested exit"
}

// ExitCode is a named type for the E_* constants which are used as exit codes.
type ExitCode int

const (
	// E_USAGE_DISPLAYED is returned when some usage info / help page was displayed. Unsure whether it should == E_SUCCESS or not
	E_USAGE_DISPLAYED ExitCode = 0
	// E_SUCCESS is used to say everything went well
	E_SUCCESS = 0
	// E_TRAPPED_INTERRUPT is the exit code returned when an unexpected interrupt like SIGUSR1 was trapped
	E_TRAPPED_INTERRUPT = -1
	// E_CANT_READ_CONFIG is the exit code returned when we couldn't read a config variable from the disk for some reason
	E_CANT_READ_CONFIG = 3
	// E_CANT_WRITE_CONFIG is the exit code returned when we couldn't write a config variable to the disk for some reason
	E_CANT_WRITE_CONFIG = 4
	// E_USER_EXIT is the exit code returned when the user's action caused the program to terminate (usually by saying no to a prompt)
	E_USER_EXIT = 5
	// E_WONT_DELETE_NONEMPTY is the exit code returned when the user's requested that a group be deleted when it still had virtual machines in
	E_WONT_DELETE_NONEMPTY = 6
	// E_PEBKAC is the exit code returned when the user entered a malformed command, name, or flag.
	E_PEBKAC = 7
	// E_SUBPROCESS_FAILED is the exit code returned when the client attempted to run a subprocess (e.g. ssh, a browser or a vpn client) but couldn't
	E_SUBPROCESS_FAILED = 8

	// E_UNKNOWN_ERROR is the exit code returned when we got an error we couldn't deal with.
	E_UNKNOWN_ERROR = 49

	// E_CANT_CONNECT_AUTH is the exit code returned when we were unable to establish an HTTP connection to the auth endpoint.
	E_CANT_CONNECT_AUTH = 50
	// E_CANT_CONNECT_BIGV is the exit code returned when we were unable to establish an HTTP connection to the BigV endpoint.
	E_CANT_CONNECT_BIGV = 150

	// E_AUTH_REPORTED_ERROR is the exit code returned when the auth server reported an internal error.
	E_AUTH_REPORTED_ERROR = 51
	// E_BIGV_REPORTED_ERROR is the exit code returned when the BigV server reported an internal error.
	E_BIGV_REPORTED_ERROR = 152

	// E_CANT_PARSE_AUTH is the exit code returned when the auth server returned something we were unable to parse.
	E_CANT_PARSE_AUTH = 52
	// E_CANT_PARSE_BIGV is the exit code returned when the BigV server returned something we were unable to parse.
	E_CANT_PARSE_BIGV = 152

	// E_CREDENTIALS_INVALID is the exit code returned when the auth server says your credentials contain invalid characters.
	E_CREDENTIALS_INVALID = 53
	// E_CREDENTIALS_WRONG is the exit code returned when the auth server says your credentials don't match a user in its database.
	E_CREDENTIALS_WRONG = 54

	// E_NOT_AUTHORIZED_BIGV is the exit code returned when the BigV server says you haven't got permission to do that.
	E_NOT_AUTHORIZED_BIGV = 155

	// E_NOT_FOUND_BIGV is the exit code returned when the BigV server says you do not have permission to see the object you are trying to view, or that it does not exist.
	E_NOT_FOUND_BIGV = 156

	// E_UNKNOWN_AUTH is the exit code returned when we get an unexpected error from the auth server.
	E_UNKNOWN_AUTH = 149
	// E_UNKNOWN_BIGV is the exit code returned when we get an unexpected error from the BigV server.
	E_UNKNOWN_BIGV = 249
)

// HelpForExitCodes prints readable information on what the various exit codes do.
func HelpForExitCodes() ExitCode {
	log.Logf(`bigv exit code list:

Exit code ranges:
    All these ranges are inclusive (i.e. 0-99 means numbers from 0 to 99, including 0 and 99.)

      0- 49: local problems
     50-149: problem talking to auth.
    150-249: problem talking to BigV.
    250-255: interrupts & signals

    Exit codes between 50 and 249 with the same tens and units have the same meaning but for a different endpoint

  0 -  49 Exit codes:

    0
	Nothing went wrong and I feel great!

    3
	Couldn't read a file from config directory

    4
	Couldn't write a file to config directory
    5
	The user caused the program to exit (usually by saying "no" to Yes/no prompts)
    6
	The user requested a non-empty group be deleted
    7
	The program was called with malformed arguments
    8
	Attempting to execute a subprocess failed

 50 - 249 Exit codes:

     50 / 150
        Unable to establish a connection to auth/BigV endpoint

     51 / 151
        Auth endpoint reported an internal error

     52 / 152
        Unable to parse output from auth endpoint (probably implies a protocol mismatch - try updating go-bigv)

     53
	Your credentials were rejected for containing invalid characters or fields.

     54
	Your credentials did not match any user on file - check you entered them correctly

    155
	Your user account doesn't have authorisation to perform that action

    156
        Something couldn't be found on BigV. This could be due to the following reasons:
            * It doesn't exist
	    * Your user account doesn't have authorisation to see it
	    * Protocol mismatch between the BigV endpoint and go-bigv.

    149 / 249

        An unknown error fell out of the auth / bigv library.

250 - 255 Exit codes:

    255
	Trapped an interrupt signal, so exited.
`)
	return E_USAGE_DISPLAYED
}

func ProcessError(err error, message ...string) ExitCode {
	trace := make([]byte, 4096, 4096)
	runtime.Stack(trace, false)

	log.Debug(1, "ProcessError called. Dumping arguments and stacktrace", os.Args, string(trace))
	if len(message) > 0 {
		log.Error(message)
	} else if err == nil {
		return E_SUCCESS
	}
	errorMessage := "Unknown error"
	exitCode := ExitCode(E_UNKNOWN_ERROR)
	if err != nil {
		switch err.(type) {
		case *auth3.Error:
			// TODO(telyn): I feel like this entire chunk should be in bytemark.co.uk/auth3/client
			authErr, _ := err.(*auth3.Error)
			switch authErr.Err.(type) {
			case *url.Error:
				urlErr, _ := authErr.Err.(*url.Error)
				if urlErr.Error != nil {
					if opError, ok := urlErr.Err.(*net.OpError); ok {
						errorMessage = fmt.Sprintf("Couldn't connect to the auth server: %v", opError.Err)
					} else {
						errorMessage = fmt.Sprintf("Couldn't connect to the auth server: %T %v\r\nPlease file a bug report quoting this message.", urlErr.Err, urlErr.Err)
					}
				} else {
					errorMessage = fmt.Sprintf("Couldn't connect to the auth server: %v", urlErr)
				}
				exitCode = E_CANT_CONNECT_AUTH
			default:
				errorMessage = fmt.Sprintf("Couldn't create auth session - internal error of type %T: %v", authErr.Err, authErr.Err)
				exitCode = E_UNKNOWN_AUTH
			}
		case *url.Error:
			urlErr, _ := err.(*url.Error)
			if urlErr.Error != nil {
				if opError, ok := urlErr.Err.(*net.OpError); ok {
					errorMessage = fmt.Sprintf("Couldn't connect to the BigV api server: %v", opError.Err)
				} else {
					errorMessage = fmt.Sprintf("Couldn't connect to the BigV api server: %T %v\r\nPlease file a bug report quoting this message.", urlErr.Err, urlErr.Err)
				}
			} else {
				errorMessage = fmt.Sprintf("Couldn't connect to the BigV api server: %v", urlErr)
			}
		case *SubprocessFailedError:
			errorMessage = err.Error()
			exitCode = E_SUBPROCESS_FAILED
		case bigv.NotAuthorizedError:
			errorMessage = err.Error()
			exitCode = E_NOT_AUTHORIZED_BIGV

		case bigv.NotFoundError:
			errorMessage = err.Error()
			exitCode = E_NOT_FOUND_BIGV
		case *UserRequestedExit:
			errorMessage = ""
			exitCode = E_USER_EXIT
		case syscall.Errno:
			errno, _ := err.(*syscall.Errno)
			errorMessage = fmt.Sprintf("A command we tried to execute failed. The operating system gave us the error code %d", errno)
			exitCode = E_UNKNOWN_ERROR
		default:
			e := err.Error()
			if strings.Contains(e, "Badly-formed parameters") {
				exitCode = E_CREDENTIALS_INVALID
				errorMessage = "The supplied credentials contained invalid characters - please try again"
			} else if strings.Contains(e, "Bad login credentials") {
				exitCode = E_CREDENTIALS_WRONG
				errorMessage = "A user account with those credentials could not be found. Check your details and try again"

			}
		}

		if _, ok := err.(bigv.BigVError); ok && exitCode == E_UNKNOWN_ERROR {
			errorMessage = fmt.Sprintf("Unknown error from BigV client library.%s", err.Error())
			exitCode = E_UNKNOWN_BIGV
		}
	} else {
		exitCode = 0
	}

	if exitCode == E_UNKNOWN_ERROR {
		log.Errorf("Unknown error of type %T: %s.\r\nPlease send a bug report containing %s to support@bytemark.co.uk.\r\n", err, err, log.LogFile.Name())
	} else if len(message) == 0 { // the message (passed as argument) is shadowed by errorMessage (made in this function)
		log.Log(errorMessage)

	}
	return exitCode
}
<|endoftext|>


<commit_before>// Copyright 2017 the u-root 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 main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"regexp"
	"strings"

	"github.com/u-root/u-root/pkg/wpa/passphrase"
)

const (
	cmd          = "wifi [options] essid [passphrase] [identity]"
	nopassphrase = `network={
		ssid="%s"
		proto=RSN
		key_mgmt=NONE
	}`
	eap = `network={
		ssid="%s"
		key_mgmt=WPA-EAP
		identity="%s"WPA Version
		password="%s"
	}`
)

var (
	CellRE       = regexp.MustCompile("(?m)^\\s*Cell")
	EssidRE      = regexp.MustCompile("(?m)^\\s*ESSID.*")
	EncKeyOptRE  = regexp.MustCompile("(?m)^\\s*Encryption key:(on|off)$")
	Wpa2RE       = regexp.MustCompile("(?m)^\\s*IE: IEEE 802.11i/WPA2 Version 1$")
	AuthSuitesRE = regexp.MustCompile("(?m)^\\s*Authentication Suites .*$")
)

func init() {
	defUsage := flag.Usage
	flag.Usage = func() {
		os.Args[0] = cmd
		defUsage()
	}
}

/*
 * Assumptions:
 *  1) Cell, essid, and encryption key option are 1:1 match
 *	2) We only support IEEE 802.11i/WPA2 Version 1
 *	3) Each WiFi only support (1) authentication suites (based on observations)
 */

func parseIwlistOut(o []byte) []WifiOption {
	cells := CellRE.FindAllIndex(o, -1)
	essids := EssidRE.FindAll(o, -1)
	encKeyOpts := EncKeyOptRE.FindAll(o, -1)

	if cells == nil {
		return nil
	}

	var res []WifiOption
	knownEssids := make(map[string]bool)

	// Assemble all the WiFi options
	for i := 0; i < len(cells); i++ {
		essid := strings.Trim(strings.Split(string(essids[i]), ":")[1], "\"\n")
		if knownEssids[essid] {
			continue
		}
		knownEssids[essid] = true
		encKeyOpt := strings.Trim(strings.Split(string(encKeyOpts[i]), ":")[1], "\n")
		if encKeyOpt == "off" {
			res = append(res, WifiOption{essid, NoEnc})
			continue
		}
		// Find the proper Authentication Suites
		start, end := cells[i][0], len(o)
		if i != len(cells)-1 {
			end = cells[i+1][0]
		}
		// Narrow down the scope when looking for WPA Tag
		wpa2SearchArea := o[start:end]
		l := Wpa2RE.FindIndex(wpa2SearchArea)
		if l == nil {
			res = append(res, WifiOption{essid, NotSupportedProto})
			continue
		}
		// Narrow down the scope when looking for Authorization Suites
		authSearchArea := wpa2SearchArea[l[0]:len(wpa2SearchArea)]
		authSuites := strings.Trim(strings.Split(string(AuthSuitesRE.Find(authSearchArea)), ":")[1], "\n ")
		switch authSuites {
		case "PSK":
			res = append(res, WifiOption{essid, WpaPsk})
		case "802.1x":
			res = append(res, WifiOption{essid, WpaEap})
		default:
			res = append(res, WifiOption{essid, NotSupportedProto})
		}
	}
	return res
}

func generateConfig(a ...string) (conf []byte, err error) {
	// format of a: [essid, pass, id]
	switch {
	case len(a) == 3:
		conf = []byte(fmt.Sprintf(eap, a[0], a[2], a[1]))
	case len(a) == 2:
		conf, err = passphrase.Run(a[0], a[1])
		if err != nil {
			return nil, fmt.Errorf("essid: %v, pass: %v : %v", a[0], a[1], err)
		}
	case len(a) == 1:
		conf = []byte(fmt.Sprintf(nopassphrase, a[0]))
	default:
		return nil, fmt.Errorf("generateConfig needs 1, 2, or 3 args")
	}
	return
}

func main() {
	go startServer()

	// Service
	var (
		iface = flag.String("i", "wlan0", "interface to use")
		list  = flag.Bool("l", false, "list all nearby WiFi")
		conf  []byte
		err   error
	)

	flag.Parse()

	if *list {
		o, err := exec.Command("iwlist", *iface, "scanning").CombinedOutput()
		if err != nil {
			log.Fatalf("iwlist: %v (%v)", string(o), err)
		}
		wifiOpts := parseIwlistOut(o)
		for _, wifiOpt := range wifiOpts {
			switch wifiOpt.AuthSuite {
			case NoEnc:
				fmt.Printf("%s: No Passphrase\n", wifiOpt.Essid)
			case WpaPsk:
				fmt.Printf("%s: WPA-PSK (only passphrase)\n", wifiOpt.Essid)
			case WpaEap:
				fmt.Printf("%s: WPA-EAP (passphrase and identity)\n", wifiOpt.Essid)
			case NotSupportedProto:
				fmt.Printf("%s: Not a supported protocol\n", wifiOpt.Essid)
			}
		}
		return
	}

	a := flag.Args()

	if len(a) == 0 {
		// Experimental Part
		// if len(a) = 0, can use the web interface to get user's input
		a = (<-UserInputChannel).args
		stubMsg := StatusMessage{
			essid: a[0],
		}

		StatusChannel <- stubMsg
		_ = <-UserInputChannel // (Experimental) So we can see the result of the page load
	}

	conf, err = generateConfig(a...)
	if err != nil {
		flag.Usage()
		log.Fatalf("error: %v", err)
	}

	if err := ioutil.WriteFile("/tmp/wifi.conf", conf, 0444); err != nil {
		log.Fatalf("/tmp/wifi.conf: %v", err)
	}

	// There's no telling how long the supplicant will take, but on the other hand,
	// it's been almost instantaneous. But, further, it needs to keep running.
	go func() {
		if o, err := exec.Command("wpa_supplicant", "-i"+*iface, "-c/tmp/wifi.conf").CombinedOutput(); err != nil {
			log.Fatalf("wpa_supplicant: %v (%v)", o, err)
		}
	}()

	cmd := exec.Command("dhclient", "-ipv4=true", "-ipv6=false", "-verbose", *iface)
	cmd.Stdout, cmd.Stderr = os.Stdout, os.Stderr
	if err := cmd.Run(); err != nil {
		log.Fatalf("%v: %v", cmd, err)
	}
}
<commit_msg>Fixed typo<commit_after>// Copyright 2017 the u-root 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 main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"regexp"
	"strings"

	"github.com/u-root/u-root/pkg/wpa/passphrase"
)

const (
	cmd          = "wifi [options] essid [passphrase] [identity]"
	nopassphrase = `network={
		ssid="%s"
		proto=RSN
		key_mgmt=NONE
	}`
	eap = `network={
		ssid="%s"
		key_mgmt=WPA-EAP
		identity="%s"
		password="%s"
	}`
)

var (
	CellRE       = regexp.MustCompile("(?m)^\\s*Cell")
	EssidRE      = regexp.MustCompile("(?m)^\\s*ESSID.*")
	EncKeyOptRE  = regexp.MustCompile("(?m)^\\s*Encryption key:(on|off)$")
	Wpa2RE       = regexp.MustCompile("(?m)^\\s*IE: IEEE 802.11i/WPA2 Version 1$")
	AuthSuitesRE = regexp.MustCompile("(?m)^\\s*Authentication Suites .*$")
)

func init() {
	defUsage := flag.Usage
	flag.Usage = func() {
		os.Args[0] = cmd
		defUsage()
	}
}

/*
 * Assumptions:
 *  1) Cell, essid, and encryption key option are 1:1 match
 *	2) We only support IEEE 802.11i/WPA2 Version 1
 *	3) Each WiFi only support (1) authentication suites (based on observations)
 */

func parseIwlistOut(o []byte) []WifiOption {
	cells := CellRE.FindAllIndex(o, -1)
	essids := EssidRE.FindAll(o, -1)
	encKeyOpts := EncKeyOptRE.FindAll(o, -1)

	if cells == nil {
		return nil
	}

	var res []WifiOption
	knownEssids := make(map[string]bool)

	// Assemble all the WiFi options
	for i := 0; i < len(cells); i++ {
		essid := strings.Trim(strings.Split(string(essids[i]), ":")[1], "\"\n")
		if knownEssids[essid] {
			continue
		}
		knownEssids[essid] = true
		encKeyOpt := strings.Trim(strings.Split(string(encKeyOpts[i]), ":")[1], "\n")
		if encKeyOpt == "off" {
			res = append(res, WifiOption{essid, NoEnc})
			continue
		}
		// Find the proper Authentication Suites
		start, end := cells[i][0], len(o)
		if i != len(cells)-1 {
			end = cells[i+1][0]
		}
		// Narrow down the scope when looking for WPA Tag
		wpa2SearchArea := o[start:end]
		l := Wpa2RE.FindIndex(wpa2SearchArea)
		if l == nil {
			res = append(res, WifiOption{essid, NotSupportedProto})
			continue
		}
		// Narrow down the scope when looking for Authorization Suites
		authSearchArea := wpa2SearchArea[l[0]:len(wpa2SearchArea)]
		authSuites := strings.Trim(strings.Split(string(AuthSuitesRE.Find(authSearchArea)), ":")[1], "\n ")
		switch authSuites {
		case "PSK":
			res = append(res, WifiOption{essid, WpaPsk})
		case "802.1x":
			res = append(res, WifiOption{essid, WpaEap})
		default:
			res = append(res, WifiOption{essid, NotSupportedProto})
		}
	}
	return res
}

func generateConfig(a ...string) (conf []byte, err error) {
	// format of a: [essid, pass, id]
	switch {
	case len(a) == 3:
		conf = []byte(fmt.Sprintf(eap, a[0], a[2], a[1]))
	case len(a) == 2:
		conf, err = passphrase.Run(a[0], a[1])
		if err != nil {
			return nil, fmt.Errorf("essid: %v, pass: %v : %v", a[0], a[1], err)
		}
	case len(a) == 1:
		conf = []byte(fmt.Sprintf(nopassphrase, a[0]))
	default:
		return nil, fmt.Errorf("generateConfig needs 1, 2, or 3 args")
	}
	return
}

func main() {
	go startServer()

	// Service
	var (
		iface = flag.String("i", "wlan0", "interface to use")
		list  = flag.Bool("l", false, "list all nearby WiFi")
		conf  []byte
		err   error
	)

	flag.Parse()

	if *list {
		o, err := exec.Command("iwlist", *iface, "scanning").CombinedOutput()
		if err != nil {
			log.Fatalf("iwlist: %v (%v)", string(o), err)
		}
		wifiOpts := parseIwlistOut(o)
		for _, wifiOpt := range wifiOpts {
			switch wifiOpt.AuthSuite {
			case NoEnc:
				fmt.Printf("%s: No Passphrase\n", wifiOpt.Essid)
			case WpaPsk:
				fmt.Printf("%s: WPA-PSK (only passphrase)\n", wifiOpt.Essid)
			case WpaEap:
				fmt.Printf("%s: WPA-EAP (passphrase and identity)\n", wifiOpt.Essid)
			case NotSupportedProto:
				fmt.Printf("%s: Not a supported protocol\n", wifiOpt.Essid)
			}
		}
		return
	}

	a := flag.Args()

	if len(a) == 0 {
		// Experimental Part
		// if len(a) = 0, can use the web interface to get user's input
		a = (<-UserInputChannel).args
		stubMsg := StatusMessage{
			essid: a[0],
		}

		StatusChannel <- stubMsg
		_ = <-UserInputChannel // (Experimental) So we can see the result of the page load
	}

	conf, err = generateConfig(a...)
	if err != nil {
		flag.Usage()
		log.Fatalf("error: %v", err)
	}

	if err := ioutil.WriteFile("/tmp/wifi.conf", conf, 0444); err != nil {
		log.Fatalf("/tmp/wifi.conf: %v", err)
	}

	// There's no telling how long the supplicant will take, but on the other hand,
	// it's been almost instantaneous. But, further, it needs to keep running.
	go func() {
		if o, err := exec.Command("wpa_supplicant", "-i"+*iface, "-c/tmp/wifi.conf").CombinedOutput(); err != nil {
			log.Fatalf("wpa_supplicant: %v (%v)", o, err)
		}
	}()

	cmd := exec.Command("dhclient", "-ipv4=true", "-ipv6=false", "-verbose", *iface)
	cmd.Stdout, cmd.Stderr = os.Stdout, os.Stderr
	if err := cmd.Run(); err != nil {
		log.Fatalf("%v: %v", cmd, err)
	}
}
<|endoftext|>


<commit_before>package zipkintracer

import (
	"github.com/apache/thrift/lib/go/thrift"
	"net/http"

	"github.com/openzipkin/zipkin-go-opentracing/_thrift/gen-go/zipkincore"
	"strings"
	"time"
)

const defaultMaxAsyncQueueSize = 64

// Default timeout for http request in seconds
const defaultHTTPTimeout = time.Second * 5

// HTTPCollector implements Collector by forwarding spans to a http server.
type HTTPCollector struct {
	logger          Logger
	url             string
	client          *http.Client
	asyncInputQueue chan *zipkincore.Span
	quit            chan struct{}
}

// HTTPOption sets a parameter for the HttpCollector
type HTTPOption func(c *HTTPCollector)

// HTTPLogger sets the logger used to report errors in the collection
// process. By default, a no-op logger is used, i.e. no errors are logged
// anywhere. It's important to set this option in a production service.
func HTTPLogger(logger Logger) HTTPOption {
	return func(c *HTTPCollector) { c.logger = logger }
}

// HTTPMaxAsyncQueueSize sets the maximum buffer size for the async queue.
func HTTPMaxAsyncQueueSize(size int) HTTPOption {
	return func(c *HTTPCollector) { c.asyncInputQueue = make(chan *zipkincore.Span, size) }
}

// HTTPTimeout sets maximum timeout for http request.
func HTTPTimeout(duration time.Duration) HTTPOption {
	return func(c *HTTPCollector) { c.client.Timeout = duration }
}

// NewHTTPCollector returns a new HTTP-backend Collector. url should be a http
// url for handle post request. timeout is passed to http client. queueSize control
// the maximum size of buffer of async queue. The logger is used to log errors,
// such as send failures;
func NewHTTPCollector(url string, options ...HTTPOption) (Collector, error) {
	c := &HTTPCollector{
		logger:          NewNopLogger(),
		url:             url,
		client:          &http.Client{Timeout: defaultHTTPTimeout},
		asyncInputQueue: make(chan *zipkincore.Span, defaultMaxAsyncQueueSize),
		quit:            make(chan struct{}, 1),
	}

	for _, option := range options {
		option(c)
	}
	go c.loop()
	return c, nil
}

// Collect implements Collector.
func (c *HTTPCollector) Collect(s *zipkincore.Span) error {
	c.asyncInputQueue <- s
	return nil
}

// Close implements Collector.
func (c *HTTPCollector) Close() error {
	c.quit <- struct{}{}
	return nil
}

func httpSerialize(s *zipkincore.Span) []byte {
	t := thrift.NewTMemoryBuffer()
	p := thrift.NewTBinaryProtocolTransport(t)
	if err := p.WriteListBegin(thrift.STRUCT, 1); err != nil {
		panic(err)
	}
	if err := s.Write(p); err != nil {
		panic(err)
	}
	if err := p.WriteListEnd(); err != nil {
		panic(err)
	}
	return t.Buffer.Bytes()
}

func (c *HTTPCollector) loop() {
	for {
		select {
		case span := <-c.asyncInputQueue:
			req, err := http.NewRequest(
				"POST",
				c.url,
				strings.NewReader(string(httpSerialize(span))))
			if err != nil {
				_ = c.logger.Log("err", err.Error())
			}
			req.Header.Set("Content-Type", "application/x-thrift")

			go func() {
				_, err := c.client.Do(req)
				if err != nil {
					_ = c.logger.Log("err", err.Error())
				}
			}()
		case <-c.quit:
			return
		}
	}
}
<commit_msg>drop packet is serialize failed<commit_after>package zipkintracer

import (
	"github.com/apache/thrift/lib/go/thrift"
	"net/http"

	"github.com/openzipkin/zipkin-go-opentracing/_thrift/gen-go/zipkincore"
	"strings"
	"time"
)

const defaultMaxAsyncQueueSize = 64

// Default timeout for http request in seconds
const defaultHTTPTimeout = time.Second * 5

// HTTPCollector implements Collector by forwarding spans to a http server.
type HTTPCollector struct {
	logger          Logger
	url             string
	client          *http.Client
	asyncInputQueue chan *zipkincore.Span
	quit            chan struct{}
}

// HTTPOption sets a parameter for the HttpCollector
type HTTPOption func(c *HTTPCollector)

// HTTPLogger sets the logger used to report errors in the collection
// process. By default, a no-op logger is used, i.e. no errors are logged
// anywhere. It's important to set this option in a production service.
func HTTPLogger(logger Logger) HTTPOption {
	return func(c *HTTPCollector) { c.logger = logger }
}

// HTTPMaxAsyncQueueSize sets the maximum buffer size for the async queue.
func HTTPMaxAsyncQueueSize(size int) HTTPOption {
	return func(c *HTTPCollector) { c.asyncInputQueue = make(chan *zipkincore.Span, size) }
}

// HTTPTimeout sets maximum timeout for http request.
func HTTPTimeout(duration time.Duration) HTTPOption {
	return func(c *HTTPCollector) { c.client.Timeout = duration }
}

// NewHTTPCollector returns a new HTTP-backend Collector. url should be a http
// url for handle post request. timeout is passed to http client. queueSize control
// the maximum size of buffer of async queue. The logger is used to log errors,
// such as send failures;
func NewHTTPCollector(url string, options ...HTTPOption) (Collector, error) {
	c := &HTTPCollector{
		logger:          NewNopLogger(),
		url:             url,
		client:          &http.Client{Timeout: defaultHTTPTimeout},
		asyncInputQueue: make(chan *zipkincore.Span, defaultMaxAsyncQueueSize),
		quit:            make(chan struct{}, 1),
	}

	for _, option := range options {
		option(c)
	}
	go c.loop()
	return c, nil
}

// Collect implements Collector.
func (c *HTTPCollector) Collect(s *zipkincore.Span) error {
	c.asyncInputQueue <- s
	return nil
}

// Close implements Collector.
func (c *HTTPCollector) Close() error {
	c.quit <- struct{}{}
	return nil
}

func httpSerialize(s *zipkincore.Span) []byte {
	t := thrift.NewTMemoryBuffer()
	p := thrift.NewTBinaryProtocolTransport(t)
	if err := p.WriteListBegin(thrift.STRUCT, 1); err != nil {
		panic(err)
	}
	if err := s.Write(p); err != nil {
		panic(err)
	}
	if err := p.WriteListEnd(); err != nil {
		panic(err)
	}
	return t.Buffer.Bytes()
}

func (c *HTTPCollector) loop() {
	for {
		select {
		case span := <-c.asyncInputQueue:
			req, err := http.NewRequest(
				"POST",
				c.url,
				strings.NewReader(string(httpSerialize(span))))
			if err != nil {
				_ = c.logger.Log("err", err.Error())
				continue
			}
			req.Header.Set("Content-Type", "application/x-thrift")

			go func() {
				_, err := c.client.Do(req)
				if err != nil {
					_ = c.logger.Log("err", err.Error())
				}
			}()
		case <-c.quit:
			return
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"github.com/timeredbull/tsuru/api/app"
	"github.com/timeredbull/tsuru/config"
	"github.com/timeredbull/tsuru/db"
	"github.com/timeredbull/tsuru/log"
	"labix.org/v2/mgo/bson"
	stdlog "log"
	"log/syslog"
	"time"
)

func getApps() []app.App {
	query := bson.M{
		"$or": []bson.M{
			bson.M{
				"units.agentstate": bson.M{"$ne": "started"},
			},
			bson.M{
				"units.machineagentstate": bson.M{"$ne": "running"},
			},
			bson.M{
				"units.instancestate": bson.M{"$ne": "running"},
			},
		},
	}
	var apps []app.App
	err := db.Session.Apps().Find(query).All(&apps)
	if err != nil {
		log.Panicf("Failed to get apps in the database: %s.", err)
	}
	return apps
}

func jujuCollect(ticker <-chan time.Time, multitenant bool) {
	var (
		env string
		err error
		f   func()
	)
	if multitenant {
		f = func() {
			for _, app := range getApps() {
				data, _ := collect(app.JujuEnv)
				output := parse(data)
				update(output)
			}
		}
	} else {
		if env, err = config.GetString("juju:default-env"); err != nil {
			log.Panic("You must configure juju default-env in tsuru.conf.")
		}
		f = func() {
			data, _ := collect(env)
			output := parse(data)
			update(output)
		}
	}
	for _ = range ticker {
		f()
	}
}

func main() {
	var err error
	log.Target, err = syslog.NewLogger(syslog.LOG_INFO, stdlog.LstdFlags)
	if err != nil {
		log.Panic(err)
	}
	configFile := flag.String("config", "/etc/tsuru/tsuru.conf", "tsuru config file")
	dry := flag.Bool("dry", false, "dry-run: does not start the agent (for testing purposes)")
	flag.Parse()
	err = config.ReadConfigFile(*configFile)
	if err != nil {
		log.Panic(err)
	}
	connString, err := config.GetString("database:url")
	if err != nil {
		log.Panic(err)
	}
	dbName, err := config.GetString("database:name")
	if err != nil {
		log.Panic(err)
	}
	db.Session, err = db.Open(connString, dbName)
	if err != nil {
		log.Panic(err)
	}
	defer db.Session.Close()
	multitenant, err := config.GetBool("multi-tenant")
	if err != nil {
		log.Panic(err)
	}

	if !*dry {
		ticker := time.Tick(time.Minute)
		jujuCollect(ticker, multitenant)
	}
}
<commit_msg>collector: using flag.(Bool|String)Var, to avoid pointer dereference<commit_after>package main

import (
	"flag"
	"github.com/timeredbull/tsuru/api/app"
	"github.com/timeredbull/tsuru/config"
	"github.com/timeredbull/tsuru/db"
	"github.com/timeredbull/tsuru/log"
	"labix.org/v2/mgo/bson"
	stdlog "log"
	"log/syslog"
	"time"
)

func getApps() []app.App {
	query := bson.M{
		"$or": []bson.M{
			bson.M{
				"units.agentstate": bson.M{"$ne": "started"},
			},
			bson.M{
				"units.machineagentstate": bson.M{"$ne": "running"},
			},
			bson.M{
				"units.instancestate": bson.M{"$ne": "running"},
			},
		},
	}
	var apps []app.App
	err := db.Session.Apps().Find(query).All(&apps)
	if err != nil {
		log.Panicf("Failed to get apps in the database: %s.", err)
	}
	return apps
}

func jujuCollect(ticker <-chan time.Time, multitenant bool) {
	var (
		env string
		err error
		f   func()
	)
	if multitenant {
		f = func() {
			for _, app := range getApps() {
				data, _ := collect(app.JujuEnv)
				output := parse(data)
				update(output)
			}
		}
	} else {
		if env, err = config.GetString("juju:default-env"); err != nil {
			log.Panic("You must configure juju default-env in tsuru.conf.")
		}
		f = func() {
			data, _ := collect(env)
			output := parse(data)
			update(output)
		}
	}
	for _ = range ticker {
		f()
	}
}

func main() {
	var (
		configFile string
		dry        bool
		err        error
	)
	log.Target, err = syslog.NewLogger(syslog.LOG_INFO, stdlog.LstdFlags)
	if err != nil {
		log.Panic(err)
	}
	flag.StringVar(&configFile, "config", "/etc/tsuru/tsuru.conf", "tsuru config file")
	flag.BoolVar(&dry, "dry", false, "dry-run: does not start the agent (for testing purposes)")
	flag.Parse()
	err = config.ReadConfigFile(configFile)
	if err != nil {
		log.Panic(err)
	}
	connString, err := config.GetString("database:url")
	if err != nil {
		log.Panic(err)
	}
	dbName, err := config.GetString("database:name")
	if err != nil {
		log.Panic(err)
	}
	db.Session, err = db.Open(connString, dbName)
	if err != nil {
		log.Panic(err)
	}
	defer db.Session.Close()
	multitenant, err := config.GetBool("multi-tenant")
	if err != nil {
		log.Panic(err)
	}

	if !dry {
		ticker := time.Tick(time.Minute)
		jujuCollect(ticker, multitenant)
	}
}
<|endoftext|>


<commit_before>package TeleGogo

// Location represents a point on the map.
type Location struct {
	// Longitude as defined by sender
	Longitude float64 `json:"longitude"`
	// Latitude as defined by sender
	Latitude float64 `json:"latitude"`
}
<commit_msg>changed location values from float64 to float32<commit_after>package TeleGogo

// Location represents a point on the map.
type Location struct {
	// Longitude as defined by sender
	Longitude float32 `json:"longitude"`
	// Latitude as defined by sender
	Latitude float32 `json:"latitude"`
}
<|endoftext|>


<commit_before>// Copyright 2012 Xing Xing <mikespook@gmail.com>.
// All rights reserved.
// Use of this source code is governed by a commercial
// license that can be found in the LICENSE file.

package log

import (
    "flag"
    "strings"
)

var (
    LogFile  = flag.String("log", "", "log to write (empty for STDOUT)")
    LogLevel = flag.String("log-level", "all", "log level " +
        "('error', 'warning', 'message', 'debug', 'all' and 'none'" +
        " are combined with '|')")
)

func StrToLevel(str string) int {
    level := LogNone
    levels := strings.SplitN(str, "|", -1)
    for _, v := range levels {
        switch v {
        case "none":
            level = level | LogNone
            break
        case "error":
            level = level | LogError
        case "warning":
            level = level | LogWarning
        case "message":
            level = level | LogMessage
        case "debug":
            level = level | LogDebug
        case "all":
            level = LogAll
        default:
        }
    }
	return level
}

func InitWithFlag() {
    if err := Init(*LogFile, StrToLevel(*LogLevel)); err != nil {
        Error(err)
    }
}
<commit_msg>setup the flag after log is inited<commit_after>// Copyright 2012 Xing Xing <mikespook@gmail.com>.
// All rights reserved.
// Use of this source code is governed by a commercial
// license that can be found in the LICENSE file.

package log

import (
	"flag"
	"strings"
)

var (
	LogFile, LogLevel string
)

func StrToLevel(str string) int {
	level := LogNone
	levels := strings.SplitN(str, "|", -1)
	for _, v := range levels {
		switch v {
		case "none":
			level = level | LogNone
			break
		case "error":
			level = level | LogError
		case "warning":
			level = level | LogWarning
		case "message":
			level = level | LogMessage
		case "debug":
			level = level | LogDebug
		case "all":
			level = LogAll
		default:
		}
	}
	return level
}

func InitWithFlag() {
	flag.StringVar(&LogFile, "log", "", "log to write (empty for STDOUT)")
	flag.StringVar(&LogLevel, "log-level", "all", "log level "+
		"('error', 'warning', 'message', 'debug', 'all' and 'none'"+
		" are combined with '|')")

	if err := Init(LogFile, StrToLevel(LogLevel)); err != nil {
		Error(err)
	}
}
<|endoftext|>


<commit_before>

<commit_msg>Code<commit_after>package main

import "fmt"

import "os"

import "strconv"

import "./log"

func main() {

number, err := strconv.ParseFloat(os.Args[1], 64)

if err != nil {fmt.Println("Arguments are Log(number) Log(base)", err)

} else {

    fmt.Printf("That number is %f!", log.Logresult(number))

  }

}<|endoftext|>


<commit_before>package logstash

import (
	"encoding/json"
	"errors"
	"log"
	"net"
	"os"

	"github.com/gliderlabs/logspout/router"
)

func init() {
	router.AdapterFactories.Register(NewLogstashAdapter, "logstash")
}

// LogstashAdapter is an adapter that streams UDP JSON to Logstash.
type LogstashAdapter struct {
	conn  net.Conn
	route *router.Route
}

func getopt(name, dfault string) string {
	value := os.Getenv(name)
	if value == "" {
		value = dfault
	}
	return value
}

// NewLogstashAdapter creates a LogstashAdapter with UDP as the default transport.
func NewLogstashAdapter(route *router.Route) (router.LogAdapter, error) {
	transport, found := router.AdapterTransports.Lookup(route.AdapterTransport("udp"))
	if !found {
		return nil, errors.New("unable to find adapter: " + route.Adapter)
	}

	conn, err := transport.Dial(route.Address, route.Options)
	if err != nil {
		return nil, err
	}

	return &LogstashAdapter{
		route: route,
		conn:  conn,
	}, nil
}

// Stream implements the router.LogAdapter interface.
func (a *LogstashAdapter) Stream(logstream chan *router.Message) {

	opt_string := getopt("OPTIONS", "")
	var options map[string]string

	if opt_string != "" {
		b := []byte(opt_string)

		json.Unmarshal(b, &options)
	}

	resp, err := http.Get("http://169.254.169.254/latest/meta-data/instance-id")
	var instance_id string
	if err == nil {
		instance_id = resp.Body
	}
	resp.Body.Close()

	for m := range logstream {
		msg := LogstashMessage{
			Message:    m.Data,
			Name:       m.Container.Name,
			ID:         m.Container.ID,
			Image:      m.Container.Config.Image,
			Hostname:   m.Container.Config.Hostname,
			Args:       m.Container.Args,
			InstanceId: instance_id,
			Options:    options,
		}
		js, err := json.Marshal(msg)
		if err != nil {
			log.Println("logstash:", err)
			continue
		}
		_, err = a.conn.Write(js)
		if err != nil {
			log.Println("logstash:", err)
			continue
		}
	}
}

// LogstashMessage is a simple JSON input to Logstash.
type LogstashMessage struct {
	Message    string            `json:"message"`
	Name       string            `json:"docker.name"`
	ID         string            `json:"docker.id"`
	Image      string            `json:"docker.image"`
	Hostname   string            `json:"docker.hostname"`
	Args       []string          `json:"docker.args,omitempty"`
	Options    map[string]string `json:"options,omitempty"`
	InstanceId string            `json:"instance-id"`
}
<commit_msg>adding in import<commit_after>package logstash

import (
	"encoding/json"
	"errors"
	"log"
	"net"
	"net/http"
	"os"

	"github.com/gliderlabs/logspout/router"
)

func init() {
	router.AdapterFactories.Register(NewLogstashAdapter, "logstash")
}

// LogstashAdapter is an adapter that streams UDP JSON to Logstash.
type LogstashAdapter struct {
	conn  net.Conn
	route *router.Route
}

func getopt(name, dfault string) string {
	value := os.Getenv(name)
	if value == "" {
		value = dfault
	}
	return value
}

// NewLogstashAdapter creates a LogstashAdapter with UDP as the default transport.
func NewLogstashAdapter(route *router.Route) (router.LogAdapter, error) {
	transport, found := router.AdapterTransports.Lookup(route.AdapterTransport("udp"))
	if !found {
		return nil, errors.New("unable to find adapter: " + route.Adapter)
	}

	conn, err := transport.Dial(route.Address, route.Options)
	if err != nil {
		return nil, err
	}

	return &LogstashAdapter{
		route: route,
		conn:  conn,
	}, nil
}

// Stream implements the router.LogAdapter interface.
func (a *LogstashAdapter) Stream(logstream chan *router.Message) {

	opt_string := getopt("OPTIONS", "")
	var options map[string]string

	if opt_string != "" {
		b := []byte(opt_string)

		json.Unmarshal(b, &options)
	}

	resp, err := http.Get("http://169.254.169.254/latest/meta-data/instance-id")
	var instance_id string
	if err == nil {
		instance_id = resp.Body
	}
	resp.Body.Close()

	for m := range logstream {
		msg := LogstashMessage{
			Message:    m.Data,
			Name:       m.Container.Name,
			ID:         m.Container.ID,
			Image:      m.Container.Config.Image,
			Hostname:   m.Container.Config.Hostname,
			Args:       m.Container.Args,
			InstanceId: instance_id,
			Options:    options,
		}
		js, err := json.Marshal(msg)
		if err != nil {
			log.Println("logstash:", err)
			continue
		}
		_, err = a.conn.Write(js)
		if err != nil {
			log.Println("logstash:", err)
			continue
		}
	}
}

// LogstashMessage is a simple JSON input to Logstash.
type LogstashMessage struct {
	Message    string            `json:"message"`
	Name       string            `json:"docker.name"`
	ID         string            `json:"docker.id"`
	Image      string            `json:"docker.image"`
	Hostname   string            `json:"docker.hostname"`
	Args       []string          `json:"docker.args,omitempty"`
	Options    map[string]string `json:"options,omitempty"`
	InstanceId string            `json:"instance-id"`
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"regexp"
	"sort"
	"strings"
	"sync"

	"github.com/olekukonko/tablewriter"

	"github.com/lxc/lxd"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/gnuflag"
	"github.com/lxc/lxd/shared/i18n"
)

type column struct {
	Name           string
	Data           columnData
	NeedsState     bool
	NeedsSnapshots bool
}

type columnData func(shared.ContainerInfo, *shared.ContainerState, []shared.SnapshotInfo) string

type byName [][]string

func (a byName) Len() int {
	return len(a)
}

func (a byName) Swap(i, j int) {
	a[i], a[j] = a[j], a[i]
}

func (a byName) Less(i, j int) bool {
	if a[i][0] == "" {
		return false
	}

	if a[j][0] == "" {
		return true
	}

	return a[i][0] < a[j][0]
}

type listCmd struct {
	chosenColumnRunes string
	fast              bool
}

func (c *listCmd) showByDefault() bool {
	return true
}

func (c *listCmd) usage() string {
	return i18n.G(
		`Lists the available resources.

lxc list [resource] [filters] [-c columns] [--fast]

The filters are:
* A single keyword like "web" which will list any container with "web" in its name.
* A key/value pair referring to a configuration item. For those, the namespace can be abreviated to the smallest unambiguous identifier:
* "user.blah=abc" will list all containers with the "blah" user property set to "abc"
* "u.blah=abc" will do the same
* "security.privileged=1" will list all privileged containers
* "s.privileged=1" will do the same

The columns are:
* 4 - IPv4 address
* 6 - IPv6 address
* a - architecture
* c - creation date
* n - name
* p - pid of container init process
* P - profiles
* s - state
* t - type (persistent or ephemeral)

Default column layout: ns46tS
Fast column layout: nsacPt`)
}

func (c *listCmd) flags() {
	gnuflag.StringVar(&c.chosenColumnRunes, "c", "ns46tS", i18n.G("Columns"))
	gnuflag.StringVar(&c.chosenColumnRunes, "columns", "ns46tS", i18n.G("Columns"))
	gnuflag.BoolVar(&c.fast, "fast", false, i18n.G("Fast mode (same as --columns=nsacPt"))
}

// This seems a little excessive.
func (c *listCmd) dotPrefixMatch(short string, full string) bool {
	fullMembs := strings.Split(full, ".")
	shortMembs := strings.Split(short, ".")

	if len(fullMembs) != len(shortMembs) {
		return false
	}

	for i, _ := range fullMembs {
		if !strings.HasPrefix(fullMembs[i], shortMembs[i]) {
			return false
		}
	}

	return true
}

func (c *listCmd) shouldShow(filters []string, state *shared.ContainerInfo) bool {
	for _, filter := range filters {
		if strings.Contains(filter, "=") {
			membs := strings.SplitN(filter, "=", 2)

			key := membs[0]
			var value string
			if len(membs) < 2 {
				value = ""
			} else {
				value = membs[1]
			}

			found := false
			for configKey, configValue := range state.Config {
				if c.dotPrefixMatch(key, configKey) {
					//try to test filter value as a regexp
					regexpValue := value
					if !(strings.Contains(value, "^") || strings.Contains(value, "$")) {
						regexpValue = "^" + regexpValue + "$"
					}
					r, err := regexp.Compile(regexpValue)
					//if not regexp compatible use original value
					if err != nil {
						if value == configValue {
							found = true
							break
						} else {
							// the property was found but didn't match
							return false
						}
					} else if r.MatchString(configValue) == true {
						found = true
						break
					}
				}
			}

			if !found {
				return false
			}
		} else {
			if !strings.Contains(state.Name, filter) {
				return false
			}
		}
	}

	return true
}

func (c *listCmd) listContainers(d *lxd.Client, cinfos []shared.ContainerInfo, filters []string, columns []column) error {
	headers := []string{}
	for _, column := range columns {
		headers = append(headers, column.Name)
	}

	threads := 10
	if len(cinfos) < threads {
		threads = len(cinfos)
	}

	cStates := map[string]*shared.ContainerState{}
	cStatesLock := sync.Mutex{}
	cStatesQueue := make(chan string, threads)
	cStatesWg := sync.WaitGroup{}

	cSnapshots := map[string][]shared.SnapshotInfo{}
	cSnapshotsLock := sync.Mutex{}
	cSnapshotsQueue := make(chan string, threads)
	cSnapshotsWg := sync.WaitGroup{}

	for i := 0; i < threads; i++ {
		cStatesWg.Add(1)
		go func() {
			for {
				cName, more := <-cStatesQueue
				if !more {
					break
				}

				state, err := d.ContainerState(cName)
				if err != nil {
					continue
				}

				cStatesLock.Lock()
				cStates[cName] = state
				cStatesLock.Unlock()
			}
			cStatesWg.Done()
		}()

		cSnapshotsWg.Add(1)
		go func() {
			for {
				cName, more := <-cSnapshotsQueue
				if !more {
					break
				}

				snaps, err := d.ListSnapshots(cName)
				if err != nil {
					continue
				}

				cSnapshotsLock.Lock()
				cSnapshots[cName] = snaps
				cSnapshotsLock.Unlock()
			}
			cSnapshotsWg.Done()
		}()
	}

	for _, cInfo := range cinfos {
		if !c.shouldShow(filters, &cInfo) {
			continue
		}

		for _, column := range columns {
			if column.NeedsState && cInfo.StatusCode != shared.Stopped {
				_, ok := cStates[cInfo.Name]
				if ok {
					continue
				}

				cStatesLock.Lock()
				cStates[cInfo.Name] = nil
				cStatesLock.Unlock()

				cStatesQueue <- cInfo.Name
			}

			if column.NeedsSnapshots {
				_, ok := cSnapshots[cInfo.Name]
				if ok {
					continue
				}

				cSnapshotsLock.Lock()
				cSnapshots[cInfo.Name] = nil
				cSnapshotsLock.Unlock()

				cSnapshotsQueue <- cInfo.Name
			}
		}
	}

	close(cStatesQueue)
	close(cSnapshotsQueue)
	cStatesWg.Wait()
	cSnapshotsWg.Wait()

	data := [][]string{}
	for _, cInfo := range cinfos {
		if !c.shouldShow(filters, &cInfo) {
			continue
		}

		col := []string{}
		for _, column := range columns {
			col = append(col, column.Data(cInfo, cStates[cInfo.Name], cSnapshots[cInfo.Name]))
		}
		data = append(data, col)
	}

	table := tablewriter.NewWriter(os.Stdout)
	table.SetAutoWrapText(false)
	table.SetRowLine(true)
	table.SetHeader(headers)
	sort.Sort(byName(data))
	table.AppendBulk(data)
	table.Render()

	return nil
}

func (c *listCmd) run(config *lxd.Config, args []string) error {
	var remote string
	name := ""

	filters := []string{}

	if len(args) != 0 {
		filters = args
		if strings.Contains(args[0], ":") {
			remote, name = config.ParseRemoteAndContainer(args[0])
			filters = args[1:]
		} else if !strings.Contains(args[0], "=") {
			remote = config.DefaultRemote
			name = args[0]
		}
	}

	if remote == "" {
		remote = config.DefaultRemote
	}

	d, err := lxd.NewClient(config, remote)
	if err != nil {
		return err
	}

	var cts []shared.ContainerInfo
	ctslist, err := d.ListContainers()
	if err != nil {
		return err
	}

	if name == "" {
		cts = ctslist
	} else {
		for _, cinfo := range ctslist {
			if len(cinfo.Name) >= len(name) && cinfo.Name[0:len(name)] == name {
				cts = append(cts, cinfo)
			}
		}
	}

	columns_map := map[rune]column{
		'4': column{i18n.G("IPV4"), c.IP4ColumnData, true, false},
		'6': column{i18n.G("IPV6"), c.IP6ColumnData, true, false},
		'a': column{i18n.G("ARCHITECTURE"), c.ArchitectureColumnData, false, false},
		'c': column{i18n.G("CREATED AT"), c.CreatedColumnData, false, false},
		'n': column{i18n.G("NAME"), c.nameColumnData, false, false},
		'p': column{i18n.G("PID"), c.PIDColumnData, true, false},
		'P': column{i18n.G("PROFILES"), c.ProfilesColumnData, false, false},
		'S': column{i18n.G("SNAPSHOTS"), c.numberSnapshotsColumnData, false, true},
		's': column{i18n.G("STATE"), c.statusColumnData, false, false},
		't': column{i18n.G("TYPE"), c.typeColumnData, false, false},
	}

	if c.fast {
		c.chosenColumnRunes = "nsacPt"
	}

	columns := []column{}
	for _, columnRune := range c.chosenColumnRunes {
		if column, ok := columns_map[columnRune]; ok {
			columns = append(columns, column)
		} else {
			return fmt.Errorf("%s does contain invalid column characters\n", c.chosenColumnRunes)
		}
	}

	return c.listContainers(d, cts, filters, columns)
}

func (c *listCmd) nameColumnData(cInfo shared.ContainerInfo, cState *shared.ContainerState, cSnaps []shared.SnapshotInfo) string {
	return cInfo.Name
}

func (c *listCmd) statusColumnData(cInfo shared.ContainerInfo, cState *shared.ContainerState, cSnaps []shared.SnapshotInfo) string {
	return strings.ToUpper(cInfo.Status)
}

func (c *listCmd) IP4ColumnData(cInfo shared.ContainerInfo, cState *shared.ContainerState, cSnaps []shared.SnapshotInfo) string {
	if cInfo.StatusCode != shared.Stopped {
		ipv4s := []string{}
		for netName, net := range cState.Network {
			if net.Type == "loopback" {
				continue
			}

			for _, addr := range net.Addresses {
				if shared.StringInSlice(addr.Scope, []string{"link", "local"}) {
					continue
				}

				if addr.Family == "inet" {
					ipv4s = append(ipv4s, fmt.Sprintf("%s (%s)", addr.Address, netName))
				}
			}
		}
		return strings.Join(ipv4s, "\n")
	} else {
		return ""
	}
}

func (c *listCmd) IP6ColumnData(cInfo shared.ContainerInfo, cState *shared.ContainerState, cSnaps []shared.SnapshotInfo) string {
	if cInfo.StatusCode != shared.Stopped {
		ipv6s := []string{}
		for netName, net := range cState.Network {
			if net.Type == "loopback" {
				continue
			}

			for _, addr := range net.Addresses {
				if shared.StringInSlice(addr.Scope, []string{"link", "local"}) {
					continue
				}

				if addr.Family == "inet6" {
					ipv6s = append(ipv6s, fmt.Sprintf("%s (%s)", addr.Address, netName))
				}
			}
		}
		return strings.Join(ipv6s, "\n")
	} else {
		return ""
	}
}

func (c *listCmd) typeColumnData(cInfo shared.ContainerInfo, cState *shared.ContainerState, cSnaps []shared.SnapshotInfo) string {
	if cInfo.Ephemeral {
		return i18n.G("EPHEMERAL")
	} else {
		return i18n.G("PERSISTENT")
	}
}

func (c *listCmd) numberSnapshotsColumnData(cInfo shared.ContainerInfo, cState *shared.ContainerState, cSnaps []shared.SnapshotInfo) string {
	return fmt.Sprintf("%d", len(cSnaps))
}

func (c *listCmd) PIDColumnData(cInfo shared.ContainerInfo, cState *shared.ContainerState, cSnaps []shared.SnapshotInfo) string {
	if cState.Pid != 0 {
		return fmt.Sprintf("%d", cState.Pid)
	} else {
		return ""
	}
}

func (c *listCmd) ArchitectureColumnData(cInfo shared.ContainerInfo, cState *shared.ContainerState, cSnaps []shared.SnapshotInfo) string {
	return cInfo.Architecture
}

func (c *listCmd) ProfilesColumnData(cInfo shared.ContainerInfo, cState *shared.ContainerState, cSnaps []shared.SnapshotInfo) string {
	return strings.Join(cInfo.Profiles, "\n")
}

func (c *listCmd) CreatedColumnData(cInfo shared.ContainerInfo, cState *shared.ContainerState, cSnaps []shared.SnapshotInfo) string {
	layout := "2006/01/02 15:04 UTC"

	if cInfo.CreationDate.UTC().Unix() != 0 {
		return cInfo.CreationDate.UTC().Format(layout)
	}

	return ""
}
<commit_msg>list: Fix crash on PID column<commit_after>package main

import (
	"fmt"
	"os"
	"regexp"
	"sort"
	"strings"
	"sync"

	"github.com/olekukonko/tablewriter"

	"github.com/lxc/lxd"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/gnuflag"
	"github.com/lxc/lxd/shared/i18n"
)

type column struct {
	Name           string
	Data           columnData
	NeedsState     bool
	NeedsSnapshots bool
}

type columnData func(shared.ContainerInfo, *shared.ContainerState, []shared.SnapshotInfo) string

type byName [][]string

func (a byName) Len() int {
	return len(a)
}

func (a byName) Swap(i, j int) {
	a[i], a[j] = a[j], a[i]
}

func (a byName) Less(i, j int) bool {
	if a[i][0] == "" {
		return false
	}

	if a[j][0] == "" {
		return true
	}

	return a[i][0] < a[j][0]
}

type listCmd struct {
	chosenColumnRunes string
	fast              bool
}

func (c *listCmd) showByDefault() bool {
	return true
}

func (c *listCmd) usage() string {
	return i18n.G(
		`Lists the available resources.

lxc list [resource] [filters] [-c columns] [--fast]

The filters are:
* A single keyword like "web" which will list any container with "web" in its name.
* A key/value pair referring to a configuration item. For those, the namespace can be abreviated to the smallest unambiguous identifier:
* "user.blah=abc" will list all containers with the "blah" user property set to "abc"
* "u.blah=abc" will do the same
* "security.privileged=1" will list all privileged containers
* "s.privileged=1" will do the same

The columns are:
* 4 - IPv4 address
* 6 - IPv6 address
* a - architecture
* c - creation date
* n - name
* p - pid of container init process
* P - profiles
* s - state
* t - type (persistent or ephemeral)

Default column layout: ns46tS
Fast column layout: nsacPt`)
}

func (c *listCmd) flags() {
	gnuflag.StringVar(&c.chosenColumnRunes, "c", "ns46tS", i18n.G("Columns"))
	gnuflag.StringVar(&c.chosenColumnRunes, "columns", "ns46tS", i18n.G("Columns"))
	gnuflag.BoolVar(&c.fast, "fast", false, i18n.G("Fast mode (same as --columns=nsacPt"))
}

// This seems a little excessive.
func (c *listCmd) dotPrefixMatch(short string, full string) bool {
	fullMembs := strings.Split(full, ".")
	shortMembs := strings.Split(short, ".")

	if len(fullMembs) != len(shortMembs) {
		return false
	}

	for i, _ := range fullMembs {
		if !strings.HasPrefix(fullMembs[i], shortMembs[i]) {
			return false
		}
	}

	return true
}

func (c *listCmd) shouldShow(filters []string, state *shared.ContainerInfo) bool {
	for _, filter := range filters {
		if strings.Contains(filter, "=") {
			membs := strings.SplitN(filter, "=", 2)

			key := membs[0]
			var value string
			if len(membs) < 2 {
				value = ""
			} else {
				value = membs[1]
			}

			found := false
			for configKey, configValue := range state.Config {
				if c.dotPrefixMatch(key, configKey) {
					//try to test filter value as a regexp
					regexpValue := value
					if !(strings.Contains(value, "^") || strings.Contains(value, "$")) {
						regexpValue = "^" + regexpValue + "$"
					}
					r, err := regexp.Compile(regexpValue)
					//if not regexp compatible use original value
					if err != nil {
						if value == configValue {
							found = true
							break
						} else {
							// the property was found but didn't match
							return false
						}
					} else if r.MatchString(configValue) == true {
						found = true
						break
					}
				}
			}

			if !found {
				return false
			}
		} else {
			if !strings.Contains(state.Name, filter) {
				return false
			}
		}
	}

	return true
}

func (c *listCmd) listContainers(d *lxd.Client, cinfos []shared.ContainerInfo, filters []string, columns []column) error {
	headers := []string{}
	for _, column := range columns {
		headers = append(headers, column.Name)
	}

	threads := 10
	if len(cinfos) < threads {
		threads = len(cinfos)
	}

	cStates := map[string]*shared.ContainerState{}
	cStatesLock := sync.Mutex{}
	cStatesQueue := make(chan string, threads)
	cStatesWg := sync.WaitGroup{}

	cSnapshots := map[string][]shared.SnapshotInfo{}
	cSnapshotsLock := sync.Mutex{}
	cSnapshotsQueue := make(chan string, threads)
	cSnapshotsWg := sync.WaitGroup{}

	for i := 0; i < threads; i++ {
		cStatesWg.Add(1)
		go func() {
			for {
				cName, more := <-cStatesQueue
				if !more {
					break
				}

				state, err := d.ContainerState(cName)
				if err != nil {
					continue
				}

				cStatesLock.Lock()
				cStates[cName] = state
				cStatesLock.Unlock()
			}
			cStatesWg.Done()
		}()

		cSnapshotsWg.Add(1)
		go func() {
			for {
				cName, more := <-cSnapshotsQueue
				if !more {
					break
				}

				snaps, err := d.ListSnapshots(cName)
				if err != nil {
					continue
				}

				cSnapshotsLock.Lock()
				cSnapshots[cName] = snaps
				cSnapshotsLock.Unlock()
			}
			cSnapshotsWg.Done()
		}()
	}

	for _, cInfo := range cinfos {
		if !c.shouldShow(filters, &cInfo) {
			continue
		}

		for _, column := range columns {
			if column.NeedsState && cInfo.StatusCode != shared.Stopped {
				_, ok := cStates[cInfo.Name]
				if ok {
					continue
				}

				cStatesLock.Lock()
				cStates[cInfo.Name] = nil
				cStatesLock.Unlock()

				cStatesQueue <- cInfo.Name
			}

			if column.NeedsSnapshots {
				_, ok := cSnapshots[cInfo.Name]
				if ok {
					continue
				}

				cSnapshotsLock.Lock()
				cSnapshots[cInfo.Name] = nil
				cSnapshotsLock.Unlock()

				cSnapshotsQueue <- cInfo.Name
			}
		}
	}

	close(cStatesQueue)
	close(cSnapshotsQueue)
	cStatesWg.Wait()
	cSnapshotsWg.Wait()

	data := [][]string{}
	for _, cInfo := range cinfos {
		if !c.shouldShow(filters, &cInfo) {
			continue
		}

		col := []string{}
		for _, column := range columns {
			col = append(col, column.Data(cInfo, cStates[cInfo.Name], cSnapshots[cInfo.Name]))
		}
		data = append(data, col)
	}

	table := tablewriter.NewWriter(os.Stdout)
	table.SetAutoWrapText(false)
	table.SetRowLine(true)
	table.SetHeader(headers)
	sort.Sort(byName(data))
	table.AppendBulk(data)
	table.Render()

	return nil
}

func (c *listCmd) run(config *lxd.Config, args []string) error {
	var remote string
	name := ""

	filters := []string{}

	if len(args) != 0 {
		filters = args
		if strings.Contains(args[0], ":") {
			remote, name = config.ParseRemoteAndContainer(args[0])
			filters = args[1:]
		} else if !strings.Contains(args[0], "=") {
			remote = config.DefaultRemote
			name = args[0]
		}
	}

	if remote == "" {
		remote = config.DefaultRemote
	}

	d, err := lxd.NewClient(config, remote)
	if err != nil {
		return err
	}

	var cts []shared.ContainerInfo
	ctslist, err := d.ListContainers()
	if err != nil {
		return err
	}

	if name == "" {
		cts = ctslist
	} else {
		for _, cinfo := range ctslist {
			if len(cinfo.Name) >= len(name) && cinfo.Name[0:len(name)] == name {
				cts = append(cts, cinfo)
			}
		}
	}

	columns_map := map[rune]column{
		'4': column{i18n.G("IPV4"), c.IP4ColumnData, true, false},
		'6': column{i18n.G("IPV6"), c.IP6ColumnData, true, false},
		'a': column{i18n.G("ARCHITECTURE"), c.ArchitectureColumnData, false, false},
		'c': column{i18n.G("CREATED AT"), c.CreatedColumnData, false, false},
		'n': column{i18n.G("NAME"), c.nameColumnData, false, false},
		'p': column{i18n.G("PID"), c.PIDColumnData, true, false},
		'P': column{i18n.G("PROFILES"), c.ProfilesColumnData, false, false},
		'S': column{i18n.G("SNAPSHOTS"), c.numberSnapshotsColumnData, false, true},
		's': column{i18n.G("STATE"), c.statusColumnData, false, false},
		't': column{i18n.G("TYPE"), c.typeColumnData, false, false},
	}

	if c.fast {
		c.chosenColumnRunes = "nsacPt"
	}

	columns := []column{}
	for _, columnRune := range c.chosenColumnRunes {
		if column, ok := columns_map[columnRune]; ok {
			columns = append(columns, column)
		} else {
			return fmt.Errorf("%s does contain invalid column characters\n", c.chosenColumnRunes)
		}
	}

	return c.listContainers(d, cts, filters, columns)
}

func (c *listCmd) nameColumnData(cInfo shared.ContainerInfo, cState *shared.ContainerState, cSnaps []shared.SnapshotInfo) string {
	return cInfo.Name
}

func (c *listCmd) statusColumnData(cInfo shared.ContainerInfo, cState *shared.ContainerState, cSnaps []shared.SnapshotInfo) string {
	return strings.ToUpper(cInfo.Status)
}

func (c *listCmd) IP4ColumnData(cInfo shared.ContainerInfo, cState *shared.ContainerState, cSnaps []shared.SnapshotInfo) string {
	if cInfo.StatusCode != shared.Stopped {
		ipv4s := []string{}
		for netName, net := range cState.Network {
			if net.Type == "loopback" {
				continue
			}

			for _, addr := range net.Addresses {
				if shared.StringInSlice(addr.Scope, []string{"link", "local"}) {
					continue
				}

				if addr.Family == "inet" {
					ipv4s = append(ipv4s, fmt.Sprintf("%s (%s)", addr.Address, netName))
				}
			}
		}
		return strings.Join(ipv4s, "\n")
	} else {
		return ""
	}
}

func (c *listCmd) IP6ColumnData(cInfo shared.ContainerInfo, cState *shared.ContainerState, cSnaps []shared.SnapshotInfo) string {
	if cInfo.StatusCode != shared.Stopped {
		ipv6s := []string{}
		for netName, net := range cState.Network {
			if net.Type == "loopback" {
				continue
			}

			for _, addr := range net.Addresses {
				if shared.StringInSlice(addr.Scope, []string{"link", "local"}) {
					continue
				}

				if addr.Family == "inet6" {
					ipv6s = append(ipv6s, fmt.Sprintf("%s (%s)", addr.Address, netName))
				}
			}
		}
		return strings.Join(ipv6s, "\n")
	} else {
		return ""
	}
}

func (c *listCmd) typeColumnData(cInfo shared.ContainerInfo, cState *shared.ContainerState, cSnaps []shared.SnapshotInfo) string {
	if cInfo.Ephemeral {
		return i18n.G("EPHEMERAL")
	} else {
		return i18n.G("PERSISTENT")
	}
}

func (c *listCmd) numberSnapshotsColumnData(cInfo shared.ContainerInfo, cState *shared.ContainerState, cSnaps []shared.SnapshotInfo) string {
	return fmt.Sprintf("%d", len(cSnaps))
}

func (c *listCmd) PIDColumnData(cInfo shared.ContainerInfo, cState *shared.ContainerState, cSnaps []shared.SnapshotInfo) string {
	if cInfo.StatusCode != shared.Stopped {
		return fmt.Sprintf("%d", cState.Pid)
	}

	return ""
}

func (c *listCmd) ArchitectureColumnData(cInfo shared.ContainerInfo, cState *shared.ContainerState, cSnaps []shared.SnapshotInfo) string {
	return cInfo.Architecture
}

func (c *listCmd) ProfilesColumnData(cInfo shared.ContainerInfo, cState *shared.ContainerState, cSnaps []shared.SnapshotInfo) string {
	return strings.Join(cInfo.Profiles, "\n")
}

func (c *listCmd) CreatedColumnData(cInfo shared.ContainerInfo, cState *shared.ContainerState, cSnaps []shared.SnapshotInfo) string {
	layout := "2006/01/02 15:04 UTC"

	if cInfo.CreationDate.UTC().Unix() != 0 {
		return cInfo.CreationDate.UTC().Format(layout)
	}

	return ""
}
<|endoftext|>