<commit_before>// Copyright © by Jeff Foley 2017-2020. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
// SPDX-License-Identifier: Apache-2.0

// In-depth Attack Surface Mapping and Asset Discovery
//  +----------------------------------------------------------------------------+
//  | ░░░░░░░░░░░░░░░░░░░░░░░░░░  OWASP Amass  ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ |
//  +----------------------------------------------------------------------------+
//  |      .+++:.            :                             .+++.                 |
//  |    +W@@@@@@8        &+W@#               o8W8:      +W@@@@@@#.   oW@@@W#+   |
//  |   &@#+   .o@##.    .@@@o@W.o@@o       :@@#&W8o    .@#:  .:oW+  .@#+++&#&   |
//  |  +@&        &@&     #@8 +@W@&8@+     :@W.   +@8   +@:          .@8         |
//  |  8@          @@     8@o  8@8  WW    .@W      W@+  .@W.          o@#:       |
//  |  WW          &@o    &@:  o@+  o@+   #@.      8@o   +W@#+.        +W@8:     |
//  |  #@          :@W    &@+  &@+   @8  :@o       o@o     oW@@W+        oW@8    |
//  |  o@+          @@&   &@+  &@+   #@  &@.      .W@W       .+#@&         o@W.  |
//  |   WW         +@W@8. &@+  :&    o@+ #@      :@W&@&         &@:  ..     :@o  |
//  |   :@W:      o@# +Wo &@+        :W: +@W&o++o@W. &@&  8@#o+&@W.  #@:    o@+  |
//  |    :W@@WWWW@@8       +              :&W@@@@&    &W  .o#@@W&.   :W@WWW@@&   |
//  |      +o&&&&+.                                                    +oooo.    |
//  +----------------------------------------------------------------------------+
package main

import (
	"bytes"
	"context"
	"errors"
	"flag"
	"fmt"
	"os"
	"path"
	"sort"
	"strings"
	"time"

	"github.com/OWASP/Amass/v3/config"
	"github.com/OWASP/Amass/v3/datasrcs"
	"github.com/OWASP/Amass/v3/eventbus"
	"github.com/OWASP/Amass/v3/format"
	"github.com/OWASP/Amass/v3/graph"
	"github.com/OWASP/Amass/v3/net"
	"github.com/OWASP/Amass/v3/requests"
	"github.com/OWASP/Amass/v3/stringfilter"
	"github.com/OWASP/Amass/v3/systems"
	"github.com/fatih/color"
)

const (
	mainUsageMsg         = "intel|enum|viz|track|db|dns [options]"
	exampleConfigFileURL = "https://github.com/OWASP/Amass/blob/master/examples/config.ini"
	userGuideURL         = "https://github.com/OWASP/Amass/blob/master/doc/user_guide.md"
	tutorialURL          = "https://github.com/OWASP/Amass/blob/master/doc/tutorial.md"
)

var (
	// Colors used to ease the reading of program output
	g      = color.New(color.FgHiGreen)
	r      = color.New(color.FgHiRed)
	b      = color.New(color.FgHiBlue)
	fgR    = color.New(color.FgRed)
	fgY    = color.New(color.FgYellow)
	yellow = color.New(color.FgHiYellow).SprintFunc()
	green  = color.New(color.FgHiGreen).SprintFunc()
	blue   = color.New(color.FgHiBlue).SprintFunc()
	red    = color.New(color.FgHiRed).SprintFunc()
)

func commandUsage(msg string, cmdFlagSet *flag.FlagSet, errBuf *bytes.Buffer) {
	format.PrintBanner()
	g.Fprintf(color.Error, "Usage: %s %s\n\n", path.Base(os.Args[0]), msg)
	cmdFlagSet.PrintDefaults()
	g.Fprintln(color.Error, errBuf.String())

	if msg == mainUsageMsg {
		g.Fprintf(color.Error, "\nSubcommands: \n\n")
		g.Fprintf(color.Error, "\t%-11s - Discover targets for enumerations\n", "amass intel")
		g.Fprintf(color.Error, "\t%-11s - Perform enumerations and network mapping\n", "amass enum")
		g.Fprintf(color.Error, "\t%-11s - Visualize enumeration results\n", "amass viz")
		g.Fprintf(color.Error, "\t%-11s - Track differences between enumerations\n", "amass track")
		g.Fprintf(color.Error, "\t%-11s - Manipulate the Amass graph database\n", "amass db")
		g.Fprintf(color.Error, "\t%-11s - Resolve DNS names at high performance\n\n", "amass dns")
	}

	g.Fprintf(color.Error, "The user's guide can be found here: \n%s\n\n", userGuideURL)
	g.Fprintf(color.Error, "An example configuration file can be found here: \n%s\n\n", exampleConfigFileURL)
	g.Fprintf(color.Error, "The Amass tutorial can be found here: \n%s\n\n", tutorialURL)
}

func main() {
	var version, help1, help2 bool
	mainFlagSet := flag.NewFlagSet("amass", flag.ContinueOnError)

	defaultBuf := new(bytes.Buffer)
	mainFlagSet.SetOutput(defaultBuf)

	mainFlagSet.BoolVar(&help1, "h", false, "Show the program usage message")
	mainFlagSet.BoolVar(&help2, "help", false, "Show the program usage message")
	mainFlagSet.BoolVar(&version, "version", false, "Print the version number of this Amass binary")

	if len(os.Args) < 2 {
		commandUsage(mainUsageMsg, mainFlagSet, defaultBuf)
		return
	}

	if err := mainFlagSet.Parse(os.Args[1:]); err != nil {
		r.Fprintf(color.Error, "%v\n", err)
		os.Exit(1)
	}
	if help1 || help2 {
		commandUsage(mainUsageMsg, mainFlagSet, defaultBuf)
		return
	}
	if version {
		fmt.Fprintf(color.Error, "%s\n", format.Version)
		return
	}

	switch os.Args[1] {
	case "db":
		runDBCommand(os.Args[2:])
	case "dns":
		runDNSCommand(os.Args[2:])
	case "enum":
		runEnumCommand(os.Args[2:])
	case "intel":
		runIntelCommand(os.Args[2:])
	case "track":
		runTrackCommand(os.Args[2:])
	case "viz":
		runVizCommand(os.Args[2:])
	default:
		commandUsage(mainUsageMsg, mainFlagSet, defaultBuf)
		os.Exit(1)
	}
}

// GetAllSourceInfo returns the names of all Amass data sources.
func GetAllSourceInfo(cfg *config.Config) []string {
	var names []string

	if cfg == nil {
		cfg = config.NewConfig()
	}

	sys, err := systems.NewLocalSystem(cfg)
	if err != nil {
		return names
	}
	sys.SetDataSources(datasrcs.GetAllSources(sys))

	for _, src := range sys.DataSources() {
		names = append(names, fmt.Sprintf("%-20s\t%s", src.String(), src.Type()))
	}

	sys.Shutdown()
	return names
}

func createOutputDirectory(cfg *config.Config) {
	// Prepare output file paths
	dir := config.OutputDirectory(cfg.Dir)
	if dir == "" {
		r.Fprintln(color.Error, "Failed to obtain the output directory")
		os.Exit(1)
	}
	// If the directory does not yet exist, create it
	if err := os.MkdirAll(dir, 0755); err != nil {
		r.Fprintf(color.Error, "Failed to create the directory: %v\n", err)
		os.Exit(1)
	}
}

func generateCategoryMap(sys systems.System) map[string][]string {
	catToSources := make(map[string][]string)

	for _, src := range sys.DataSources() {
		t := src.Type()

		catToSources[t] = append(catToSources[t], src.String())
	}

	return catToSources
}

func expandCategoryNames(names []string, categories map[string][]string) []string {
	var newnames []string

	for _, name := range names {
		if _, found := categories[name]; found {
			newnames = append(newnames, categories[name]...)
			continue
		}

		newnames = append(newnames, name)
	}

	return newnames
}

func openGraphDatabase(dir string, cfg *config.Config) *graph.Graph {
	for _, db := range cfg.GraphDBs {
		if !db.Primary {
			continue
		}

		cayley := graph.NewCayleyGraph(db.System, db.URL, db.Options)
		if cayley == nil {
			return nil
		}

		g := graph.NewGraph(cayley)
		if g == nil {
			return nil
		}

		return g
	}

	if db := cfg.LocalDatabaseSettings(cfg.GraphDBs); db != nil {
		db.Options = ""

		cayley := graph.NewCayleyGraph(db.System, config.OutputDirectory(dir), db.Options)
		if cayley == nil {
			return nil
		}

		if g := graph.NewGraph(cayley); g != nil {
			return g
		}
	}

	return nil
}

func orderedEvents(events []string, db *graph.Graph) ([]string, []time.Time, []time.Time) {
	sort.Slice(events, func(i, j int) bool {
		var less bool

		e1, l1 := db.EventDateRange(events[i])
		e2, l2 := db.EventDateRange(events[j])
		if l1.After(l2) || e2.Before(e1) {
			less = true
		}
		return less
	})

	var earliest, latest []time.Time
	for _, event := range events {
		e, l := db.EventDateRange(event)

		earliest = append(earliest, e)
		latest = append(latest, l)
	}

	return events, earliest, latest
}

// Obtain the enumeration IDs that include the provided domain
func eventUUIDs(domains []string, db *graph.Graph) []string {
	var uuids []string

	for _, id := range db.EventList() {
		if len(domains) == 0 {
			uuids = append(uuids, id)
			continue
		}

		var count int
		surface := db.EventDomains(id)
		for _, domain := range surface {
			if domainNameInScope(domain, domains) {
				count++
			}
		}

		if count == len(domains) {
			uuids = append(uuids, id)
		}
	}

	return uuids
}

func memGraphForScope(domains []string, from *graph.Graph) (*graph.Graph, error) {
	db := graph.NewGraph(graph.NewCayleyGraphMemory())
	if db == nil {
		return nil, errors.New("Failed to create the in-memory graph database")
	}

	// Migrate the event data into the in-memory graph database
	if err := from.MigrateEventsInScope(db, domains); err != nil {
		return nil, fmt.Errorf("Failed to move the data into the in-memory graph database: %v", err)
	}

	return db, nil
}

func getEventOutput(uuids []string, db *graph.Graph) []*requests.Output {
	var output []*requests.Output
	cache := net.NewASNCache()
	filter := stringfilter.NewStringFilter()

	for i := len(uuids) - 1; i >= 0; i-- {
		for _, out := range db.EventOutput(uuids[i], filter, true, cache) {
			output = append(output, out)
		}
	}

	return output
}

func domainNameInScope(name string, scope []string) bool {
	var discovered bool

	n := strings.ToLower(strings.TrimSpace(name))
	for _, d := range scope {
		d = strings.ToLower(d)

		if n == d || strings.HasSuffix(n, "."+d) {
			discovered = true
			break
		}
	}

	return discovered
}

func healASInfo(uuids []string, db *graph.Graph) bool {
	cache := net.NewASNCache()
	db.ASNCacheFill(cache)

	cfg := config.NewConfig()
	cfg.LocalDatabase = false
	sys, err := systems.NewLocalSystem(cfg)
	if err != nil {
		return false
	}
	sys.SetDataSources(datasrcs.GetAllSources(sys))
	defer sys.Shutdown()

	bus := eventbus.NewEventBus()
	bus.Subscribe(requests.NewASNTopic, cache.Update)
	defer bus.Unsubscribe(requests.NewASNTopic, cache.Update)
	ctx := context.WithValue(context.Background(), requests.ContextConfig, cfg)
	ctx = context.WithValue(ctx, requests.ContextEventBus, bus)

	var updated bool
	for _, uuid := range uuids {
		for _, out := range db.EventOutput(uuid, nil, false, cache) {
			for _, a := range out.Addresses {
				if r := cache.AddrSearch(a.Address.String()); r != nil {
					db.InsertInfrastructure(r.ASN, r.Description, r.Address, r.Prefix, r.Source, r.Tag, uuid)
					continue
				}

				for _, src := range sys.DataSources() {
					src.ASNRequest(ctx, &requests.ASNRequest{Address: a.Address.String()})
				}

				for cache.AddrSearch(a.Address.String()) == nil {
					time.Sleep(time.Second)
				}

				if r := cache.AddrSearch(a.Address.String()); r != nil {
					db.InsertInfrastructure(r.ASN, r.Description, r.Address, r.Prefix, r.Source, r.Tag, uuid)
				}

				updated = true
			}
		}
	}

	return updated
}
<commit_msg>cmd/amass: remove unneeded for loop<commit_after>// Copyright © by Jeff Foley 2017-2020. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
// SPDX-License-Identifier: Apache-2.0

// In-depth Attack Surface Mapping and Asset Discovery
//  +----------------------------------------------------------------------------+
//  | ░░░░░░░░░░░░░░░░░░░░░░░░░░  OWASP Amass  ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ |
//  +----------------------------------------------------------------------------+
//  |      .+++:.            :                             .+++.                 |
//  |    +W@@@@@@8        &+W@#               o8W8:      +W@@@@@@#.   oW@@@W#+   |
//  |   &@#+   .o@##.    .@@@o@W.o@@o       :@@#&W8o    .@#:  .:oW+  .@#+++&#&   |
//  |  +@&        &@&     #@8 +@W@&8@+     :@W.   +@8   +@:          .@8         |
//  |  8@          @@     8@o  8@8  WW    .@W      W@+  .@W.          o@#:       |
//  |  WW          &@o    &@:  o@+  o@+   #@.      8@o   +W@#+.        +W@8:     |
//  |  #@          :@W    &@+  &@+   @8  :@o       o@o     oW@@W+        oW@8    |
//  |  o@+          @@&   &@+  &@+   #@  &@.      .W@W       .+#@&         o@W.  |
//  |   WW         +@W@8. &@+  :&    o@+ #@      :@W&@&         &@:  ..     :@o  |
//  |   :@W:      o@# +Wo &@+        :W: +@W&o++o@W. &@&  8@#o+&@W.  #@:    o@+  |
//  |    :W@@WWWW@@8       +              :&W@@@@&    &W  .o#@@W&.   :W@WWW@@&   |
//  |      +o&&&&+.                                                    +oooo.    |
//  +----------------------------------------------------------------------------+
package main

import (
	"bytes"
	"context"
	"errors"
	"flag"
	"fmt"
	"os"
	"path"
	"sort"
	"strings"
	"time"

	"github.com/OWASP/Amass/v3/config"
	"github.com/OWASP/Amass/v3/datasrcs"
	"github.com/OWASP/Amass/v3/eventbus"
	"github.com/OWASP/Amass/v3/format"
	"github.com/OWASP/Amass/v3/graph"
	"github.com/OWASP/Amass/v3/net"
	"github.com/OWASP/Amass/v3/requests"
	"github.com/OWASP/Amass/v3/stringfilter"
	"github.com/OWASP/Amass/v3/systems"
	"github.com/fatih/color"
)

const (
	mainUsageMsg         = "intel|enum|viz|track|db|dns [options]"
	exampleConfigFileURL = "https://github.com/OWASP/Amass/blob/master/examples/config.ini"
	userGuideURL         = "https://github.com/OWASP/Amass/blob/master/doc/user_guide.md"
	tutorialURL          = "https://github.com/OWASP/Amass/blob/master/doc/tutorial.md"
)

var (
	// Colors used to ease the reading of program output
	g      = color.New(color.FgHiGreen)
	r      = color.New(color.FgHiRed)
	b      = color.New(color.FgHiBlue)
	fgR    = color.New(color.FgRed)
	fgY    = color.New(color.FgYellow)
	yellow = color.New(color.FgHiYellow).SprintFunc()
	green  = color.New(color.FgHiGreen).SprintFunc()
	blue   = color.New(color.FgHiBlue).SprintFunc()
	red    = color.New(color.FgHiRed).SprintFunc()
)

func commandUsage(msg string, cmdFlagSet *flag.FlagSet, errBuf *bytes.Buffer) {
	format.PrintBanner()
	g.Fprintf(color.Error, "Usage: %s %s\n\n", path.Base(os.Args[0]), msg)
	cmdFlagSet.PrintDefaults()
	g.Fprintln(color.Error, errBuf.String())

	if msg == mainUsageMsg {
		g.Fprintf(color.Error, "\nSubcommands: \n\n")
		g.Fprintf(color.Error, "\t%-11s - Discover targets for enumerations\n", "amass intel")
		g.Fprintf(color.Error, "\t%-11s - Perform enumerations and network mapping\n", "amass enum")
		g.Fprintf(color.Error, "\t%-11s - Visualize enumeration results\n", "amass viz")
		g.Fprintf(color.Error, "\t%-11s - Track differences between enumerations\n", "amass track")
		g.Fprintf(color.Error, "\t%-11s - Manipulate the Amass graph database\n", "amass db")
		g.Fprintf(color.Error, "\t%-11s - Resolve DNS names at high performance\n\n", "amass dns")
	}

	g.Fprintf(color.Error, "The user's guide can be found here: \n%s\n\n", userGuideURL)
	g.Fprintf(color.Error, "An example configuration file can be found here: \n%s\n\n", exampleConfigFileURL)
	g.Fprintf(color.Error, "The Amass tutorial can be found here: \n%s\n\n", tutorialURL)
}

func main() {
	var version, help1, help2 bool
	mainFlagSet := flag.NewFlagSet("amass", flag.ContinueOnError)

	defaultBuf := new(bytes.Buffer)
	mainFlagSet.SetOutput(defaultBuf)

	mainFlagSet.BoolVar(&help1, "h", false, "Show the program usage message")
	mainFlagSet.BoolVar(&help2, "help", false, "Show the program usage message")
	mainFlagSet.BoolVar(&version, "version", false, "Print the version number of this Amass binary")

	if len(os.Args) < 2 {
		commandUsage(mainUsageMsg, mainFlagSet, defaultBuf)
		return
	}

	if err := mainFlagSet.Parse(os.Args[1:]); err != nil {
		r.Fprintf(color.Error, "%v\n", err)
		os.Exit(1)
	}
	if help1 || help2 {
		commandUsage(mainUsageMsg, mainFlagSet, defaultBuf)
		return
	}
	if version {
		fmt.Fprintf(color.Error, "%s\n", format.Version)
		return
	}

	switch os.Args[1] {
	case "db":
		runDBCommand(os.Args[2:])
	case "dns":
		runDNSCommand(os.Args[2:])
	case "enum":
		runEnumCommand(os.Args[2:])
	case "intel":
		runIntelCommand(os.Args[2:])
	case "track":
		runTrackCommand(os.Args[2:])
	case "viz":
		runVizCommand(os.Args[2:])
	default:
		commandUsage(mainUsageMsg, mainFlagSet, defaultBuf)
		os.Exit(1)
	}
}

// GetAllSourceInfo returns the names of all Amass data sources.
func GetAllSourceInfo(cfg *config.Config) []string {
	var names []string

	if cfg == nil {
		cfg = config.NewConfig()
	}

	sys, err := systems.NewLocalSystem(cfg)
	if err != nil {
		return names
	}
	sys.SetDataSources(datasrcs.GetAllSources(sys))

	for _, src := range sys.DataSources() {
		names = append(names, fmt.Sprintf("%-20s\t%s", src.String(), src.Type()))
	}

	sys.Shutdown()
	return names
}

func createOutputDirectory(cfg *config.Config) {
	// Prepare output file paths
	dir := config.OutputDirectory(cfg.Dir)
	if dir == "" {
		r.Fprintln(color.Error, "Failed to obtain the output directory")
		os.Exit(1)
	}
	// If the directory does not yet exist, create it
	if err := os.MkdirAll(dir, 0755); err != nil {
		r.Fprintf(color.Error, "Failed to create the directory: %v\n", err)
		os.Exit(1)
	}
}

func generateCategoryMap(sys systems.System) map[string][]string {
	catToSources := make(map[string][]string)

	for _, src := range sys.DataSources() {
		t := src.Type()

		catToSources[t] = append(catToSources[t], src.String())
	}

	return catToSources
}

func expandCategoryNames(names []string, categories map[string][]string) []string {
	var newnames []string

	for _, name := range names {
		if _, found := categories[name]; found {
			newnames = append(newnames, categories[name]...)
			continue
		}

		newnames = append(newnames, name)
	}

	return newnames
}

func openGraphDatabase(dir string, cfg *config.Config) *graph.Graph {
	for _, db := range cfg.GraphDBs {
		if !db.Primary {
			continue
		}

		cayley := graph.NewCayleyGraph(db.System, db.URL, db.Options)
		if cayley == nil {
			return nil
		}

		g := graph.NewGraph(cayley)
		if g == nil {
			return nil
		}

		return g
	}

	if db := cfg.LocalDatabaseSettings(cfg.GraphDBs); db != nil {
		db.Options = ""

		cayley := graph.NewCayleyGraph(db.System, config.OutputDirectory(dir), db.Options)
		if cayley == nil {
			return nil
		}

		if g := graph.NewGraph(cayley); g != nil {
			return g
		}
	}

	return nil
}

func orderedEvents(events []string, db *graph.Graph) ([]string, []time.Time, []time.Time) {
	sort.Slice(events, func(i, j int) bool {
		var less bool

		e1, l1 := db.EventDateRange(events[i])
		e2, l2 := db.EventDateRange(events[j])
		if l1.After(l2) || e2.Before(e1) {
			less = true
		}
		return less
	})

	var earliest, latest []time.Time
	for _, event := range events {
		e, l := db.EventDateRange(event)

		earliest = append(earliest, e)
		latest = append(latest, l)
	}

	return events, earliest, latest
}

// Obtain the enumeration IDs that include the provided domain
func eventUUIDs(domains []string, db *graph.Graph) []string {
	var uuids []string

	for _, id := range db.EventList() {
		if len(domains) == 0 {
			uuids = append(uuids, id)
			continue
		}

		var count int
		surface := db.EventDomains(id)
		for _, domain := range surface {
			if domainNameInScope(domain, domains) {
				count++
			}
		}

		if count == len(domains) {
			uuids = append(uuids, id)
		}
	}

	return uuids
}

func memGraphForScope(domains []string, from *graph.Graph) (*graph.Graph, error) {
	db := graph.NewGraph(graph.NewCayleyGraphMemory())
	if db == nil {
		return nil, errors.New("Failed to create the in-memory graph database")
	}

	// Migrate the event data into the in-memory graph database
	if err := from.MigrateEventsInScope(db, domains); err != nil {
		return nil, fmt.Errorf("Failed to move the data into the in-memory graph database: %v", err)
	}

	return db, nil
}

func getEventOutput(uuids []string, db *graph.Graph) []*requests.Output {
	var output []*requests.Output
	cache := net.NewASNCache()
	filter := stringfilter.NewStringFilter()

	for i := len(uuids) - 1; i >= 0; i-- {
		output = append(output, db.EventOutput(uuids[i], filter, true, cache)...)
	}

	return output
}

func domainNameInScope(name string, scope []string) bool {
	var discovered bool

	n := strings.ToLower(strings.TrimSpace(name))
	for _, d := range scope {
		d = strings.ToLower(d)

		if n == d || strings.HasSuffix(n, "."+d) {
			discovered = true
			break
		}
	}

	return discovered
}

func healASInfo(uuids []string, db *graph.Graph) bool {
	cache := net.NewASNCache()
	db.ASNCacheFill(cache)

	cfg := config.NewConfig()
	cfg.LocalDatabase = false
	sys, err := systems.NewLocalSystem(cfg)
	if err != nil {
		return false
	}
	sys.SetDataSources(datasrcs.GetAllSources(sys))
	defer sys.Shutdown()

	bus := eventbus.NewEventBus()
	bus.Subscribe(requests.NewASNTopic, cache.Update)
	defer bus.Unsubscribe(requests.NewASNTopic, cache.Update)
	ctx := context.WithValue(context.Background(), requests.ContextConfig, cfg)
	ctx = context.WithValue(ctx, requests.ContextEventBus, bus)

	var updated bool
	for _, uuid := range uuids {
		for _, out := range db.EventOutput(uuid, nil, false, cache) {
			for _, a := range out.Addresses {
				if r := cache.AddrSearch(a.Address.String()); r != nil {
					db.InsertInfrastructure(r.ASN, r.Description, r.Address, r.Prefix, r.Source, r.Tag, uuid)
					continue
				}

				for _, src := range sys.DataSources() {
					src.ASNRequest(ctx, &requests.ASNRequest{Address: a.Address.String()})
				}

				for cache.AddrSearch(a.Address.String()) == nil {
					time.Sleep(time.Second)
				}

				if r := cache.AddrSearch(a.Address.String()); r != nil {
					db.InsertInfrastructure(r.ASN, r.Description, r.Address, r.Prefix, r.Source, r.Tag, uuid)
				}

				updated = true
			}
		}
	}

	return updated
}
<|endoftext|>


<commit_before>/*
   Copyright 2020 Docker Compose CLI authors

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

package compose

import (
	"context"
	"fmt"
	"io"
	"os"
	"sort"
	"strconv"
	"strings"

	"github.com/docker/compose/v2/cmd/formatter"
	"github.com/docker/compose/v2/pkg/utils"

	formatter2 "github.com/docker/cli/cli/command/formatter"
	"github.com/pkg/errors"
	"github.com/spf13/cobra"

	"github.com/docker/compose/v2/pkg/api"
)

type psOptions struct {
	*projectOptions
	Format   string
	All      bool
	Quiet    bool
	Services bool
	Filter   string
	Status   []string
}

func (p *psOptions) parseFilter() error {
	if p.Filter == "" {
		return nil
	}
	parts := strings.SplitN(p.Filter, "=", 2)
	if len(parts) != 2 {
		return errors.New("arguments to --filter should be in form KEY=VAL")
	}
	switch parts[0] {
	case "status":
		p.Status = append(p.Status, parts[1])
	case "source":
		return api.ErrNotImplemented
	default:
		return fmt.Errorf("unknow filter %s", parts[0])
	}
	return nil
}

func psCommand(p *projectOptions, backend api.Service) *cobra.Command {
	opts := psOptions{
		projectOptions: p,
	}
	psCmd := &cobra.Command{
		Use:   "ps [SERVICE...]",
		Short: "List containers",
		PreRunE: func(cmd *cobra.Command, args []string) error {
			return opts.parseFilter()
		},
		RunE: Adapt(func(ctx context.Context, args []string) error {
			return runPs(ctx, backend, args, opts)
		}),
		ValidArgsFunction: serviceCompletion(p),
	}
	flags := psCmd.Flags()
	flags.StringVar(&opts.Format, "format", "pretty", "Format the output. Values: [pretty | json]")
	flags.StringVar(&opts.Filter, "filter", "", "Filter services by a property. Deprecated, use --status instead")
	flags.StringArrayVar(&opts.Status, "status", []string{}, "Filter services by status. Values: [paused | restarting | removing | running | dead | created | exited]")
	flags.BoolVarP(&opts.Quiet, "quiet", "q", false, "Only display IDs")
	flags.BoolVar(&opts.Services, "services", false, "Display services")
	flags.BoolVarP(&opts.All, "all", "a", false, "Show all stopped containers (including those created by the run command)")
	flags.Lookup("filter").Hidden = true
	return psCmd
}

func runPs(ctx context.Context, backend api.Service, services []string, opts psOptions) error {
	projectName, err := opts.toProjectName()
	if err != nil {
		return err
	}
	containers, err := backend.Ps(ctx, projectName, api.PsOptions{
		All:      opts.All,
		Services: services,
	})
	if err != nil {
		return err
	}

SERVICES:
	for _, s := range services {
		for _, c := range containers {
			if c.Service == s {
				continue SERVICES
			}
		}
		return fmt.Errorf("no such service: %s", s)
	}

	if len(opts.Status) != 0 {
		containers = filterByStatus(containers, opts.Status)
	}

	sort.Slice(containers, func(i, j int) bool {
		return containers[i].Name < containers[j].Name
	})

	if opts.Quiet {
		for _, c := range containers {
			fmt.Println(c.ID)
		}
		return nil
	}

	if opts.Services {
		services := []string{}
		for _, s := range containers {
			if !utils.StringContains(services, s.Service) {
				services = append(services, s.Service)
			}
		}
		fmt.Println(strings.Join(services, "\n"))
		return nil
	}

	return formatter.Print(containers, opts.Format, os.Stdout,
		writter(containers),
		"NAME", "COMMAND", "SERVICE", "STATUS", "PORTS")
}

func writter(containers []api.ContainerSummary) func(w io.Writer) {
	return func(w io.Writer) {
		for _, container := range containers {
			ports := DisplayablePorts(container)
			status := container.State
			if status == "running" && container.Health != "" {
				status = fmt.Sprintf("%s (%s)", container.State, container.Health)
			} else if status == "exited" || status == "dead" {
				status = fmt.Sprintf("%s (%d)", container.State, container.ExitCode)
			}
			command := formatter2.Ellipsis(container.Command, 20)
			_, _ = fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\n", container.Name, strconv.Quote(command), container.Service, status, ports)
		}
	}
}

func filterByStatus(containers []api.ContainerSummary, statuses []string) []api.ContainerSummary {
	var filtered []api.ContainerSummary
	for _, c := range containers {
		if hasStatus(c, statuses) {
			filtered = append(filtered, c)
		}
	}
	return filtered
}

func hasStatus(c api.ContainerSummary, statuses []string) bool {
	for _, status := range statuses {
		if c.State == status {
			return true
		}
	}
	return false
}

type portRange struct {
	pStart   int
	pEnd     int
	tStart   int
	tEnd     int
	IP       string
	protocol string
}

func (pr portRange) String() string {
	var (
		pub string
		tgt string
	)

	if pr.pEnd > pr.pStart {
		pub = fmt.Sprintf("%s:%d-%d->", pr.IP, pr.pStart, pr.pEnd)
	} else if pr.pStart > 0 {
		pub = fmt.Sprintf("%s:%d->", pr.IP, pr.pStart)
	}
	if pr.tEnd > pr.tStart {
		tgt = fmt.Sprintf("%d-%d", pr.tStart, pr.tEnd)
	} else {
		tgt = fmt.Sprintf("%d", pr.tStart)
	}
	return fmt.Sprintf("%s%s/%s", pub, tgt, pr.protocol)
}

// DisplayablePorts is copy pasted from https://github.com/docker/cli/pull/581/files
func DisplayablePorts(c api.ContainerSummary) string {
	if c.Publishers == nil {
		return ""
	}

	sort.Sort(c.Publishers)

	pr := portRange{}
	ports := []string{}
	for _, p := range c.Publishers {
		prIsRange := pr.tEnd != pr.tStart
		tOverlaps := p.TargetPort <= pr.tEnd

		// Start a new port-range if:
		// - the protocol is different from the current port-range
		// - published or target port are not consecutive to the current port-range
		// - the current port-range is a _range_, and the target port overlaps with the current range's target-ports
		if p.Protocol != pr.protocol || p.URL != pr.IP || p.PublishedPort-pr.pEnd > 1 || p.TargetPort-pr.tEnd > 1 || prIsRange && tOverlaps {
			// start a new port-range, and print the previous port-range (if any)
			if pr.pStart > 0 {
				ports = append(ports, pr.String())
			}
			pr = portRange{
				pStart:   p.PublishedPort,
				pEnd:     p.PublishedPort,
				tStart:   p.TargetPort,
				tEnd:     p.TargetPort,
				protocol: p.Protocol,
				IP:       p.URL,
			}
			continue
		}
		pr.pEnd = p.PublishedPort
		pr.tEnd = p.TargetPort
	}
	if pr.tStart > 0 {
		ports = append(ports, pr.String())
	}
	return strings.Join(ports, ", ")
}
<commit_msg>compose ps: fix typo "unknow" -> "unknown"<commit_after>/*
   Copyright 2020 Docker Compose CLI authors

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

package compose

import (
	"context"
	"fmt"
	"io"
	"os"
	"sort"
	"strconv"
	"strings"

	"github.com/docker/compose/v2/cmd/formatter"
	"github.com/docker/compose/v2/pkg/utils"

	formatter2 "github.com/docker/cli/cli/command/formatter"
	"github.com/pkg/errors"
	"github.com/spf13/cobra"

	"github.com/docker/compose/v2/pkg/api"
)

type psOptions struct {
	*projectOptions
	Format   string
	All      bool
	Quiet    bool
	Services bool
	Filter   string
	Status   []string
}

func (p *psOptions) parseFilter() error {
	if p.Filter == "" {
		return nil
	}
	parts := strings.SplitN(p.Filter, "=", 2)
	if len(parts) != 2 {
		return errors.New("arguments to --filter should be in form KEY=VAL")
	}
	switch parts[0] {
	case "status":
		p.Status = append(p.Status, parts[1])
	case "source":
		return api.ErrNotImplemented
	default:
		return fmt.Errorf("unknown filter %s", parts[0])
	}
	return nil
}

func psCommand(p *projectOptions, backend api.Service) *cobra.Command {
	opts := psOptions{
		projectOptions: p,
	}
	psCmd := &cobra.Command{
		Use:   "ps [SERVICE...]",
		Short: "List containers",
		PreRunE: func(cmd *cobra.Command, args []string) error {
			return opts.parseFilter()
		},
		RunE: Adapt(func(ctx context.Context, args []string) error {
			return runPs(ctx, backend, args, opts)
		}),
		ValidArgsFunction: serviceCompletion(p),
	}
	flags := psCmd.Flags()
	flags.StringVar(&opts.Format, "format", "pretty", "Format the output. Values: [pretty | json]")
	flags.StringVar(&opts.Filter, "filter", "", "Filter services by a property. Deprecated, use --status instead")
	flags.StringArrayVar(&opts.Status, "status", []string{}, "Filter services by status. Values: [paused | restarting | removing | running | dead | created | exited]")
	flags.BoolVarP(&opts.Quiet, "quiet", "q", false, "Only display IDs")
	flags.BoolVar(&opts.Services, "services", false, "Display services")
	flags.BoolVarP(&opts.All, "all", "a", false, "Show all stopped containers (including those created by the run command)")
	flags.Lookup("filter").Hidden = true
	return psCmd
}

func runPs(ctx context.Context, backend api.Service, services []string, opts psOptions) error {
	projectName, err := opts.toProjectName()
	if err != nil {
		return err
	}
	containers, err := backend.Ps(ctx, projectName, api.PsOptions{
		All:      opts.All,
		Services: services,
	})
	if err != nil {
		return err
	}

SERVICES:
	for _, s := range services {
		for _, c := range containers {
			if c.Service == s {
				continue SERVICES
			}
		}
		return fmt.Errorf("no such service: %s", s)
	}

	if len(opts.Status) != 0 {
		containers = filterByStatus(containers, opts.Status)
	}

	sort.Slice(containers, func(i, j int) bool {
		return containers[i].Name < containers[j].Name
	})

	if opts.Quiet {
		for _, c := range containers {
			fmt.Println(c.ID)
		}
		return nil
	}

	if opts.Services {
		services := []string{}
		for _, s := range containers {
			if !utils.StringContains(services, s.Service) {
				services = append(services, s.Service)
			}
		}
		fmt.Println(strings.Join(services, "\n"))
		return nil
	}

	return formatter.Print(containers, opts.Format, os.Stdout,
		writter(containers),
		"NAME", "COMMAND", "SERVICE", "STATUS", "PORTS")
}

func writter(containers []api.ContainerSummary) func(w io.Writer) {
	return func(w io.Writer) {
		for _, container := range containers {
			ports := DisplayablePorts(container)
			status := container.State
			if status == "running" && container.Health != "" {
				status = fmt.Sprintf("%s (%s)", container.State, container.Health)
			} else if status == "exited" || status == "dead" {
				status = fmt.Sprintf("%s (%d)", container.State, container.ExitCode)
			}
			command := formatter2.Ellipsis(container.Command, 20)
			_, _ = fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\n", container.Name, strconv.Quote(command), container.Service, status, ports)
		}
	}
}

func filterByStatus(containers []api.ContainerSummary, statuses []string) []api.ContainerSummary {
	var filtered []api.ContainerSummary
	for _, c := range containers {
		if hasStatus(c, statuses) {
			filtered = append(filtered, c)
		}
	}
	return filtered
}

func hasStatus(c api.ContainerSummary, statuses []string) bool {
	for _, status := range statuses {
		if c.State == status {
			return true
		}
	}
	return false
}

type portRange struct {
	pStart   int
	pEnd     int
	tStart   int
	tEnd     int
	IP       string
	protocol string
}

func (pr portRange) String() string {
	var (
		pub string
		tgt string
	)

	if pr.pEnd > pr.pStart {
		pub = fmt.Sprintf("%s:%d-%d->", pr.IP, pr.pStart, pr.pEnd)
	} else if pr.pStart > 0 {
		pub = fmt.Sprintf("%s:%d->", pr.IP, pr.pStart)
	}
	if pr.tEnd > pr.tStart {
		tgt = fmt.Sprintf("%d-%d", pr.tStart, pr.tEnd)
	} else {
		tgt = fmt.Sprintf("%d", pr.tStart)
	}
	return fmt.Sprintf("%s%s/%s", pub, tgt, pr.protocol)
}

// DisplayablePorts is copy pasted from https://github.com/docker/cli/pull/581/files
func DisplayablePorts(c api.ContainerSummary) string {
	if c.Publishers == nil {
		return ""
	}

	sort.Sort(c.Publishers)

	pr := portRange{}
	ports := []string{}
	for _, p := range c.Publishers {
		prIsRange := pr.tEnd != pr.tStart
		tOverlaps := p.TargetPort <= pr.tEnd

		// Start a new port-range if:
		// - the protocol is different from the current port-range
		// - published or target port are not consecutive to the current port-range
		// - the current port-range is a _range_, and the target port overlaps with the current range's target-ports
		if p.Protocol != pr.protocol || p.URL != pr.IP || p.PublishedPort-pr.pEnd > 1 || p.TargetPort-pr.tEnd > 1 || prIsRange && tOverlaps {
			// start a new port-range, and print the previous port-range (if any)
			if pr.pStart > 0 {
				ports = append(ports, pr.String())
			}
			pr = portRange{
				pStart:   p.PublishedPort,
				pEnd:     p.PublishedPort,
				tStart:   p.TargetPort,
				tEnd:     p.TargetPort,
				protocol: p.Protocol,
				IP:       p.URL,
			}
			continue
		}
		pr.pEnd = p.PublishedPort
		pr.tEnd = p.TargetPort
	}
	if pr.tStart > 0 {
		ports = append(ports, pr.String())
	}
	return strings.Join(ports, ", ")
}
<|endoftext|>


<commit_before>// gowww is the CLI of the gowww/app framework.
package main

import (
	"flag"
	"fmt"
	"os"
	"os/exec"
	"os/signal"
	"path/filepath"
	"regexp"

	"github.com/fsnotify/fsnotify"
)

var (
	flagName        = flag.String("name", getwd(false), "The file name used for build.")
	flagBuildDocker = flag.Bool("docker", false, `User Docker's "golang:latest" image to build for Linux.`)

	subprocArgs []string
	watcher     *fsnotify.Watcher
	runningProc *os.Process

	reFilenameGo              = regexp.MustCompile(`^[0-9A-Za-z_-]+[^_test].go$`)
	reFilenameScriptsGopherJS = regexp.MustCompile(`^scripts/[0-9A-Za-z_-]+[^_test].go$`)
	reFilenameViews           = regexp.MustCompile(`^views/[0-9A-Za-z_-]+.gohtml$`)
)

func flagParse() {

}

func main() {
	defer clean()
	atexit(clean)

	flag.Usage = help
	flag.Parse()

	// Pass args after "--" to subprocess.
	for i := 0; i < len(os.Args); i++ {
		if os.Args[i] == "--" {
			subprocArgs = os.Args[i+1:]
		}
	}

	switch flag.Arg(0) {
	case "", "watch":
		watch()
	case "build":
		build()
	default:
		help()
	}
}

func run() {
	if runningProc != nil {
		if err := runningProc.Kill(); err != nil {
			panic(err)
		}
	}
	cmd := exec.Command("./"+buildName(), subprocArgs...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	if err := cmd.Start(); err != nil {
		panic(err)
	}
	runningProc = cmd.Process
}

func clean() {
	if watcher != nil {
		watcher.Close()
	}
	if runningProc != nil {
		runningProc.Kill()
	}
}

func cleanLines(n int) {
	fmt.Printf("\033[%dA\033[0K", n)
}

func getwd(fullpath bool) string {
	wd, err := os.Getwd()
	if err != nil {
		panic(err)
	}
	if fullpath {
		return wd
	}
	return filepath.Base(wd)
}

func atexit(f func()) {
	s := make(chan os.Signal, 1)
	signal.Notify(s, os.Interrupt)
	go func() {
		<-s
		f()
		os.Exit(0)
	}()
}
<commit_msg>Remove residue<commit_after>// gowww is the CLI of the gowww/app framework.
package main

import (
	"flag"
	"fmt"
	"os"
	"os/exec"
	"os/signal"
	"path/filepath"
	"regexp"

	"github.com/fsnotify/fsnotify"
)

var (
	flagName        = flag.String("name", getwd(false), "The file name used for build.")
	flagBuildDocker = flag.Bool("docker", false, `User Docker's "golang:latest" image to build for Linux.`)

	subprocArgs []string
	watcher     *fsnotify.Watcher
	runningProc *os.Process

	reFilenameGo              = regexp.MustCompile(`^[0-9A-Za-z_-]+[^_test].go$`)
	reFilenameScriptsGopherJS = regexp.MustCompile(`^scripts/[0-9A-Za-z_-]+[^_test].go$`)
	reFilenameViews           = regexp.MustCompile(`^views/[0-9A-Za-z_-]+.gohtml$`)
)

func main() {
	defer clean()
	atexit(clean)

	flag.Usage = help
	flag.Parse()

	// Pass args after "--" to subprocess.
	for i := 0; i < len(os.Args); i++ {
		if os.Args[i] == "--" {
			subprocArgs = os.Args[i+1:]
		}
	}

	switch flag.Arg(0) {
	case "", "watch":
		watch()
	case "build":
		build()
	default:
		help()
	}
}

func run() {
	if runningProc != nil {
		if err := runningProc.Kill(); err != nil {
			panic(err)
		}
	}
	cmd := exec.Command("./"+buildName(), subprocArgs...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	if err := cmd.Start(); err != nil {
		panic(err)
	}
	runningProc = cmd.Process
}

func clean() {
	if watcher != nil {
		watcher.Close()
	}
	if runningProc != nil {
		runningProc.Kill()
	}
}

func cleanLines(n int) {
	fmt.Printf("\033[%dA\033[0K", n)
}

func getwd(fullpath bool) string {
	wd, err := os.Getwd()
	if err != nil {
		panic(err)
	}
	if fullpath {
		return wd
	}
	return filepath.Base(wd)
}

func atexit(f func()) {
	s := make(chan os.Signal, 1)
	signal.Notify(s, os.Interrupt)
	go func() {
		<-s
		f()
		os.Exit(0)
	}()
}
<|endoftext|>


<commit_before>// Copyright 2014 Volker Dobler.  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"
)

var cmdVersion = &Command{
	RunArgs:     runVersion,
	Usage:       "version",
	Description: "print version information",
	Flag:        flag.NewFlagSet("version", flag.ContinueOnError),
	Help: `
Version prints version information about ht.
	`,
}

var (
	version = "2.2.0"
)

func runVersion(cmd *Command, _ []string) {
	fmt.Printf("ht version %s\n", version)
}
<commit_msg>all: increase version to 2.3<commit_after>// Copyright 2014 Volker Dobler.  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"
)

var cmdVersion = &Command{
	RunArgs:     runVersion,
	Usage:       "version",
	Description: "print version information",
	Flag:        flag.NewFlagSet("version", flag.ContinueOnError),
	Help: `
Version prints version information about ht.
	`,
}

var (
	version = "2.3.0"
)

func runVersion(cmd *Command, _ []string) {
	fmt.Printf("ht version %s\n", version)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io"
	"os"
	"os/signal"
	"runtime/pprof"

	logging "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-logging"
	ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
	manet "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr/net"

	cmds "github.com/jbenet/go-ipfs/commands"
	cmdsCli "github.com/jbenet/go-ipfs/commands/cli"
	cmdsHttp "github.com/jbenet/go-ipfs/commands/http"
	"github.com/jbenet/go-ipfs/config"
	"github.com/jbenet/go-ipfs/core"
	commands "github.com/jbenet/go-ipfs/core/commands2"
	daemon "github.com/jbenet/go-ipfs/daemon2"
	u "github.com/jbenet/go-ipfs/util"
)

// log is the command logger
var log = u.Logger("cmd/ipfs")

const (
	heapProfile = "ipfs.mprof"
	errorFormat = "ERROR: %v\n\n"
)

var ofi io.WriteCloser

func main() {
	handleInterrupt()

	args := os.Args[1:]
	req, root, err := createRequest(args)
	if err != nil {
		fmt.Println(err)
		exit(1)
	}
	handleOptions(req, root)

	// if debugging, setup profiling.
	if u.Debug {
		var err error
		ofi, err = os.Create("cpu.prof")
		if err != nil {
			fmt.Println(err)
			return
		}

		pprof.StartCPUProfile(ofi)
	}

	res := callCommand(req, root)
	outputResponse(res, root)

	exit(0)
}

func createRequest(args []string) (cmds.Request, *cmds.Command, error) {
	req, root, cmd, path, err := cmdsCli.Parse(args, Root, commands.Root)

	// handle parse error (which means the commandline input was wrong,
	// e.g. incorrect number of args, or nonexistent subcommand)
	if err != nil {
		// if the -help flag wasn't specified, show the error message
		// or if a path was returned (user specified a valid subcommand), show the error message
		// (this means there was an option or argument error)
		if path != nil && len(path) > 0 {
			help, _ := req.Option("help").Bool()
			if !help {
				fmt.Printf(errorFormat, err)
			}
		}

		// when generating help for the root command, we don't want the autogenerated subcommand text
		// (since we have better hand-made subcommand list in the root Help field)
		if cmd == nil {
			root = &*commands.Root
			root.Subcommands = nil
		}

		// generate the help text for the command the user was trying to call (or root)
		helpText, htErr := cmdsCli.HelpText("ipfs", root, path)
		if htErr != nil {
			fmt.Println(htErr)
		} else {
			fmt.Println(helpText)
		}
		return nil, nil, err
	}

	configPath, err := getConfigRoot(req)
	if err != nil {
		return nil, nil, err
	}

	conf, err := getConfig(configPath)
	if err != nil {
		return nil, nil, err
	}
	ctx := req.Context()
	ctx.ConfigRoot = configPath
	ctx.Config = conf

	if !req.Option("encoding").Found() {
		if req.Command().Marshallers != nil && req.Command().Marshallers[cmds.Text] != nil {
			req.SetOption("encoding", cmds.Text)
		} else {
			req.SetOption("encoding", cmds.JSON)
		}
	}

	return req, root, nil
}

func handleOptions(req cmds.Request, root *cmds.Command) {
	if help, err := req.Option("help").Bool(); help && err == nil {
		helpText, err := cmdsCli.HelpText("ipfs", root, req.Path())
		if err != nil {
			fmt.Println(err.Error())
		} else {
			fmt.Println(helpText)
		}
		exit(0)
	} else if err != nil {
		fmt.Println(err)
		exit(1)
	}

	if debug, err := req.Option("debug").Bool(); debug && err == nil {
		u.Debug = true
		u.SetAllLoggers(logging.DEBUG)
	} else if err != nil {
		fmt.Println(err)
		exit(1)
	}
}

func callCommand(req cmds.Request, root *cmds.Command) cmds.Response {
	var res cmds.Response

	if root == Root {
		res = root.Call(req)

	} else {
		local, err := req.Option("local").Bool()
		if err != nil {
			fmt.Println(err)
			exit(1)
		}

		if (!req.Option("local").Found() || !local) && daemon.Locked(req.Context().ConfigRoot) {
			addr, err := ma.NewMultiaddr(req.Context().Config.Addresses.API)
			if err != nil {
				fmt.Println(err)
				exit(1)
			}

			_, host, err := manet.DialArgs(addr)
			if err != nil {
				fmt.Println(err)
				exit(1)
			}

			client := cmdsHttp.NewClient(host)

			res, err = client.Send(req)
			if err != nil {
				fmt.Println(err)
				exit(1)
			}

		} else {
			node, err := core.NewIpfsNode(req.Context().Config, false)
			if err != nil {
				fmt.Println(err)
				exit(1)
			}
			defer node.Close()
			req.Context().Node = node

			res = root.Call(req)
		}
	}

	return res
}

func outputResponse(res cmds.Response, root *cmds.Command) {
	if res.Error() != nil {
		fmt.Printf(errorFormat, res.Error().Error())

		if res.Error().Code == cmds.ErrClient {
			helpText, err := cmdsCli.HelpText("ipfs", root, res.Request().Path())
			if err != nil {
				fmt.Println(err.Error())
			} else {
				fmt.Println(helpText)
			}
		}

		exit(1)
	}

	out, err := res.Reader()
	if err != nil {
		fmt.Println(err.Error())
		return
	}

	io.Copy(os.Stdout, out)
}

func getConfigRoot(req cmds.Request) (string, error) {
	configOpt, err := req.Option("config").String()
	if err != nil {
		return "", err
	}
	if configOpt != "" {
		return configOpt, nil
	}

	configPath, err := config.PathRoot()
	if err != nil {
		return "", err
	}
	return configPath, nil
}

func getConfig(path string) (*config.Config, error) {
	configFile, err := config.Filename(path)
	if err != nil {
		return nil, err
	}

	return config.Load(configFile)
}

func writeHeapProfileToFile() error {
	mprof, err := os.Create(heapProfile)
	if err != nil {
		log.Fatal(err)
	}
	defer mprof.Close()
	return pprof.WriteHeapProfile(mprof)
}

// listen for and handle SIGTERM
func handleInterrupt() {
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)

	go func() {
		for _ = range c {
			log.Info("Received interrupt signal, terminating...")
			exit(0)
		}
	}()
}

func exit(code int) {
	if u.Debug {
		pprof.StopCPUProfile()
		ofi.Close()

		err := writeHeapProfileToFile()
		if err != nil {
			log.Critical(err)
		}
	}

	os.Exit(code)
}
<commit_msg>refactor(ipfs2/main) split lines<commit_after>package main

import (
	"fmt"
	"io"
	"os"
	"os/signal"
	"runtime/pprof"

	logging "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-logging"
	ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
	manet "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr/net"

	cmds "github.com/jbenet/go-ipfs/commands"
	cmdsCli "github.com/jbenet/go-ipfs/commands/cli"
	cmdsHttp "github.com/jbenet/go-ipfs/commands/http"
	"github.com/jbenet/go-ipfs/config"
	"github.com/jbenet/go-ipfs/core"
	commands "github.com/jbenet/go-ipfs/core/commands2"
	daemon "github.com/jbenet/go-ipfs/daemon2"
	u "github.com/jbenet/go-ipfs/util"
)

// log is the command logger
var log = u.Logger("cmd/ipfs")

const (
	heapProfile = "ipfs.mprof"
	errorFormat = "ERROR: %v\n\n"
)

var ofi io.WriteCloser

func main() {
	handleInterrupt()

	args := os.Args[1:]
	req, root, err := createRequest(args)
	if err != nil {
		fmt.Println(err)
		exit(1)
	}
	handleOptions(req, root)

	// if debugging, setup profiling.
	if u.Debug {
		var err error
		ofi, err = os.Create("cpu.prof")
		if err != nil {
			fmt.Println(err)
			return
		}

		pprof.StartCPUProfile(ofi)
	}

	res := callCommand(req, root)
	outputResponse(res, root)

	exit(0)
}

func createRequest(args []string) (cmds.Request, *cmds.Command, error) {
	req, root, cmd, path, err := cmdsCli.Parse(args, Root, commands.Root)

	// handle parse error (which means the commandline input was wrong,
	// e.g. incorrect number of args, or nonexistent subcommand)
	if err != nil {
		// if the -help flag wasn't specified, show the error message
		// or if a path was returned (user specified a valid subcommand), show the error message
		// (this means there was an option or argument error)
		if path != nil && len(path) > 0 {
			help, _ := req.Option("help").Bool()
			if !help {
				fmt.Printf(errorFormat, err)
			}
		}

		// when generating help for the root command, we don't want the autogenerated subcommand text
		// (since we have better hand-made subcommand list in the root Help field)
		if cmd == nil {
			root = &*commands.Root
			root.Subcommands = nil
		}

		// generate the help text for the command the user was trying to call (or root)
		helpText, htErr := cmdsCli.HelpText("ipfs", root, path)
		if htErr != nil {
			fmt.Println(htErr)
		} else {
			fmt.Println(helpText)
		}
		return nil, nil, err
	}

	configPath, err := getConfigRoot(req)
	if err != nil {
		return nil, nil, err
	}

	conf, err := getConfig(configPath)
	if err != nil {
		return nil, nil, err
	}
	ctx := req.Context()
	ctx.ConfigRoot = configPath
	ctx.Config = conf

	if !req.Option("encoding").Found() {
		if req.Command().Marshallers != nil && req.Command().Marshallers[cmds.Text] != nil {
			req.SetOption("encoding", cmds.Text)
		} else {
			req.SetOption("encoding", cmds.JSON)
		}
	}

	return req, root, nil
}

func handleOptions(req cmds.Request, root *cmds.Command) {
	help, err := req.Option("help").Bool()
	if help && err == nil {
		helpText, err := cmdsCli.HelpText("ipfs", root, req.Path())
		if err != nil {
			fmt.Println(err.Error())
		} else {
			fmt.Println(helpText)
		}
		exit(0)
	} else if err != nil {
		fmt.Println(err)
		exit(1)
	}

	if debug, err := req.Option("debug").Bool(); debug && err == nil {
		u.Debug = true
		u.SetAllLoggers(logging.DEBUG)
	} else if err != nil {
		fmt.Println(err)
		exit(1)
	}
}

func callCommand(req cmds.Request, root *cmds.Command) cmds.Response {
	var res cmds.Response

	if root == Root {
		res = root.Call(req)

	} else {
		local, err := req.Option("local").Bool()
		if err != nil {
			fmt.Println(err)
			exit(1)
		}

		if (!req.Option("local").Found() || !local) && daemon.Locked(req.Context().ConfigRoot) {
			addr, err := ma.NewMultiaddr(req.Context().Config.Addresses.API)
			if err != nil {
				fmt.Println(err)
				exit(1)
			}

			_, host, err := manet.DialArgs(addr)
			if err != nil {
				fmt.Println(err)
				exit(1)
			}

			client := cmdsHttp.NewClient(host)

			res, err = client.Send(req)
			if err != nil {
				fmt.Println(err)
				exit(1)
			}

		} else {
			node, err := core.NewIpfsNode(req.Context().Config, false)
			if err != nil {
				fmt.Println(err)
				exit(1)
			}
			defer node.Close()
			req.Context().Node = node

			res = root.Call(req)
		}
	}

	return res
}

func outputResponse(res cmds.Response, root *cmds.Command) {
	if res.Error() != nil {
		fmt.Printf(errorFormat, res.Error().Error())

		if res.Error().Code == cmds.ErrClient {
			helpText, err := cmdsCli.HelpText("ipfs", root, res.Request().Path())
			if err != nil {
				fmt.Println(err.Error())
			} else {
				fmt.Println(helpText)
			}
		}

		exit(1)
	}

	out, err := res.Reader()
	if err != nil {
		fmt.Println(err.Error())
		return
	}

	io.Copy(os.Stdout, out)
}

func getConfigRoot(req cmds.Request) (string, error) {
	configOpt, err := req.Option("config").String()
	if err != nil {
		return "", err
	}
	if configOpt != "" {
		return configOpt, nil
	}

	configPath, err := config.PathRoot()
	if err != nil {
		return "", err
	}
	return configPath, nil
}

func getConfig(path string) (*config.Config, error) {
	configFile, err := config.Filename(path)
	if err != nil {
		return nil, err
	}

	return config.Load(configFile)
}

func writeHeapProfileToFile() error {
	mprof, err := os.Create(heapProfile)
	if err != nil {
		log.Fatal(err)
	}
	defer mprof.Close()
	return pprof.WriteHeapProfile(mprof)
}

// listen for and handle SIGTERM
func handleInterrupt() {
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)

	go func() {
		for _ = range c {
			log.Info("Received interrupt signal, terminating...")
			exit(0)
		}
	}()
}

func exit(code int) {
	if u.Debug {
		pprof.StopCPUProfile()
		ofi.Close()

		err := writeHeapProfileToFile()
		if err != nil {
			log.Critical(err)
		}
	}

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


<commit_before>package cmd

import (
	"bytes"
	"fmt"
	"log"
	"runtime"
	"strconv"
	"strings"
	"text/template"

	"github.com/rsteube/carapace"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
	gitlab "github.com/xanzy/go-gitlab"
	"github.com/zaquestion/lab/internal/action"
	"github.com/zaquestion/lab/internal/git"
	lab "github.com/zaquestion/lab/internal/gitlab"
)

var issueEditCmd = &cobra.Command{
	Use:     "edit [remote] <id>",
	Aliases: []string{"update"},
	Short:   "Edit or update an issue",
	Long:    ``,
	Example: `lab issue edit <id>                                # update issue via $EDITOR
lab issue update <id>                              # same as above
lab issue edit <id> -m "new title"                 # update title
lab issue edit <id> -m "new title" -m "new desc"   # update title & description
lab issue edit <id> -l newlabel --unlabel oldlabel # relabel issue`,
	Args:             cobra.MinimumNArgs(1),
	PersistentPreRun: LabPersistentPreRun,
	Run: func(cmd *cobra.Command, args []string) {
		// get remote and issue from cmd arguments
		rn, issueNum, err := parseArgs(args)
		if err != nil {
			log.Fatal(err)
		}

		// get existing issue
		issue, err := lab.IssueGet(rn, int(issueNum))
		if err != nil {
			log.Fatal(err)
		}

		labels, labelsChanged, err := issueEditGetLabels(issue, cmd.Flags())
		if err != nil {
			log.Fatal(err)
		}

		assigneeIDs, assigneesChanged, err := issueEditGetAssignees(issue, cmd.Flags())
		if err != nil {
			log.Fatal(err)
		}

		title, body, err := issueEditGetTitleDescription(issue, cmd.Flags())
		if err != nil {
			_, f, l, _ := runtime.Caller(0)
			log.Fatal(f+":"+strconv.Itoa(l)+" ", err)
		}
		if title == "" {
			log.Fatal("aborting: empty issue title")
		}

		abortUpdate := title == issue.Title && body == issue.Description && !labelsChanged && !assigneesChanged
		if abortUpdate {
			log.Fatal("aborting: no changes")
		}

		linebreak, _ := cmd.Flags().GetBool("force-linebreak")
		if linebreak {
			body = textToMarkdown(body)
		}

		opts := &gitlab.UpdateIssueOptions{
			Title:       &title,
			Description: &body,
		}

		if labelsChanged {
			opts.Labels = lab.Labels(labels)
		}

		if assigneesChanged {
			opts.AssigneeIDs = assigneeIDs
		}

		issueURL, err := lab.IssueUpdate(rn, int(issueNum), opts)
		if err != nil {
			log.Fatal(err)
		}
		fmt.Println(issueURL)
	},
}

// issueEditGetLabels returns a string slice of issues based on the current
// issue labels and flags from the command line, and a bool indicating whether
// the labels have changed
func issueEditGetLabels(issue *gitlab.Issue, flags *pflag.FlagSet) ([]string, bool, error) {
	// get the labels to add
	labels, err := flags.GetStringSlice("label")
	if err != nil {
		return []string{}, false, err
	}

	// get the labels to remove
	unlabels, err := flags.GetStringSlice("unlabel")
	if err != nil {
		return []string{}, false, err
	}

	// add the new labels to the current labels, then remove the "unlabels"
	labels = difference(union(issue.Labels, labels), unlabels)

	return labels, !same(issue.Labels, labels), nil
}

// issueEditGetAssignees returns an int slice of assignee IDs based on the
// current issue assignees and flags from the command line, and a bool
// indicating whether the assignees have changed
func issueEditGetAssignees(issue *gitlab.Issue, flags *pflag.FlagSet) ([]int, bool, error) {
	currentAssignees := make([]string, len(issue.Assignees))
	if len(issue.Assignees) > 0 && issue.Assignees[0].Username != "" {
		for i, a := range issue.Assignees {
			currentAssignees[i] = a.Username
		}
	}

	// get the assignees to add
	assignees, err := flags.GetStringSlice("assign")
	if err != nil {
		return []int{}, false, err
	}

	// get the assignees to remove
	unassignees, err := flags.GetStringSlice("unassign")
	if err != nil {
		return []int{}, false, err
	}

	// add the new assignees to the current assignees, then remove the "unassignees"
	assignees = difference(union(currentAssignees, assignees), unassignees)
	assigneesChanged := !same(currentAssignees, assignees)

	// turn the new assignee list into a list of assignee IDs
	var assigneeIDs []int
	if assigneesChanged && len(assignees) == 0 {
		// if we're removing all assignees, we have to use []int{0}
		// see https://github.com/xanzy/go-gitlab/issues/427
		assigneeIDs = []int{0}
	} else {
		assigneeIDs = make([]int, len(assignees))
		for i, a := range assignees {
			assigneeIDs[i] = *getAssigneeID(a)
		}
	}

	return assigneeIDs, assigneesChanged, nil
}

// issueEditGetTitleDescription returns a title and description for an issue
// based on the current issue title and description and various flags from the
// command line
func issueEditGetTitleDescription(issue *gitlab.Issue, flags *pflag.FlagSet) (string, string, error) {
	title, body := issue.Title, issue.Description

	// get all of the "message" flags
	msgs, err := flags.GetStringArray("message")
	if err != nil {
		log.Fatal(err)
	}

	if len(msgs) > 0 {
		title = msgs[0]

		if len(msgs) > 1 {
			body = strings.Join(msgs[1:], "\n\n")
		}

		// we have everything we need
		return title, body, nil
	}

	// if other flags were given (eg label), then skip the editor and return
	// what we already have
	if flags.NFlag() != 0 {
		return title, body, nil
	}

	text, err := issueEditText(title, body)
	if err != nil {
		return "", "", err
	}
	return git.Edit("ISSUE_EDIT", text)
}

// issueEditText returns an issue editing template that is suitable for loading
// into an editor
func issueEditText(title string, body string) (string, error) {
	const tmpl = `{{.InitMsg}}

{{.CommentChar}} Edit the title and/or description of this issue. The first
{{.CommentChar}} block of text is the title and the rest is the description.`

	msg := &struct {
		InitMsg     string
		CommentChar string
	}{
		InitMsg:     title + "\n\n" + body,
		CommentChar: git.CommentChar(),
	}

	t, err := template.New("tmpl").Parse(tmpl)
	if err != nil {
		return "", err
	}

	var b bytes.Buffer
	err = t.Execute(&b, msg)
	if err != nil {
		return "", err
	}

	return b.String(), nil
}

// union returns all the unique elements in a and b
func union(a, b []string) []string {
	mb := map[string]bool{}
	ab := []string{}
	for _, x := range b {
		mb[x] = true
		// add all of b's elements to ab
		ab = append(ab, x)
	}
	for _, x := range a {
		if _, ok := mb[x]; !ok {
			// if a's elements aren't in b, add them to ab
			// if they are, we don't need to add them
			ab = append(ab, x)
		}
	}
	return ab
}

// difference returns the elements in a that aren't in b
func difference(a, b []string) []string {
	mb := map[string]bool{}
	for _, x := range b {
		mb[x] = true
	}
	ab := []string{}
	for _, x := range a {
		if _, ok := mb[x]; !ok {
			ab = append(ab, x)
		}
	}
	return ab
}

// same returns true if a and b contain the same strings (regardless of order)
func same(a, b []string) bool {
	if len(a) != len(b) {
		return false
	}

	mb := map[string]bool{}
	for _, x := range b {
		mb[x] = true
	}

	for _, x := range a {
		if _, ok := mb[x]; !ok {
			return false
		}
	}
	return true
}

func init() {
	issueEditCmd.Flags().StringArrayP("message", "m", []string{}, "Use the given <msg>; multiple -m are concatenated as separate paragraphs")
	issueEditCmd.Flags().StringSliceP("label", "l", []string{}, "Add the given label(s) to the issue")
	issueEditCmd.Flags().StringSliceP("unlabel", "", []string{}, "Remove the given label(s) from the issue")
	issueEditCmd.Flags().StringSliceP("assign", "a", []string{}, "Add an assignee by username")
	issueEditCmd.Flags().StringSliceP("unassign", "", []string{}, "Remove an assignee by username")
	issueEditCmd.Flags().Bool("force-linebreak", false, "append 2 spaces to the end of each line to force markdown linebreaks")

	issueCmd.AddCommand(issueEditCmd)
	carapace.Gen(issueEditCmd).PositionalCompletion(
		action.Remotes(),
		action.Issues(issueList),
	)
}
<commit_msg>issue_edit: Rework Flags() usage<commit_after>package cmd

import (
	"bytes"
	"fmt"
	"log"
	"runtime"
	"strconv"
	"strings"
	"text/template"

	"github.com/rsteube/carapace"
	"github.com/spf13/cobra"
	gitlab "github.com/xanzy/go-gitlab"
	"github.com/zaquestion/lab/internal/action"
	"github.com/zaquestion/lab/internal/git"
	lab "github.com/zaquestion/lab/internal/gitlab"
)

var issueEditCmd = &cobra.Command{
	Use:     "edit [remote] <id>",
	Aliases: []string{"update"},
	Short:   "Edit or update an issue",
	Long:    ``,
	Example: `lab issue edit <id>                                # update issue via $EDITOR
lab issue update <id>                              # same as above
lab issue edit <id> -m "new title"                 # update title
lab issue edit <id> -m "new title" -m "new desc"   # update title & description
lab issue edit <id> -l newlabel --unlabel oldlabel # relabel issue`,
	Args:             cobra.MinimumNArgs(1),
	PersistentPreRun: LabPersistentPreRun,
	Run: func(cmd *cobra.Command, args []string) {
		rn, issueNum, err := parseArgs(args)
		if err != nil {
			log.Fatal(err)
		}

		issue, err := lab.IssueGet(rn, int(issueNum))
		if err != nil {
			log.Fatal(err)
		}

		// get the labels to add
		labels, err := cmd.Flags().GetStringSlice("label")
		if err != nil {
			log.Fatal(err)
		}

		// get the labels to remove
		unlabels, err := cmd.Flags().GetStringSlice("unlabel")
		if err != nil {
			log.Fatal(err)
		}

		labels, labelsChanged, err := issueEditGetLabels(issue, labels, unlabels)
		if err != nil {
			log.Fatal(err)
		}

		// get the assignees to add
		assignees, err := cmd.Flags().GetStringSlice("assign")
		if err != nil {
			log.Fatal(err)
		}

		// get the assignees to remove
		unassignees, err := cmd.Flags().GetStringSlice("unassign")
		if err != nil {
			log.Fatal(err)
		}

		assigneeIDs, assigneesChanged, err := issueEditGetAssignees(issue, assignees, unassignees)
		if err != nil {
			log.Fatal(err)
		}

		// get all of the "message" flags
		msgs, err := cmd.Flags().GetStringArray("message")
		if err != nil {
			log.Fatal(err)
		}
		title, body, err := issueEditGetTitleDescription(issue, msgs, cmd.Flags().NFlag())
		if err != nil {
			_, f, l, _ := runtime.Caller(0)
			log.Fatal(f+":"+strconv.Itoa(l)+" ", err)
		}
		if title == "" {
			log.Fatal("aborting: empty issue title")
		}

		abortUpdate := title == issue.Title && body == issue.Description && !labelsChanged && !assigneesChanged
		if abortUpdate {
			log.Fatal("aborting: no changes")
		}

		linebreak, _ := cmd.Flags().GetBool("force-linebreak")
		if linebreak {
			body = textToMarkdown(body)
		}

		opts := &gitlab.UpdateIssueOptions{
			Title:       &title,
			Description: &body,
		}

		if labelsChanged {
			opts.Labels = lab.Labels(labels)
		}

		if assigneesChanged {
			opts.AssigneeIDs = assigneeIDs
		}

		issueURL, err := lab.IssueUpdate(rn, int(issueNum), opts)
		if err != nil {
			log.Fatal(err)
		}
		fmt.Println(issueURL)
	},
}

// issueEditGetLabels returns a string slice of issues based on the current
// issue labels and flags from the command line, and a bool indicating whether
// the labels have changed
func issueEditGetLabels(issue *gitlab.Issue, labels []string, unlabels []string) ([]string, bool, error) {
	// add the new labels to the current labels, then remove the "unlabels"
	labels = difference(union(issue.Labels, labels), unlabels)

	return labels, !same(issue.Labels, labels), nil
}

// issueEditGetAssignees returns an int slice of assignee IDs based on the
// current issue assignees and flags from the command line, and a bool
// indicating whether the assignees have changed
func issueEditGetAssignees(issue *gitlab.Issue, assignees []string, unassignees []string) ([]int, bool, error) {
	currentAssignees := make([]string, len(issue.Assignees))
	if len(issue.Assignees) > 0 && issue.Assignees[0].Username != "" {
		for i, a := range issue.Assignees {
			currentAssignees[i] = a.Username
		}
	}

	// add the new assignees to the current assignees, then remove the "unassignees"
	assignees = difference(union(currentAssignees, assignees), unassignees)
	assigneesChanged := !same(currentAssignees, assignees)

	// turn the new assignee list into a list of assignee IDs
	var assigneeIDs []int
	if assigneesChanged && len(assignees) == 0 {
		// if we're removing all assignees, we have to use []int{0}
		// see https://github.com/xanzy/go-gitlab/issues/427
		assigneeIDs = []int{0}
	} else {
		assigneeIDs = make([]int, len(assignees))
		for i, a := range assignees {
			assigneeIDs[i] = *getAssigneeID(a)
		}
	}

	return assigneeIDs, assigneesChanged, nil
}

// issueEditGetTitleDescription returns a title and description for an issue
// based on the current issue title and description and various flags from the
// command line
func issueEditGetTitleDescription(issue *gitlab.Issue, msgs []string, nFlag int) (string, string, error) {
	title, body := issue.Title, issue.Description

	if len(msgs) > 0 {
		title = msgs[0]

		if len(msgs) > 1 {
			body = strings.Join(msgs[1:], "\n\n")
		}

		// we have everything we need
		return title, body, nil
	}

	// if other flags were given (eg label), then skip the editor and return
	// what we already have
	if nFlag != 0 {
		return title, body, nil
	}

	text, err := issueEditText(title, body)
	if err != nil {
		return "", "", err
	}
	return git.Edit("ISSUE_EDIT", text)
}

// issueEditText returns an issue editing template that is suitable for loading
// into an editor
func issueEditText(title string, body string) (string, error) {
	const tmpl = `{{.InitMsg}}

{{.CommentChar}} Edit the title and/or description of this issue. The first
{{.CommentChar}} block of text is the title and the rest is the description.`

	msg := &struct {
		InitMsg     string
		CommentChar string
	}{
		InitMsg:     title + "\n\n" + body,
		CommentChar: git.CommentChar(),
	}

	t, err := template.New("tmpl").Parse(tmpl)
	if err != nil {
		return "", err
	}

	var b bytes.Buffer
	err = t.Execute(&b, msg)
	if err != nil {
		return "", err
	}

	return b.String(), nil
}

// union returns all the unique elements in a and b
func union(a, b []string) []string {
	mb := map[string]bool{}
	ab := []string{}
	for _, x := range b {
		mb[x] = true
		// add all of b's elements to ab
		ab = append(ab, x)
	}
	for _, x := range a {
		if _, ok := mb[x]; !ok {
			// if a's elements aren't in b, add them to ab
			// if they are, we don't need to add them
			ab = append(ab, x)
		}
	}
	return ab
}

// difference returns the elements in a that aren't in b
func difference(a, b []string) []string {
	mb := map[string]bool{}
	for _, x := range b {
		mb[x] = true
	}
	ab := []string{}
	for _, x := range a {
		if _, ok := mb[x]; !ok {
			ab = append(ab, x)
		}
	}
	return ab
}

// same returns true if a and b contain the same strings (regardless of order)
func same(a, b []string) bool {
	if len(a) != len(b) {
		return false
	}

	mb := map[string]bool{}
	for _, x := range b {
		mb[x] = true
	}

	for _, x := range a {
		if _, ok := mb[x]; !ok {
			return false
		}
	}
	return true
}

func init() {
	issueEditCmd.Flags().StringArrayP("message", "m", []string{}, "Use the given <msg>; multiple -m are concatenated as separate paragraphs")
	issueEditCmd.Flags().StringSliceP("label", "l", []string{}, "Add the given label(s) to the issue")
	issueEditCmd.Flags().StringSliceP("unlabel", "", []string{}, "Remove the given label(s) from the issue")
	issueEditCmd.Flags().StringSliceP("assign", "a", []string{}, "Add an assignee by username")
	issueEditCmd.Flags().StringSliceP("unassign", "", []string{}, "Remove an assignee by username")
	issueEditCmd.Flags().Bool("force-linebreak", false, "append 2 spaces to the end of each line to force markdown linebreaks")

	issueCmd.AddCommand(issueEditCmd)
	carapace.Gen(issueEditCmd).PositionalCompletion(
		action.Remotes(),
		action.Issues(issueList),
	)
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"flag"
	"fmt"
	"log"
	"net"
	"os"
	"path/filepath"
	"strings"

	"github.com/jmartin82/mmock/internal/config"
	"github.com/jmartin82/mmock/internal/config/parser"
	"github.com/jmartin82/mmock/internal/console"
	"github.com/jmartin82/mmock/internal/server"
	"github.com/jmartin82/mmock/internal/statistics"
	"github.com/jmartin82/mmock/pkg/match"
	"github.com/jmartin82/mmock/pkg/match/payload"
	"github.com/jmartin82/mmock/pkg/mock"
	"github.com/jmartin82/mmock/pkg/vars"
	"github.com/jmartin82/mmock/pkg/vars/fake"
)

//VERSION of the application
var VERSION string = "development"

//ErrNotFoundPath error from missing or configuration path
var ErrNotFoundPath = errors.New("Configuration path not found")

//ErrNotFoundDefaultPath if we can't resolve the current path
var ErrNotFoundDefaultPath = errors.New("We can't determinate the current path")

//ErrNotFoundAnyMock when we don't found any valid mock config to load
var ErrNotFoundAnyMock = errors.New("No valid mock config found")

func banner() {
	fmt.Printf("MMock v %s", VERSION)
	fmt.Println("")

	fmt.Print(
		`		.---. .---.
               :     : o   :    me want request!
           _..-:   o :     :-.._    /
       .-''  '  ` + "`" + `---' ` + "`" + `---' "   ` + "`" + `` + "`" + `-.
     .'   "   '  "  .    "  . '  "  ` + "`" + `.
    :   '.---.,,.,...,.,.,.,..---.  ' ;
    ` + "`" + `. " ` + "`" + `.                     .' " .'
     ` + "`" + `.  '` + "`" + `.                   .' ' .'
      ` + "`" + `.    ` + "`" + `-._           _.-' "  .'  .----.
        ` + "`" + `. "    '"--...--"'  . ' .'  .'  o   ` + "`" + `.
        .'` + "`" + `-._'    " .     " _.-'` + "`" + `. :       o  :
      .'      ` + "`" + `` + "`" + `` + "`" + `--.....--'''    ' ` + "`" + `:_ o       :
    .'    "     '         "     "   ; ` + "`" + `.;";";";'
   ;         '       "       '     . ; .' ; ; ;
  ;     '         '       '   "    .'      .-'
  '  "     "   '      "           "    _.-'
 `)
	fmt.Println("")
}

// Get preferred outbound ip of this machine
func getOutboundIP() string {
	conn, err := net.Dial("udp", "8.8.8.8:80")
	if err != nil {
		return "127.0.0.1"
	}
	defer conn.Close()

	log.Println("Getting external IP")
	localAddr := conn.LocalAddr().String()
	idx := strings.LastIndex(localAddr, ":")

	return localAddr[0:idx]
}

func getTransactionSpy(checker match.Matcher, matchStore match.TransactionStorer) *match.Spy {
	return match.NewSpy(checker, matchStore)
}

func existsConfigPath(path string) bool {
	_, err := os.Stat(path)
	if err == nil {
		return true
	}
	if os.IsNotExist(err) {
		return false
	}
	return true
}

func getMapping(path string) config.Mapping {
	path, _ = filepath.Abs(path)
	if !existsConfigPath(path) {
		log.Fatalln(ErrNotFoundPath.Error())
	}

	fsMapper := config.NewFileSystemMapper()
	fsMapper.AddParser(parser.JSONReader{})
	fsMapper.AddParser(parser.YAMLReader{})

	fsUpdate := make(chan struct{})

	watcher := config.NewFileWatcher(path, fsUpdate)
	watcher.Bind()

	return config.NewConfigMapping(path, fsMapper, fsUpdate)
}

func getRouter(mapping config.Mapping, checker match.Matcher) *server.Router {
	router := server.NewRouter(mapping, checker)
	return router
}

func getVarsProcessor() *vars.ResponseMessageEvaluator {
	ccg := fake.NewCreditCardGenerator()
	fp := fake.NewFakeDataProvider(ccg)
	ff := vars.NewFillerFactory(fp)
	return vars.NewResponseMessageEvaluator(ff)
}

func startServer(ip string, port, portTLS int, configTLS string, done chan struct{}, router server.RequestResolver, mLog chan match.Transaction, scenario match.ScenearioStorer, varsProcessor vars.Evaluator, spier match.TransactionSpier) {
	dispatcher := server.Dispatcher{
		IP:         ip,
		Port:       port,
		PortTLS:    portTLS,
		ConfigTLS:  configTLS,
		Resolver:   router,
		Translator: mock.HTTP{},
		Evaluator:  varsProcessor,
		Scenario:   scenario,
		Spier:      spier,
		Mlog:       mLog,
	}
	dispatcher.Start()
	done <- struct{}{}
}
func startConsole(ip string, port int, resultsPerPage int, spy match.TransactionSpier, scenario match.ScenearioStorer, mapping config.Mapping, done chan struct{}, mLog chan match.Transaction) {
	dispatcher := console.Dispatcher{
		IP:             ip,
		Port:           port,
		MatchSpy:       spy,
		Scenario:       scenario,
		Mapping:        mapping,
		Mlog:           mLog,
		ResultsPerPage: resultsPerPage,
	}
	dispatcher.Start()
	done <- struct{}{}
}

func main() {
	banner()
	outIP := getOutboundIP()
	path, err := filepath.Abs("./config")
	TLS, err := filepath.Abs("./tls")
	if err != nil {
		panic(ErrNotFoundDefaultPath)
	}

	sIP := flag.String("server-ip", outIP, "Definition server IP")
	sPort := flag.Int("server-port", 8083, "Definition server Port")
	sPortTLS := flag.Int("server-tls-port", 8084, "Definition server TLS Port")
	sStatistics := flag.Bool("server-statistics", true, "Definition server sends anonymous statistics")
	cIP := flag.String("console-ip", outIP, "Console server IP")
	cPort := flag.Int("console-port", 8082, "Console server Port")
	console := flag.Bool("console", true, "Console enabled  (true/false)")
	cPath := flag.String("config-path", path, "Mocks config folder")
	cTLS := flag.String("tls-path", TLS, "TLS config folder (server.crt and server.key should be inside)")
	cStorageCapacity := flag.Int("request-storage-capacity", 100, "Request storage capacity (0 = infinite)")
	cResultsPerPage := flag.Int("results-per-page", 25, "Number of results per page")

	flag.Parse()

	//chanels
	mLog := make(chan match.Transaction)
	done := make(chan struct{})

	//shared structs
	scenario := match.NewInMemoryScenarioStore()
	comparator := payload.NewDefaultComparator()
	tester := match.NewTester(comparator, scenario)
	matchStore := match.NewInMemoryTransactionStore(tester, *cStorageCapacity)
	mapping := getMapping(*cPath)
	spy := getTransactionSpy(tester, matchStore)
	router := getRouter(mapping, tester)
	varsProcessor := getVarsProcessor()

	if *sStatistics {
		fmt.Printf("\n************************************************************************************\n")
		fmt.Printf("* Mmock is collecting anonymous statistics about the usage of the features.        *\n")
		fmt.Printf("* You can disable this behavior adding the following flag -server-statistics=false *\n")
		fmt.Printf("************************************************************************************\n\n")
	} else {
		statistics.SetMonitor(statistics.NewNullableMonitor())
	}

	defer statistics.Stop()

	go startServer(*sIP, *sPort, *sPortTLS, *cTLS, done, router, mLog, scenario, varsProcessor, spy)
	log.Printf("HTTP Server running at http://%s:%d\n", *sIP, *sPort)
	log.Printf("HTTPS Server running at https://%s:%d\n", *sIP, *sPortTLS)
	if *console {
		go startConsole(*cIP, *cPort, *cResultsPerPage, spy, scenario, mapping, done, mLog)
		log.Printf("Console running at http://%s:%d\n", *cIP, *cPort)
	}

	<-done

}
<commit_msg>fix banner (#109)<commit_after>package main

import (
	"errors"
	"flag"
	"fmt"
	"log"
	"net"
	"os"
	"path/filepath"
	"strings"

	"github.com/jmartin82/mmock/internal/config"
	"github.com/jmartin82/mmock/internal/config/parser"
	"github.com/jmartin82/mmock/internal/console"
	"github.com/jmartin82/mmock/internal/server"
	"github.com/jmartin82/mmock/internal/statistics"
	"github.com/jmartin82/mmock/pkg/match"
	"github.com/jmartin82/mmock/pkg/match/payload"
	"github.com/jmartin82/mmock/pkg/mock"
	"github.com/jmartin82/mmock/pkg/vars"
	"github.com/jmartin82/mmock/pkg/vars/fake"
)

//VERSION of the application
var VERSION string = "development"

//ErrNotFoundPath error from missing or configuration path
var ErrNotFoundPath = errors.New("Configuration path not found")

//ErrNotFoundDefaultPath if we can't resolve the current path
var ErrNotFoundDefaultPath = errors.New("We can't determinate the current path")

//ErrNotFoundAnyMock when we don't found any valid mock config to load
var ErrNotFoundAnyMock = errors.New("No valid mock config found")

func banner() {
	fmt.Printf("MMock v %s", VERSION)
	fmt.Print(`
                .---. .---.
               :     : o   :    me want request!
           _..-:   o :     :-.._    /
       .-''  '  ` + "`" + `---' ` + "`" + `---' "   ` + "`" + `` + "`" + `-.
     .'   "   '  "  .    "  . '  "  ` + "`" + `.
    :   '.---.,,.,...,.,.,.,..---.  ' ;
    ` + "`" + `. " ` + "`" + `.                     .' " .'
     ` + "`" + `.  '` + "`" + `.                   .' ' .'
      ` + "`" + `.    ` + "`" + `-._           _.-' "  .'  .----.
        ` + "`" + `. "    '"--...--"'  . ' .'  .'  o   ` + "`" + `.
        .'` + "`" + `-._'    " .     " _.-'` + "`" + `. :       o  :
      .'      ` + "`" + `` + "`" + `` + "`" + `--.....--'''    ' ` + "`" + `:_ o       :
    .'    "     '         "     "   ; ` + "`" + `.;";";";'
   ;         '       "       '     . ; .' ; ; ;
  ;     '         '       '   "    .'      .-'
  '  "     "   '      "           "    _.-'
 `)
	fmt.Println("")
}

// Get preferred outbound ip of this machine
func getOutboundIP() string {
	conn, err := net.Dial("udp", "8.8.8.8:80")
	if err != nil {
		return "127.0.0.1"
	}
	defer conn.Close()

	log.Println("Getting external IP")
	localAddr := conn.LocalAddr().String()
	idx := strings.LastIndex(localAddr, ":")

	return localAddr[0:idx]
}

func getTransactionSpy(checker match.Matcher, matchStore match.TransactionStorer) *match.Spy {
	return match.NewSpy(checker, matchStore)
}

func existsConfigPath(path string) bool {
	_, err := os.Stat(path)
	if err == nil {
		return true
	}
	if os.IsNotExist(err) {
		return false
	}
	return true
}

func getMapping(path string) config.Mapping {
	path, _ = filepath.Abs(path)
	if !existsConfigPath(path) {
		log.Fatalln(ErrNotFoundPath.Error())
	}

	fsMapper := config.NewFileSystemMapper()
	fsMapper.AddParser(parser.JSONReader{})
	fsMapper.AddParser(parser.YAMLReader{})

	fsUpdate := make(chan struct{})

	watcher := config.NewFileWatcher(path, fsUpdate)
	watcher.Bind()

	return config.NewConfigMapping(path, fsMapper, fsUpdate)
}

func getRouter(mapping config.Mapping, checker match.Matcher) *server.Router {
	router := server.NewRouter(mapping, checker)
	return router
}

func getVarsProcessor() *vars.ResponseMessageEvaluator {
	ccg := fake.NewCreditCardGenerator()
	fp := fake.NewFakeDataProvider(ccg)
	ff := vars.NewFillerFactory(fp)
	return vars.NewResponseMessageEvaluator(ff)
}

func startServer(ip string, port, portTLS int, configTLS string, done chan struct{}, router server.RequestResolver, mLog chan match.Transaction, scenario match.ScenearioStorer, varsProcessor vars.Evaluator, spier match.TransactionSpier) {
	dispatcher := server.Dispatcher{
		IP:         ip,
		Port:       port,
		PortTLS:    portTLS,
		ConfigTLS:  configTLS,
		Resolver:   router,
		Translator: mock.HTTP{},
		Evaluator:  varsProcessor,
		Scenario:   scenario,
		Spier:      spier,
		Mlog:       mLog,
	}
	dispatcher.Start()
	done <- struct{}{}
}
func startConsole(ip string, port int, resultsPerPage int, spy match.TransactionSpier, scenario match.ScenearioStorer, mapping config.Mapping, done chan struct{}, mLog chan match.Transaction) {
	dispatcher := console.Dispatcher{
		IP:             ip,
		Port:           port,
		MatchSpy:       spy,
		Scenario:       scenario,
		Mapping:        mapping,
		Mlog:           mLog,
		ResultsPerPage: resultsPerPage,
	}
	dispatcher.Start()
	done <- struct{}{}
}

func main() {
	banner()
	outIP := getOutboundIP()
	path, err := filepath.Abs("./config")
	TLS, err := filepath.Abs("./tls")
	if err != nil {
		panic(ErrNotFoundDefaultPath)
	}

	sIP := flag.String("server-ip", outIP, "Definition server IP")
	sPort := flag.Int("server-port", 8083, "Definition server Port")
	sPortTLS := flag.Int("server-tls-port", 8084, "Definition server TLS Port")
	sStatistics := flag.Bool("server-statistics", true, "Definition server sends anonymous statistics")
	cIP := flag.String("console-ip", outIP, "Console server IP")
	cPort := flag.Int("console-port", 8082, "Console server Port")
	console := flag.Bool("console", true, "Console enabled  (true/false)")
	cPath := flag.String("config-path", path, "Mocks config folder")
	cTLS := flag.String("tls-path", TLS, "TLS config folder (server.crt and server.key should be inside)")
	cStorageCapacity := flag.Int("request-storage-capacity", 100, "Request storage capacity (0 = infinite)")
	cResultsPerPage := flag.Int("results-per-page", 25, "Number of results per page")

	flag.Parse()

	//chanels
	mLog := make(chan match.Transaction)
	done := make(chan struct{})

	//shared structs
	scenario := match.NewInMemoryScenarioStore()
	comparator := payload.NewDefaultComparator()
	tester := match.NewTester(comparator, scenario)
	matchStore := match.NewInMemoryTransactionStore(tester, *cStorageCapacity)
	mapping := getMapping(*cPath)
	spy := getTransactionSpy(tester, matchStore)
	router := getRouter(mapping, tester)
	varsProcessor := getVarsProcessor()

	if *sStatistics {
		fmt.Printf("\n************************************************************************************\n")
		fmt.Printf("* Mmock is collecting anonymous statistics about the usage of the features.        *\n")
		fmt.Printf("* You can disable this behavior adding the following flag -server-statistics=false *\n")
		fmt.Printf("************************************************************************************\n\n")
	} else {
		statistics.SetMonitor(statistics.NewNullableMonitor())
	}

	defer statistics.Stop()

	go startServer(*sIP, *sPort, *sPortTLS, *cTLS, done, router, mLog, scenario, varsProcessor, spy)
	log.Printf("HTTP Server running at http://%s:%d\n", *sIP, *sPort)
	log.Printf("HTTPS Server running at https://%s:%d\n", *sIP, *sPortTLS)
	if *console {
		go startConsole(*cIP, *cPort, *cResultsPerPage, spy, scenario, mapping, done, mLog)
		log.Printf("Console running at http://%s:%d\n", *cIP, *cPort)
	}

	<-done

}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"errors"
	"flag"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"testing"

	"github.com/richardlehane/siegfried"
	"github.com/richardlehane/siegfried/config"
)

var testhome = flag.String("testhome", filepath.Join("..", "roy", "data"), "override the default home directory")
var testdata = flag.String("testdata", filepath.Join(".", "testdata"), "override the default test data directory")

var s *siegfried.Siegfried

func setup() error {
	var err error
	config.SetHome(*testhome)
	s, err = siegfried.Load(config.Signature())
	return err
}

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

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

func TestLoad(t *testing.T) {
	err := setup()
	if err != nil {
		t.Error(err)
	}
}

func check(i string, j []string) bool {
	for _, v := range j {
		if i == v {
			return true
		}
	}
	return false
}

func matchString(i []string) string {
	str := "[ "
	for _, v := range i {
		str += v
		str += " "
	}
	return str + "]"
}

func TestSuite(t *testing.T) {
	err := setup()
	if err != nil {
		t.Error(err)
	}
	expect := make([]string, 0)
	names := make([]string, 0)
	wf := func(path string, info os.FileInfo, err error) error {
		if info.IsDir() {
			return nil
		}
		last := strings.Split(path, string(os.PathSeparator))
		path = last[len(last)-1]
		var idx int
		idx = strings.Index(path, "container")
		if idx < 0 {
			idx = strings.Index(path, "signature")
		}
		if idx < 0 {
			idx = len(path)
		}
		strs := strings.Split(path[:idx-1], "-")
		if len(strs) == 2 {
			expect = append(expect, strings.Join(strs, "/"))
		} else if len(strs) == 3 {
			expect = append(expect, "x-fmt/"+strs[2])
		} else {
			return errors.New("long string encountered: " + path)
		}
		names = append(names, path)
		return nil
	}
	suite := filepath.Join(*testdata, "skeleton-suite")
	err = filepath.Walk(suite, wf)
	if err != nil {
		t.Fatal(err)
	}
	matches, err := multiIdentifyT(s, suite)
	if err != nil {
		t.Fatal(err)
	}
	if len(expect) != len(matches) {
		t.Error("Expect should equal matches")
	}
	var iter int
	for i, v := range expect {
		if !check(v, matches[i]) {
			t.Errorf("Failed to match signature %v; got %v; expected %v", names[i], matchString(matches[i]), v)

		} else {
			iter++
		}
	}
	if iter != len(expect) {
		t.Errorf("Matched %v out of %v signatures", iter, len(expect))
	}
}

func TestTip(t *testing.T) {
	expect := "fmt/669"
	err := setup()
	if err != nil {
		t.Error(err)
	}
	buf := bytes.NewReader([]byte{0x00, 0x4d, 0x52, 0x4d, 0x00})
	c, err := s.Identify("test.mrw", buf)
	for i := range c {
		if i.String() != expect {
			t.Errorf("First buffer: expecting %s, got %s", expect, i)
		}
	}
	buf = bytes.NewReader([]byte{0x00, 0x4d, 0x52, 0x4d, 0x00})
	c, err = s.Identify("test.mrw", buf)
	for i := range c {
		if i.String() != expect {
			t.Errorf("Second buffer: expecting %s, got %s", expect, i)
		}
	}
	buf = bytes.NewReader([]byte{0x00, 0x4d, 0x52, 0x4d, 0x00})
	c, err = s.Identify("test.mrw", buf)
	for i := range c {
		if i.String() != expect {
			t.Errorf("Third buffer: expecting %s, got %s", expect, i)
		}
	}
}

// Benchmarks
func BenchmarkNew(bench *testing.B) {
	for i := 0; i < bench.N; i++ {
		setup()
	}
}

func benchidentify(ext string) {
	file := filepath.Join(*testdata, "benchmark", "Benchmark")
	file += "." + ext
	identifyT(s, file)
}

func BenchmarkACCDB(bench *testing.B) {
	for i := 0; i < bench.N; i++ {
		benchidentify("accdb")
	}
}

func BenchmarkBMP(bench *testing.B) {
	for i := 0; i < bench.N; i++ {
		benchidentify("bmp")
	}
}

func BenchmarkDOCX(bench *testing.B) {
	for i := 0; i < bench.N; i++ {
		benchidentify("docx")
	}
}

func BenchmarkGIF(bench *testing.B) {
	for i := 0; i < bench.N; i++ {
		benchidentify("gif")
	}
}

func BenchmarkJPG(bench *testing.B) {
	for i := 0; i < bench.N; i++ {
		benchidentify("jpg")
	}
}

func BenchmarkMSG(bench *testing.B) {
	for i := 0; i < bench.N; i++ {
		benchidentify("msg")
	}
}

func BenchmarkODT(bench *testing.B) {
	for i := 0; i < bench.N; i++ {
		benchidentify("odt")
	}
}

func BenchmarkPDF(bench *testing.B) {
	for i := 0; i < bench.N; i++ {
		benchidentify("pdf")
	}
}

func BenchmarkPNG(bench *testing.B) {
	for i := 0; i < bench.N; i++ {
		benchidentify("png")
	}
}

func BenchmarkPPTX(bench *testing.B) {
	for i := 0; i < bench.N; i++ {
		benchidentify("pptx")
	}
}

func BenchmarkRTF(bench *testing.B) {
	for i := 0; i < bench.N; i++ {
		benchidentify("rtf")
	}
}

func BenchmarkTIF(bench *testing.B) {
	for i := 0; i < bench.N; i++ {
		benchidentify("tif")
	}
}

func BenchmarkXLSX(bench *testing.B) {
	for i := 0; i < bench.N; i++ {
		benchidentify("xlsx")
	}
}

func BenchmarkXML(bench *testing.B) {
	for i := 0; i < bench.N; i++ {
		benchidentify("xml")
	}
}

func BenchmarkMulti(bench *testing.B) {
	dir := filepath.Join(*testdata, "benchmark")
	for i := 0; i < bench.N; i++ {
		multiIdentifyT(s, dir)
	}
}
<commit_msg>tracing segy fault<commit_after>package main

import (
	"bytes"
	"errors"
	"flag"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"testing"

	"github.com/richardlehane/siegfried"
	"github.com/richardlehane/siegfried/config"
)

var testhome = flag.String("testhome", filepath.Join("..", "roy", "data"), "override the default home directory")
var testdata = flag.String("testdata", filepath.Join(".", "testdata"), "override the default test data directory")

var s *siegfried.Siegfried

func setup() error {
	var err error
	config.SetHome(*testhome)
	s, err = siegfried.Load(config.Signature())
	return err
}

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

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

func TestLoad(t *testing.T) {
	err := setup()
	if err != nil {
		t.Error(err)
	}
}

func check(i string, j []string) bool {
	for _, v := range j {
		if i == v {
			return true
		}
	}
	return false
}

func matchString(i []string) string {
	str := "[ "
	for _, v := range i {
		str += v
		str += " "
	}
	return str + "]"
}

func TestSuite(t *testing.T) {
	err := setup()
	if err != nil {
		t.Error(err)
	}
	expect := make([]string, 0)
	names := make([]string, 0)
	wf := func(path string, info os.FileInfo, err error) error {
		if info.IsDir() {
			return nil
		}
		last := strings.Split(path, string(os.PathSeparator))
		path = last[len(last)-1]
		var idx int
		idx = strings.Index(path, "container")
		if idx < 0 {
			idx = strings.Index(path, "signature")
		}
		if idx < 0 {
			idx = len(path)
		}
		strs := strings.Split(path[:idx-1], "-")
		if len(strs) == 2 {
			expect = append(expect, strings.Join(strs, "/"))
		} else if len(strs) == 3 {
			expect = append(expect, "x-fmt/"+strs[2])
		} else {
			return errors.New("long string encountered: " + path)
		}
		names = append(names, path)
		return nil
	}
	suite := filepath.Join(*testdata, "skeleton-suite")
	err = filepath.Walk(suite, wf)
	if err != nil {
		t.Fatal(err)
	}
	matches, err := multiIdentifyT(s, suite)
	if err != nil {
		t.Fatal(err)
	}
	if len(expect) != len(matches) {
		t.Error("Expect should equal matches")
	}
	var iter int
	for i, v := range expect {
		if !check(v, matches[i]) {
			t.Errorf("Failed to match signature %v; got %v; expected %v", names[i], matchString(matches[i]), v)

		} else {
			iter++
		}
	}
	if iter != len(expect) {
		t.Errorf("Matched %v out of %v signatures", iter, len(expect))
	}
}

func TestTip(t *testing.T) {
	expect := "fmt/669"
	err := setup()
	if err != nil {
		t.Error(err)
	}
	buf := bytes.NewReader([]byte{0x00, 0x4d, 0x52, 0x4d, 0x00})
	c, err := s.Identify("test.mrw", buf)
	for i := range c {
		if i.String() != expect {
			t.Errorf("First buffer: expecting %s, got %s", expect, i)
		}
	}
	buf = bytes.NewReader([]byte{0x00, 0x4d, 0x52, 0x4d, 0x00})
	c, err = s.Identify("test.mrw", buf)
	for i := range c {
		if i.String() != expect {
			t.Errorf("Second buffer: expecting %s, got %s", expect, i)
		}
	}
	buf = bytes.NewReader([]byte{0x00, 0x4d, 0x52, 0x4d, 0x00})
	c, err = s.Identify("test.mrw", buf)
	for i := range c {
		if i.String() != expect {
			t.Errorf("Third buffer: expecting %s, got %s", expect, i)
		}
	}
}

func Test363(t *testing.T) {
	expect := "fmt/363"
	err := setup()
	if err != nil {
		t.Error(err)
	}
	segy := func(l int) []byte {
		b := make([]byte, l)
		for i := range b {
			if i > 21 {
				break
			}
			b[i] = 64
		}
		copy(b[l-9:], []byte{01, 00, 00, 00, 01, 00, 00, 01, 00})
		return b
	}
	se := segy(3226)
	for i := 0; i < 1000; i++ {
		buf := bytes.NewReader(se)
		c, _ := s.Identify("test.seg", buf)
		for i := range c {
			if i.String() != expect {
				t.Errorf("First buffer: expecting %s, got %s", expect, i)
			}
		}
	}
	se = segy(3626)
	for i := 0; i < 1000; i++ {
		buf := bytes.NewReader(se)
		c, _ := s.Identify("test2.seg", buf)
		for i := range c {
			if i.String() != expect {
				t.Errorf("Second buffer: expecting %s, got %s", expect, i)
			}
		}
	}
}

// Benchmarks
func BenchmarkNew(bench *testing.B) {
	for i := 0; i < bench.N; i++ {
		setup()
	}
}

func benchidentify(ext string) {
	file := filepath.Join(*testdata, "benchmark", "Benchmark")
	file += "." + ext
	identifyT(s, file)
}

func BenchmarkACCDB(bench *testing.B) {
	for i := 0; i < bench.N; i++ {
		benchidentify("accdb")
	}
}

func BenchmarkBMP(bench *testing.B) {
	for i := 0; i < bench.N; i++ {
		benchidentify("bmp")
	}
}

func BenchmarkDOCX(bench *testing.B) {
	for i := 0; i < bench.N; i++ {
		benchidentify("docx")
	}
}

func BenchmarkGIF(bench *testing.B) {
	for i := 0; i < bench.N; i++ {
		benchidentify("gif")
	}
}

func BenchmarkJPG(bench *testing.B) {
	for i := 0; i < bench.N; i++ {
		benchidentify("jpg")
	}
}

func BenchmarkMSG(bench *testing.B) {
	for i := 0; i < bench.N; i++ {
		benchidentify("msg")
	}
}

func BenchmarkODT(bench *testing.B) {
	for i := 0; i < bench.N; i++ {
		benchidentify("odt")
	}
}

func BenchmarkPDF(bench *testing.B) {
	for i := 0; i < bench.N; i++ {
		benchidentify("pdf")
	}
}

func BenchmarkPNG(bench *testing.B) {
	for i := 0; i < bench.N; i++ {
		benchidentify("png")
	}
}

func BenchmarkPPTX(bench *testing.B) {
	for i := 0; i < bench.N; i++ {
		benchidentify("pptx")
	}
}

func BenchmarkRTF(bench *testing.B) {
	for i := 0; i < bench.N; i++ {
		benchidentify("rtf")
	}
}

func BenchmarkTIF(bench *testing.B) {
	for i := 0; i < bench.N; i++ {
		benchidentify("tif")
	}
}

func BenchmarkXLSX(bench *testing.B) {
	for i := 0; i < bench.N; i++ {
		benchidentify("xlsx")
	}
}

func BenchmarkXML(bench *testing.B) {
	for i := 0; i < bench.N; i++ {
		benchidentify("xml")
	}
}

func BenchmarkMulti(bench *testing.B) {
	dir := filepath.Join(*testdata, "benchmark")
	for i := 0; i < bench.N; i++ {
		multiIdentifyT(s, dir)
	}
}
<|endoftext|>


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

package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"os"
	"regexp"

	"github.com/mvdan/xurls"
)

var (
	matching = flag.String("m", "", "")
	relaxed  = flag.Bool("r", false, "")
)

func init() {
	flag.Usage = func() {
		fmt.Fprintln(os.Stderr, `Usage: xurls [-h]`)
		fmt.Fprintln(os.Stderr)
		fmt.Fprintln(os.Stderr, `   -m <regexp>   only match urls whose scheme matches a regexp`)
		fmt.Fprintln(os.Stderr, `                    example: "https?://|mailto:"`)
		fmt.Fprintln(os.Stderr, `   -r            also match urls without a scheme (relaxed)`)
	}
}

func scan(re *regexp.Regexp, r io.Reader) {
	scanner := bufio.NewScanner(r)
	scanner.Split(bufio.ScanWords)
	for scanner.Scan() {
		word := scanner.Text()
		for _, match := range re.FindAllString(word, -1) {
			fmt.Println(match)
		}
	}
}

func main() {
	flag.Parse()
	if *relaxed && *matching != "" {
		fmt.Fprintln(os.Stderr, "-r and -m at the same time don't make much sense.")
		os.Exit(1)
	}
	re := xurls.Strict
	if *relaxed {
		re = xurls.Relaxed
	} else if *matching != "" {
		var err error
		if re, err = xurls.StrictMatching(*matching); err != nil {
			fmt.Fprintln(os.Stderr, "invalid -m regular expression:", *matching)
			os.Exit(2)
		}
	}
	args := flag.Args()
	if len(args) == 0 {
		scan(re, os.Stdin)
	} else {
		for _, path := range args {
			if path == "-" {
				scan(re, os.Stdin)
				continue
			}
			file, err := os.Open(path)
			if err != nil {
				fmt.Fprintln(os.Stdout, "could not open file:", path)
			}
			scan(re, file)
			file.Close()
		}
	}
}
<commit_msg>cmd/xurls: Print error messages we get<commit_after>/* Copyright (c) 2015, Daniel Martí <mvdan@mvdan.cc> */
/* See LICENSE for licensing information */

package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"os"
	"regexp"

	"github.com/mvdan/xurls"
)

var (
	matching = flag.String("m", "", "")
	relaxed  = flag.Bool("r", false, "")
)

func init() {
	flag.Usage = func() {
		fmt.Fprintln(os.Stderr, `Usage: xurls [-h]`)
		fmt.Fprintln(os.Stderr)
		fmt.Fprintln(os.Stderr, `   -m <regexp>   only match urls whose scheme matches a regexp`)
		fmt.Fprintln(os.Stderr, `                    example: "https?://|mailto:"`)
		fmt.Fprintln(os.Stderr, `   -r            also match urls without a scheme (relaxed)`)
	}
}

func scan(re *regexp.Regexp, r io.Reader) {
	scanner := bufio.NewScanner(r)
	scanner.Split(bufio.ScanWords)
	for scanner.Scan() {
		word := scanner.Text()
		for _, match := range re.FindAllString(word, -1) {
			fmt.Println(match)
		}
	}
}

func main() {
	flag.Parse()
	if *relaxed && *matching != "" {
		fmt.Fprintf(os.Stderr, "-r and -m at the same time don't make much sense.\n")
		os.Exit(1)
	}
	re := xurls.Strict
	if *relaxed {
		re = xurls.Relaxed
	} else if *matching != "" {
		var err error
		if re, err = xurls.StrictMatching(*matching); err != nil {
			fmt.Fprintf(os.Stderr, "invalid regular expression '%s': %v\n", *matching, err)
			os.Exit(2)
		}
	}
	args := flag.Args()
	if len(args) == 0 {
		scan(re, os.Stdin)
	} else {
		for _, path := range args {
			if path == "-" {
				scan(re, os.Stdin)
				continue
			}
			file, err := os.Open(path)
			if err != nil {
				fmt.Fprintf(os.Stdout, "could not open file '%s': %v\n", path, err)
			}
			scan(re, file)
			file.Close()
		}
	}
}
<|endoftext|>