<commit_before>package main

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

	cloudflare "github.com/cloudflare/cloudflare-go"
	"github.com/urfave/cli/v2"
)

func zoneCerts(*cli.Context) error {
	return nil
}

func zoneKeyless(*cli.Context) error {
	return nil
}

func zoneRailgun(*cli.Context) error {
	return nil
}

func zoneCreate(c *cli.Context) error {
	if err := checkFlags(c, "zone"); err != nil {
		return err
	}
	zone := c.String("zone")
	jumpstart := c.Bool("jumpstart")
	accountID := c.String("account-id")
	zoneType := c.String("type")
	var account cloudflare.Account
	if accountID != "" {
		account.ID = accountID
	}

	if zoneType != "partial" {
		zoneType = "full"
	}

	_, err := api.CreateZone(context.Background(), zone, jumpstart, account, zoneType)
	if err != nil {
		fmt.Fprintln(os.Stderr, fmt.Sprintf("%s", err))
		return err
	}

	return nil
}

func zoneCheck(c *cli.Context) error {
	if err := checkFlags(c, "zone"); err != nil {
		return err
	}
	zone := c.String("zone")

	zoneID, err := api.ZoneIDByName(zone)
	if err != nil {
		fmt.Println(err)
		return err
	}

	res, err := api.ZoneActivationCheck(context.Background(), zoneID)
	if err != nil {
		fmt.Println(err)
		return err
	}
	fmt.Printf("%s\n", res.Messages[0].Message)

	return nil
}

func zoneList(c *cli.Context) error {
	zones, err := api.ListZones(context.Background())
	if err != nil {
		fmt.Println(err)
		return err
	}
	output := make([][]string, 0, len(zones))
	for _, z := range zones {
		output = append(output, []string{
			z.ID,
			z.Name,
			z.Plan.Name,
			z.Status,
		})
	}
	writeTable(c, output, "ID", "Name", "Plan", "Status")

	return nil
}

func zoneDelete(c *cli.Context) error {
	if err := checkFlags(c, "zone"); err != nil {
		return err
	}

	zoneID, err := api.ZoneIDByName(c.String("zone"))
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return err
	}

	_, err = api.DeleteZone(context.Background(), zoneID)
	if err != nil {
		fmt.Fprintln(os.Stderr, fmt.Sprintf("%s", err))
		return err
	}

	return nil
}

func zoneCreateLockdown(c *cli.Context) error {
	if err := checkFlags(c, "zone", "urls", "targets", "values"); err != nil {
		return err
	}
	zoneID, err := api.ZoneIDByName(c.String("zone"))
	if err != nil {
		fmt.Println(err)
		return err
	}
	targets := c.StringSlice("targets")
	values := c.StringSlice("values")
	if len(targets) != len(values) {
		cli.ShowCommandHelp(c, "targets and values does not match")
		return nil
	}
	var zonelockdownconfigs = []cloudflare.ZoneLockdownConfig{}
	for index := 0; index < len(targets); index++ {
		zonelockdownconfigs = append(zonelockdownconfigs, cloudflare.ZoneLockdownConfig{
			Target: c.StringSlice("targets")[index],
			Value:  c.StringSlice("values")[index],
		})
	}
	lockdown := cloudflare.ZoneLockdown{
		Description:    c.String("description"),
		URLs:           c.StringSlice("urls"),
		Configurations: zonelockdownconfigs,
	}

	var resp *cloudflare.ZoneLockdownResponse

	resp, err = api.CreateZoneLockdown(context.Background(), zoneID, lockdown)
	if err != nil {
		fmt.Fprintln(os.Stderr, "Error creating ZONE lock down: ", err)
		return err
	}
	output := make([][]string, 0, 1)
	output = append(output, formatLockdownResponse(resp))

	writeTable(c, output, "ID")

	return nil
}

func zoneInfo(c *cli.Context) error {
	var zone string
	if c.NArg() > 0 {
		zone = c.Args().First()
	} else if c.String("zone") != "" {
		zone = c.String("zone")
	} else {
		cli.ShowSubcommandHelp(c)
		return nil
	}
	zones, err := api.ListZones(context.Background(), zone)
	if err != nil {
		fmt.Println(err)
		return err
	}
	output := make([][]string, 0, len(zones))
	for _, z := range zones {
		var nameservers []string
		if len(z.VanityNS) > 0 {
			nameservers = z.VanityNS
		} else {
			nameservers = z.NameServers
		}
		output = append(output, []string{
			z.ID,
			z.Name,
			z.Plan.Name,
			z.Status,
			strings.Join(nameservers, ", "),
			fmt.Sprintf("%t", z.Paused),
			z.Type,
		})
	}
	writeTable(c, output, "ID", "Zone", "Plan", "Status", "Name Servers", "Paused", "Type")

	return nil
}

func zonePlan(*cli.Context) error {
	return nil
}

func zoneSettings(*cli.Context) error {
	return nil
}

func zoneCachePurge(c *cli.Context) error {
	if err := checkFlags(c, "zone"); err != nil {
		cli.ShowSubcommandHelp(c)
		return err
	}

	zoneName := c.String("zone")
	zoneID, err := api.ZoneIDByName(c.String("zone"))
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return err
	}

	var resp cloudflare.PurgeCacheResponse

	// Purge everything
	if c.Bool("everything") {
		resp, err = api.PurgeEverything(context.Background(), zoneID)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error purging all from zone %q: %s\n", zoneName, err)
			return err
		}
	} else {
		var (
			files = c.StringSlice("files")
			tags  = c.StringSlice("tags")
			hosts = c.StringSlice("hosts")
		)

		if len(files) == 0 && len(tags) == 0 && len(hosts) == 0 {
			fmt.Fprintln(os.Stderr, "You must provide at least one of the --files, --tags or --hosts flags")
			return nil
		}

		// Purge selectively
		purgeReq := cloudflare.PurgeCacheRequest{
			Files: c.StringSlice("files"),
			Tags:  c.StringSlice("tags"),
			Hosts: c.StringSlice("hosts"),
		}

		resp, err = api.PurgeCache(context.Background(), zoneID, purgeReq)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error purging the cache from zone %q: %s\n", zoneName, err)
			return err
		}
	}

	output := make([][]string, 0, 1)
	output = append(output, formatCacheResponse(resp))

	writeTable(c, output, "ID")

	return nil
}

func zoneRecords(c *cli.Context) error {
	var zone string
	if c.NArg() > 0 {
		zone = c.Args().First()
	} else if c.String("zone") != "" {
		zone = c.String("zone")
	} else {
		cli.ShowSubcommandHelp(c)
		return nil
	}

	zoneID, err := api.ZoneIDByName(zone)
	if err != nil {
		fmt.Println(err)
		return err
	}

	// Create a an empty record for searching for records
	rr := cloudflare.DNSRecord{}
	var records []cloudflare.DNSRecord
	if c.String("id") != "" {
		rec, err := api.DNSRecord(context.Background(), zoneID, c.String("id"))
		if err != nil {
			fmt.Println(err)
			return err
		}
		records = append(records, rec)
	} else {
		if c.String("type") != "" {
			rr.Type = c.String("type")
		}
		if c.String("name") != "" {
			rr.Name = c.String("name")
		}
		if c.String("content") != "" {
			rr.Name = c.String("content")
		}
		var err error
		records, err = api.DNSRecords(context.Background(), zoneID, rr)
		if err != nil {
			fmt.Println(err)
			return err
		}
	}
	output := make([][]string, 0, len(records))
	for _, r := range records {
		switch r.Type {
		case "MX":
			r.Content = fmt.Sprintf("%d %s", r.Priority, r.Content)
		case "SRV":
			dp := r.Data.(map[string]interface{})
			r.Content = fmt.Sprintf("%.f %s", dp["priority"], r.Content)
			// Cloudflare's API, annoyingly, automatically prepends the weight
			// and port into content, separated by tabs.
			// XXX: File this as a bug. LOC doesn't do this.
			r.Content = strings.Replace(r.Content, "\t", " ", -1)
		}
		output = append(output, []string{
			r.ID,
			r.Type,
			r.Name,
			r.Content,
			fmt.Sprintf("%s", strconv.FormatBool(*r.Proxied)),
			fmt.Sprintf("%d", r.TTL),
		})
	}
	writeTable(c, output, "ID", "Type", "Name", "Content", "Proxied", "TTL")

	return nil
}

func formatCacheResponse(resp cloudflare.PurgeCacheResponse) []string {
	return []string{
		resp.Result.ID,
	}
}

func formatLockdownResponse(resp *cloudflare.ZoneLockdownResponse) []string {
	return []string{
		resp.Result.ID,
	}
}

func zoneExport(c *cli.Context) error {
	var zone string
	if c.NArg() > 0 {
		zone = c.Args().First()
	} else if c.String("zone") != "" {
		zone = c.String("zone")
	} else {
		cli.ShowSubcommandHelp(c)
		return nil
	}

	zoneID, err := api.ZoneIDByName(zone)
	if err != nil {
		fmt.Println(err)
		return err
	}

	res, err := api.ZoneExport(context.Background(), zoneID)
	if err != nil {
		fmt.Println(err)
		return err
	}
	fmt.Print(res)

	return nil
}
<commit_msg>add prefixes to flarectl<commit_after>package main

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

	cloudflare "github.com/cloudflare/cloudflare-go"
	"github.com/urfave/cli/v2"
)

func zoneCerts(*cli.Context) error {
	return nil
}

func zoneKeyless(*cli.Context) error {
	return nil
}

func zoneRailgun(*cli.Context) error {
	return nil
}

func zoneCreate(c *cli.Context) error {
	if err := checkFlags(c, "zone"); err != nil {
		return err
	}
	zone := c.String("zone")
	jumpstart := c.Bool("jumpstart")
	accountID := c.String("account-id")
	zoneType := c.String("type")
	var account cloudflare.Account
	if accountID != "" {
		account.ID = accountID
	}

	if zoneType != "partial" {
		zoneType = "full"
	}

	_, err := api.CreateZone(context.Background(), zone, jumpstart, account, zoneType)
	if err != nil {
		fmt.Fprintln(os.Stderr, fmt.Sprintf("%s", err))
		return err
	}

	return nil
}

func zoneCheck(c *cli.Context) error {
	if err := checkFlags(c, "zone"); err != nil {
		return err
	}
	zone := c.String("zone")

	zoneID, err := api.ZoneIDByName(zone)
	if err != nil {
		fmt.Println(err)
		return err
	}

	res, err := api.ZoneActivationCheck(context.Background(), zoneID)
	if err != nil {
		fmt.Println(err)
		return err
	}
	fmt.Printf("%s\n", res.Messages[0].Message)

	return nil
}

func zoneList(c *cli.Context) error {
	zones, err := api.ListZones(context.Background())
	if err != nil {
		fmt.Println(err)
		return err
	}
	output := make([][]string, 0, len(zones))
	for _, z := range zones {
		output = append(output, []string{
			z.ID,
			z.Name,
			z.Plan.Name,
			z.Status,
		})
	}
	writeTable(c, output, "ID", "Name", "Plan", "Status")

	return nil
}

func zoneDelete(c *cli.Context) error {
	if err := checkFlags(c, "zone"); err != nil {
		return err
	}

	zoneID, err := api.ZoneIDByName(c.String("zone"))
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return err
	}

	_, err = api.DeleteZone(context.Background(), zoneID)
	if err != nil {
		fmt.Fprintln(os.Stderr, fmt.Sprintf("%s", err))
		return err
	}

	return nil
}

func zoneCreateLockdown(c *cli.Context) error {
	if err := checkFlags(c, "zone", "urls", "targets", "values"); err != nil {
		return err
	}
	zoneID, err := api.ZoneIDByName(c.String("zone"))
	if err != nil {
		fmt.Println(err)
		return err
	}
	targets := c.StringSlice("targets")
	values := c.StringSlice("values")
	if len(targets) != len(values) {
		cli.ShowCommandHelp(c, "targets and values does not match")
		return nil
	}
	var zonelockdownconfigs = []cloudflare.ZoneLockdownConfig{}
	for index := 0; index < len(targets); index++ {
		zonelockdownconfigs = append(zonelockdownconfigs, cloudflare.ZoneLockdownConfig{
			Target: c.StringSlice("targets")[index],
			Value:  c.StringSlice("values")[index],
		})
	}
	lockdown := cloudflare.ZoneLockdown{
		Description:    c.String("description"),
		URLs:           c.StringSlice("urls"),
		Configurations: zonelockdownconfigs,
	}

	var resp *cloudflare.ZoneLockdownResponse

	resp, err = api.CreateZoneLockdown(context.Background(), zoneID, lockdown)
	if err != nil {
		fmt.Fprintln(os.Stderr, "Error creating ZONE lock down: ", err)
		return err
	}
	output := make([][]string, 0, 1)
	output = append(output, formatLockdownResponse(resp))

	writeTable(c, output, "ID")

	return nil
}

func zoneInfo(c *cli.Context) error {
	var zone string
	if c.NArg() > 0 {
		zone = c.Args().First()
	} else if c.String("zone") != "" {
		zone = c.String("zone")
	} else {
		cli.ShowSubcommandHelp(c)
		return nil
	}
	zones, err := api.ListZones(context.Background(), zone)
	if err != nil {
		fmt.Println(err)
		return err
	}
	output := make([][]string, 0, len(zones))
	for _, z := range zones {
		var nameservers []string
		if len(z.VanityNS) > 0 {
			nameservers = z.VanityNS
		} else {
			nameservers = z.NameServers
		}
		output = append(output, []string{
			z.ID,
			z.Name,
			z.Plan.Name,
			z.Status,
			strings.Join(nameservers, ", "),
			fmt.Sprintf("%t", z.Paused),
			z.Type,
		})
	}
	writeTable(c, output, "ID", "Zone", "Plan", "Status", "Name Servers", "Paused", "Type")

	return nil
}

func zonePlan(*cli.Context) error {
	return nil
}

func zoneSettings(*cli.Context) error {
	return nil
}

func zoneCachePurge(c *cli.Context) error {
	if err := checkFlags(c, "zone"); err != nil {
		cli.ShowSubcommandHelp(c)
		return err
	}

	zoneName := c.String("zone")
	zoneID, err := api.ZoneIDByName(c.String("zone"))
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return err
	}

	var resp cloudflare.PurgeCacheResponse

	// Purge everything
	if c.Bool("everything") {
		resp, err = api.PurgeEverything(context.Background(), zoneID)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error purging all from zone %q: %s\n", zoneName, err)
			return err
		}
	} else {
		var (
			files    = c.StringSlice("files")
			tags     = c.StringSlice("tags")
			hosts    = c.StringSlice("hosts")
			prefixes = c.StringSlice("prefixes")
		)

		if len(files) == 0 && len(tags) == 0 && len(hosts) == 0 && len(prefixes) == 0 {
			fmt.Fprintln(os.Stderr, "You must provide at least one of the --files, --tags or --hosts flags")
			return nil
		}

		// Purge selectively
		purgeReq := cloudflare.PurgeCacheRequest{
			Files:    c.StringSlice("files"),
			Tags:     c.StringSlice("tags"),
			Hosts:    c.StringSlice("hosts"),
			Prefixes: c.StringSlice("prefixes"),
		}

		resp, err = api.PurgeCache(context.Background(), zoneID, purgeReq)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error purging the cache from zone %q: %s\n", zoneName, err)
			return err
		}
	}

	output := make([][]string, 0, 1)
	output = append(output, formatCacheResponse(resp))

	writeTable(c, output, "ID")

	return nil
}

func zoneRecords(c *cli.Context) error {
	var zone string
	if c.NArg() > 0 {
		zone = c.Args().First()
	} else if c.String("zone") != "" {
		zone = c.String("zone")
	} else {
		cli.ShowSubcommandHelp(c)
		return nil
	}

	zoneID, err := api.ZoneIDByName(zone)
	if err != nil {
		fmt.Println(err)
		return err
	}

	// Create a an empty record for searching for records
	rr := cloudflare.DNSRecord{}
	var records []cloudflare.DNSRecord
	if c.String("id") != "" {
		rec, err := api.DNSRecord(context.Background(), zoneID, c.String("id"))
		if err != nil {
			fmt.Println(err)
			return err
		}
		records = append(records, rec)
	} else {
		if c.String("type") != "" {
			rr.Type = c.String("type")
		}
		if c.String("name") != "" {
			rr.Name = c.String("name")
		}
		if c.String("content") != "" {
			rr.Name = c.String("content")
		}
		var err error
		records, err = api.DNSRecords(context.Background(), zoneID, rr)
		if err != nil {
			fmt.Println(err)
			return err
		}
	}
	output := make([][]string, 0, len(records))
	for _, r := range records {
		switch r.Type {
		case "MX":
			r.Content = fmt.Sprintf("%d %s", r.Priority, r.Content)
		case "SRV":
			dp := r.Data.(map[string]interface{})
			r.Content = fmt.Sprintf("%.f %s", dp["priority"], r.Content)
			// Cloudflare's API, annoyingly, automatically prepends the weight
			// and port into content, separated by tabs.
			// XXX: File this as a bug. LOC doesn't do this.
			r.Content = strings.Replace(r.Content, "\t", " ", -1)
		}
		output = append(output, []string{
			r.ID,
			r.Type,
			r.Name,
			r.Content,
			fmt.Sprintf("%s", strconv.FormatBool(*r.Proxied)),
			fmt.Sprintf("%d", r.TTL),
		})
	}
	writeTable(c, output, "ID", "Type", "Name", "Content", "Proxied", "TTL")

	return nil
}

func formatCacheResponse(resp cloudflare.PurgeCacheResponse) []string {
	return []string{
		resp.Result.ID,
	}
}

func formatLockdownResponse(resp *cloudflare.ZoneLockdownResponse) []string {
	return []string{
		resp.Result.ID,
	}
}

func zoneExport(c *cli.Context) error {
	var zone string
	if c.NArg() > 0 {
		zone = c.Args().First()
	} else if c.String("zone") != "" {
		zone = c.String("zone")
	} else {
		cli.ShowSubcommandHelp(c)
		return nil
	}

	zoneID, err := api.ZoneIDByName(zone)
	if err != nil {
		fmt.Println(err)
		return err
	}

	res, err := api.ZoneExport(context.Background(), zoneID)
	if err != nil {
		fmt.Println(err)
		return err
	}
	fmt.Print(res)

	return nil
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// 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.

// Implements go/build buildpack.
// The build buildpack runs go build.
package main

import (
	"os"
	"path/filepath"
	"strings"

	"github.com/GoogleCloudPlatform/buildpacks/pkg/devmode"
	"github.com/GoogleCloudPlatform/buildpacks/pkg/env"
	gcp "github.com/GoogleCloudPlatform/buildpacks/pkg/gcpbuildpack"
	"github.com/GoogleCloudPlatform/buildpacks/pkg/golang"
	"github.com/buildpack/libbuildpack/layers"
)

const (
	cantLoadDefaultPackageError = "can't load package: package ."
)

func main() {
	gcp.Main(detectFn, buildFn)
}

func detectFn(ctx *gcp.Context) error {
	if !ctx.HasAtLeastOne("*.go") {
		ctx.OptOut("No *.go files found")
	}
	return nil
}

func buildFn(ctx *gcp.Context) error {
	// Create a cached layer for the GOCACHE.
	cl := ctx.Layer("gocache")
	lf := []layers.Flag{layers.Cache, layers.Build}
	if devmode.Enabled(ctx) {
		lf = append(lf, layers.Launch)
		ctx.OverrideLaunchEnv(cl, "GOCACHE", cl.Root)
	}
	ctx.WriteMetadata(cl, nil, lf...)

	// Create a layer for the compiled binary.
	bl := ctx.Layer("bin")
	ctx.PrependPathLaunchEnv(bl, "PATH", bl.Root)
	ctx.WriteMetadata(bl, nil, layers.Launch)

	pkg, ok := os.LookupEnv(env.Buildable)
	if !ok {
		pkg = "."
	}

	// Build the application.
	ctx.ExecUserWithParams(gcp.ExecParams{
		Cmd: []string{"go", "build", "-o", filepath.Join(bl.Root, golang.OutBin), pkg},
		Env: []string{"GOCACHE=" + cl.Root},
	}, printTipsAndKeepStderrTail(ctx))

	// Configure the entrypoint for production.
	if !devmode.Enabled(ctx) {
		ctx.AddWebProcess([]string{golang.OutBin})
		return nil
	}

	// Configure the entrypoint and metadata for dev mode.
	devmode.AddFileWatcherProcess(ctx, devmode.Config{
		Cmd: []string{"go", "run", pkg},
		Ext: devmode.GoWatchedExtensions,
	})
	devmode.AddSyncMetadata(ctx, devmode.GoSyncRules)

	return nil
}

func printTipsAndKeepStderrTail(ctx *gcp.Context) gcp.ErrorSummaryProducer {
	return func(result *gcp.ExecResult) *gcp.Error {
		if result.ExitCode != 0 && strings.Contains(result.Stderr, cantLoadDefaultPackageError) {
			ctx.Tipf("Tip: %q env var configures which Go package is built. Default is '.'", env.Buildable)
		}

		return gcp.UserErrorKeepStderrTail(result)
	}
}
<commit_msg>Specify golang web process using absolute path.<commit_after>// Copyright 2020 Google LLC
//
// 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.

// Implements go/build buildpack.
// The build buildpack runs go build.
package main

import (
	"os"
	"path/filepath"
	"strings"

	"github.com/GoogleCloudPlatform/buildpacks/pkg/devmode"
	"github.com/GoogleCloudPlatform/buildpacks/pkg/env"
	gcp "github.com/GoogleCloudPlatform/buildpacks/pkg/gcpbuildpack"
	"github.com/GoogleCloudPlatform/buildpacks/pkg/golang"
	"github.com/buildpack/libbuildpack/layers"
)

const (
	cantLoadDefaultPackageError = "can't load package: package ."
)

func main() {
	gcp.Main(detectFn, buildFn)
}

func detectFn(ctx *gcp.Context) error {
	if !ctx.HasAtLeastOne("*.go") {
		ctx.OptOut("No *.go files found")
	}
	return nil
}

func buildFn(ctx *gcp.Context) error {
	// Create a cached layer for the GOCACHE.
	cl := ctx.Layer("gocache")
	lf := []layers.Flag{layers.Cache, layers.Build}
	if devmode.Enabled(ctx) {
		lf = append(lf, layers.Launch)
		ctx.OverrideLaunchEnv(cl, "GOCACHE", cl.Root)
	}
	ctx.WriteMetadata(cl, nil, lf...)

	// Create a layer for the compiled binary.  Add it to PATH in case
	// users wish to invoke the binary manually.
	bl := ctx.Layer("bin")
	ctx.PrependPathLaunchEnv(bl, "PATH", bl.Root)
	ctx.WriteMetadata(bl, nil, layers.Launch)
	outBin := filepath.Join(bl.Root, golang.OutBin)

	pkg, ok := os.LookupEnv(env.Buildable)
	if !ok {
		pkg = "."
	}

	// Build the application.
	ctx.ExecUserWithParams(gcp.ExecParams{
		Cmd: []string{"go", "build", "-o", outBin, pkg},
		Env: []string{"GOCACHE=" + cl.Root},
	}, printTipsAndKeepStderrTail(ctx))

	// Configure the entrypoint for production: use the full path to ease `skaffold debug`
	// as it does not access image contents.
	if !devmode.Enabled(ctx) {
		ctx.AddWebProcess([]string{outBin})
		return nil
	}

	// Configure the entrypoint and metadata for dev mode.
	devmode.AddFileWatcherProcess(ctx, devmode.Config{
		Cmd: []string{"go", "run", pkg},
		Ext: devmode.GoWatchedExtensions,
	})
	devmode.AddSyncMetadata(ctx, devmode.GoSyncRules)

	return nil
}

func printTipsAndKeepStderrTail(ctx *gcp.Context) gcp.ErrorSummaryProducer {
	return func(result *gcp.ExecResult) *gcp.Error {
		if result.ExitCode != 0 && strings.Contains(result.Stderr, cantLoadDefaultPackageError) {
			ctx.Tipf("Tip: %q env var configures which Go package is built. Default is '.'", env.Buildable)
		}

		return gcp.UserErrorKeepStderrTail(result)
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 SpectoLabs. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// hoverfly is an HTTP/s proxy configurable via flags/environment variables/admin HTTP API
//
// this proxy can be dynamically configured through HTTP calls when it's running, to change modes,
// export and import requests.

package main

import (
	"crypto/tls"
	"flag"
	"fmt"
	"strings"
	"time"

	log "github.com/Sirupsen/logrus"
	hv "github.com/SpectoLabs/hoverfly"
	"github.com/SpectoLabs/hoverfly/authentication/backends"
	"github.com/SpectoLabs/hoverfly/cache"
	hvc "github.com/SpectoLabs/hoverfly/certs"
	"github.com/rusenask/goproxy"
)

type arrayFlags []string

func (i *arrayFlags) String() string {
	return "my string representation"
}

func (i *arrayFlags) Set(value string) error {
	*i = append(*i, value)
	return nil
}

var importFlags arrayFlags
var destinationFlags arrayFlags

var (
	verbose         = flag.Bool("v", false, "should every proxy request be logged to stdout")
	capture         = flag.Bool("capture", false, "start Hoverfly in capture mode - transparently intercepts and saves requests/response")
	synthesize      = flag.Bool("synthesize", false, "start Hoverfly in synthesize mode (middleware is required)")
	modify          = flag.Bool("modify", false, "start Hoverfly in modify mode - applies middleware (required) to both outgoing and incomming HTTP traffic")
	middleware      = flag.String("middleware", "", "should proxy use middleware")
	proxyPort       = flag.String("pp", "", "proxy port - run proxy on another port (i.e. '-pp 9999' to run proxy on port 9999)")
	adminPort       = flag.String("ap", "", "admin port - run admin interface on another port (i.e. '-ap 1234' to run admin UI on port 1234)")
	metrics         = flag.Bool("metrics", false, "supply -metrics flag to enable metrics logging to stdout")
	dev             = flag.Bool("dev", false, "supply -dev flag to serve directly from ./static/dist instead from statik binary")
	destination     = flag.String("destination", ".", "destination URI to catch")
	addNew          = flag.Bool("add", false, "add new user '-add -username hfadmin -password hfpass'")
	addUser         = flag.String("username", "", "username for new user")
	addPassword     = flag.String("password", "", "password for new user")
	isAdmin         = flag.Bool("admin", true, "supply '-admin false' to make this non admin user (defaults to 'true') ")
	authEnabled     = flag.Bool("auth", false, "enable authentication, currently it is disabled by default")
	generateCA      = flag.Bool("generate-ca-cert", false, "generate CA certificate and private key for MITM")
	certName        = flag.String("cert-name", "hoverfly.proxy", "cert name")
	certOrg         = flag.String("cert-org", "Hoverfly Authority", "organisation name for new cert")
	cert            = flag.String("cert", "", "CA certificate used to sign MITM certificates")
	key             = flag.String("key", "", "private key of the CA used to sign MITM certificates")
	tlsVerification = flag.Bool("tls-verification", true, "turn on/off tls verification for outgoing requests (will not try to verify certificates) - defaults to true")
	databasePath    = flag.String("db-dir", "", "database location - supply it if you want to provide specific to database (will be created there if it doesn't exist)")
	database        = flag.String("db", "boltdb", "Persistance storage to use - 'boltdb' or 'memory' which will not write anything to disk")
)

func main() {
	log.SetFormatter(&log.JSONFormatter{})
	flag.Var(&importFlags, "import", "import from file or from URL (i.e. '-import my_service.json' or '-import http://mypage.com/service_x.json'")
	flag.Var(&destinationFlags, "dest", "specify which hosts to process (i.e. '-dest fooservice.org -dest barservice.org -dest catservice.org') - other hosts will be ignored will passthrough'")
	flag.Parse()

	// getting settings
	cfg := hv.InitSettings()

	if *verbose {
		// Only log the warning severity or above.
		log.SetLevel(log.DebugLevel)
	}
	cfg.Verbose = *verbose

	if *dev {
		// making text pretty
		log.SetFormatter(&log.TextFormatter{})
	}

	if *generateCA {
		tlsc, err := hvc.GenerateAndSave(*certName, *certOrg, 365*24*time.Hour)
		if err != nil {
			log.WithFields(log.Fields{
				"error": err.Error(),
			}).Fatal("failed to generate certificate.")
		}
		goproxy.GoproxyCa = *tlsc

	} else if *cert != "" && *key != "" {
		tlsc, err := tls.LoadX509KeyPair(*cert, *key)
		if err != nil {
			log.Fatalf("Failed to load certifiate and key pair, got error: %s", err.Error())
		}

		goproxy.GoproxyCa = tlsc

	}

	// overriding environment variables (proxy and admin ports)
	if *proxyPort != "" {
		cfg.ProxyPort = *proxyPort
	}
	if *adminPort != "" {
		cfg.AdminPort = *adminPort
	}

	// development settings
	cfg.Development = *dev

	// overriding default middleware setting
	cfg.Middleware = *middleware

	// setting default mode
	mode := hv.VirtualizeMode

	if *capture {
		mode = hv.CaptureMode
		// checking whether user supplied other modes
		if *synthesize == true || *modify == true {
			log.Fatal("Two or more modes supplied, check your flags")
		}
	} else if *synthesize {
		mode = hv.SynthesizeMode

		if cfg.Middleware == "" {
			log.Fatal("Synthesize mode chosen although middleware not supplied")
		}

		if *capture == true || *modify == true {
			log.Fatal("Two or more modes supplied, check your flags")
		}
	} else if *modify {
		mode = hv.ModifyMode

		if cfg.Middleware == "" {
			log.Fatal("Modify mode chosen although middleware not supplied")
		}

		if *capture == true || *synthesize == true {
			log.Fatal("Two or more modes supplied, check your flags")
		}
	}

	// setting mode
	cfg.SetMode(mode)

	// enabling authentication if flag or env variable is set to 'true'
	if cfg.AuthEnabled || *authEnabled {
		cfg.AuthEnabled = true
	}

	// disabling tls verification if flag or env variable is set to 'false' (defaults to true)
	if !cfg.TLSVerification || !*tlsVerification {
		cfg.TLSVerification = false
		log.Info("tls certificate verification is now turned off!")
	}

	if len(destinationFlags) > 0 {
		cfg.Destination = strings.Join(destinationFlags[:], "|")

	} else {
		//  setting destination regexp
		cfg.Destination = *destination
	}

	var requestCache cache.Cache
	var metadataCache cache.Cache
	var tokenCache cache.Cache
	var userCache cache.Cache

	if *databasePath != "" {
		cfg.DatabasePath = *databasePath
	}

	if *database == "boltdb" {
		log.Info("Creating bolt db backend...")
		db := cache.GetDB(cfg.DatabasePath)
		defer db.Close()
		requestCache = cache.NewBoltDBCache(db, []byte("requestsBucket"))
		metadataCache = cache.NewBoltDBCache(db, []byte("metadataBucket"))
		tokenCache = cache.NewBoltDBCache(db, []byte(backends.TokenBucketName))
		userCache = cache.NewBoltDBCache(db, []byte(backends.UserBucketName))
	} else {
		log.Info("Creating in memory map backend...")
		requestCache = cache.NewInMemoryCache()
		metadataCache = cache.NewInMemoryCache()
		tokenCache = cache.NewInMemoryCache()
		userCache = cache.NewInMemoryCache()
	}

	hoverfly := hv.GetNewHoverfly(cfg, requestCache, metadataCache, backends.NewAuthBackend(tokenCache, userCache))

	// if add new user supplied - adding it to database
	if *addNew {
		err := hoverfly.Authentication.AddUser(*addUser, *addPassword, *isAdmin)
		if err != nil {
			log.WithFields(log.Fields{
				"error":    err.Error(),
				"username": *addUser,
			}).Fatal("failed to add new user")
		} else {
			log.WithFields(log.Fields{
				"username": *addUser,
			}).Info("user added successfuly")
		}
		return
	}

	// importing stuff
	if len(importFlags) > 0 {
		for i, v := range importFlags {
			if v != "" {
				log.WithFields(log.Fields{
					"import": v,
				}).Debug("Importing given resource")
				err := hoverfly.Import(v)
				if err != nil {
					log.WithFields(log.Fields{
						"error":  err.Error(),
						"import": v,
					}).Fatal("Failed to import given resource")
				} else {
					err = hoverfly.MetadataCache.Set([]byte(fmt.Sprintf("import_%d", i+1)), []byte(v))
				}

			}
		}
	}

	// start metrics registry flush
	if *metrics {
		hoverfly.Counter.Init()
	}

	err := hoverfly.StartProxy()
	if err != nil {
		log.WithFields(log.Fields{
			"error": err.Error(),
		}).Fatal("failed to start proxy...")
	}

	// starting admin interface, this is blocking
	hoverfly.StartAdminInterface()
}
<commit_msg>passing in authentication struct<commit_after>// Copyright 2015 SpectoLabs. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// hoverfly is an HTTP/s proxy configurable via flags/environment variables/admin HTTP API
//
// this proxy can be dynamically configured through HTTP calls when it's running, to change modes,
// export and import requests.

package main

import (
	"crypto/tls"
	"flag"
	"fmt"
	"strings"
	"time"

	log "github.com/Sirupsen/logrus"
	hv "github.com/SpectoLabs/hoverfly"
	"github.com/SpectoLabs/hoverfly/authentication/backends"
	"github.com/SpectoLabs/hoverfly/cache"
	hvc "github.com/SpectoLabs/hoverfly/certs"
	"github.com/rusenask/goproxy"
)

type arrayFlags []string

func (i *arrayFlags) String() string {
	return "my string representation"
}

func (i *arrayFlags) Set(value string) error {
	*i = append(*i, value)
	return nil
}

var importFlags arrayFlags
var destinationFlags arrayFlags

var (
	verbose         = flag.Bool("v", false, "should every proxy request be logged to stdout")
	capture         = flag.Bool("capture", false, "start Hoverfly in capture mode - transparently intercepts and saves requests/response")
	synthesize      = flag.Bool("synthesize", false, "start Hoverfly in synthesize mode (middleware is required)")
	modify          = flag.Bool("modify", false, "start Hoverfly in modify mode - applies middleware (required) to both outgoing and incomming HTTP traffic")
	middleware      = flag.String("middleware", "", "should proxy use middleware")
	proxyPort       = flag.String("pp", "", "proxy port - run proxy on another port (i.e. '-pp 9999' to run proxy on port 9999)")
	adminPort       = flag.String("ap", "", "admin port - run admin interface on another port (i.e. '-ap 1234' to run admin UI on port 1234)")
	metrics         = flag.Bool("metrics", false, "supply -metrics flag to enable metrics logging to stdout")
	dev             = flag.Bool("dev", false, "supply -dev flag to serve directly from ./static/dist instead from statik binary")
	destination     = flag.String("destination", ".", "destination URI to catch")
	addNew          = flag.Bool("add", false, "add new user '-add -username hfadmin -password hfpass'")
	addUser         = flag.String("username", "", "username for new user")
	addPassword     = flag.String("password", "", "password for new user")
	isAdmin         = flag.Bool("admin", true, "supply '-admin false' to make this non admin user (defaults to 'true') ")
	authEnabled     = flag.Bool("auth", false, "enable authentication, currently it is disabled by default")
	generateCA      = flag.Bool("generate-ca-cert", false, "generate CA certificate and private key for MITM")
	certName        = flag.String("cert-name", "hoverfly.proxy", "cert name")
	certOrg         = flag.String("cert-org", "Hoverfly Authority", "organisation name for new cert")
	cert            = flag.String("cert", "", "CA certificate used to sign MITM certificates")
	key             = flag.String("key", "", "private key of the CA used to sign MITM certificates")
	tlsVerification = flag.Bool("tls-verification", true, "turn on/off tls verification for outgoing requests (will not try to verify certificates) - defaults to true")
	databasePath    = flag.String("db-dir", "", "database location - supply it if you want to provide specific to database (will be created there if it doesn't exist)")
	database        = flag.String("db", "boltdb", "Persistance storage to use - 'boltdb' or 'memory' which will not write anything to disk")
)

func main() {
	log.SetFormatter(&log.JSONFormatter{})
	flag.Var(&importFlags, "import", "import from file or from URL (i.e. '-import my_service.json' or '-import http://mypage.com/service_x.json'")
	flag.Var(&destinationFlags, "dest", "specify which hosts to process (i.e. '-dest fooservice.org -dest barservice.org -dest catservice.org') - other hosts will be ignored will passthrough'")
	flag.Parse()

	// getting settings
	cfg := hv.InitSettings()

	if *verbose {
		// Only log the warning severity or above.
		log.SetLevel(log.DebugLevel)
	}
	cfg.Verbose = *verbose

	if *dev {
		// making text pretty
		log.SetFormatter(&log.TextFormatter{})
	}

	if *generateCA {
		tlsc, err := hvc.GenerateAndSave(*certName, *certOrg, 365*24*time.Hour)
		if err != nil {
			log.WithFields(log.Fields{
				"error": err.Error(),
			}).Fatal("failed to generate certificate.")
		}
		goproxy.GoproxyCa = *tlsc

	} else if *cert != "" && *key != "" {
		tlsc, err := tls.LoadX509KeyPair(*cert, *key)
		if err != nil {
			log.Fatalf("Failed to load certifiate and key pair, got error: %s", err.Error())
		}

		goproxy.GoproxyCa = tlsc

	}

	// overriding environment variables (proxy and admin ports)
	if *proxyPort != "" {
		cfg.ProxyPort = *proxyPort
	}
	if *adminPort != "" {
		cfg.AdminPort = *adminPort
	}

	// development settings
	cfg.Development = *dev

	// overriding default middleware setting
	cfg.Middleware = *middleware

	// setting default mode
	mode := hv.VirtualizeMode

	if *capture {
		mode = hv.CaptureMode
		// checking whether user supplied other modes
		if *synthesize == true || *modify == true {
			log.Fatal("Two or more modes supplied, check your flags")
		}
	} else if *synthesize {
		mode = hv.SynthesizeMode

		if cfg.Middleware == "" {
			log.Fatal("Synthesize mode chosen although middleware not supplied")
		}

		if *capture == true || *modify == true {
			log.Fatal("Two or more modes supplied, check your flags")
		}
	} else if *modify {
		mode = hv.ModifyMode

		if cfg.Middleware == "" {
			log.Fatal("Modify mode chosen although middleware not supplied")
		}

		if *capture == true || *synthesize == true {
			log.Fatal("Two or more modes supplied, check your flags")
		}
	}

	// setting mode
	cfg.SetMode(mode)

	// enabling authentication if flag or env variable is set to 'true'
	if cfg.AuthEnabled || *authEnabled {
		cfg.AuthEnabled = true
	}

	// disabling tls verification if flag or env variable is set to 'false' (defaults to true)
	if !cfg.TLSVerification || !*tlsVerification {
		cfg.TLSVerification = false
		log.Info("tls certificate verification is now turned off!")
	}

	if len(destinationFlags) > 0 {
		cfg.Destination = strings.Join(destinationFlags[:], "|")

	} else {
		//  setting destination regexp
		cfg.Destination = *destination
	}

	var requestCache cache.Cache
	var metadataCache cache.Cache
	var tokenCache cache.Cache
	var userCache cache.Cache

	if *databasePath != "" {
		cfg.DatabasePath = *databasePath
	}

	if *database == "boltdb" {
		log.Info("Creating bolt db backend...")
		db := cache.GetDB(cfg.DatabasePath)
		defer db.Close()
		requestCache = cache.NewBoltDBCache(db, []byte("requestsBucket"))
		metadataCache = cache.NewBoltDBCache(db, []byte("metadataBucket"))
		tokenCache = cache.NewBoltDBCache(db, []byte(backends.TokenBucketName))
		userCache = cache.NewBoltDBCache(db, []byte(backends.UserBucketName))
	} else {
		log.Info("Creating in memory map backend...")
		requestCache = cache.NewInMemoryCache()
		metadataCache = cache.NewInMemoryCache()
		tokenCache = cache.NewInMemoryCache()
		userCache = cache.NewInMemoryCache()
	}

	authBackend := backends.NewCacheBasedAuthBackend(tokenCache, userCache)

	hoverfly := hv.GetNewHoverfly(cfg, requestCache, metadataCache, authBackend)

	// if add new user supplied - adding it to database
	if *addNew {
		err := hoverfly.Authentication.AddUser(*addUser, *addPassword, *isAdmin)
		if err != nil {
			log.WithFields(log.Fields{
				"error":    err.Error(),
				"username": *addUser,
			}).Fatal("failed to add new user")
		} else {
			log.WithFields(log.Fields{
				"username": *addUser,
			}).Info("user added successfuly")
		}
		return
	}

	// importing stuff
	if len(importFlags) > 0 {
		for i, v := range importFlags {
			if v != "" {
				log.WithFields(log.Fields{
					"import": v,
				}).Debug("Importing given resource")
				err := hoverfly.Import(v)
				if err != nil {
					log.WithFields(log.Fields{
						"error":  err.Error(),
						"import": v,
					}).Fatal("Failed to import given resource")
				} else {
					err = hoverfly.MetadataCache.Set([]byte(fmt.Sprintf("import_%d", i+1)), []byte(v))
				}

			}
		}
	}

	// start metrics registry flush
	if *metrics {
		hoverfly.Counter.Init()
	}

	err := hoverfly.StartProxy()
	if err != nil {
		log.WithFields(log.Fields{
			"error": err.Error(),
		}).Fatal("failed to start proxy...")
	}

	// starting admin interface, this is blocking
	hoverfly.StartAdminInterface()
}
<|endoftext|>


<commit_before>// Copyright 2015 SpectoLabs. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// hoverfly is an HTTP/s proxy configurable via flags/environment variables/admin HTTP API
//
// this proxy can be dynamically configured through HTTP calls when it's running, to change modes,
// export and import requests.

package main

import (
	log "github.com/Sirupsen/logrus"
	hv "github.com/SpectoLabs/hoverfly"
	"github.com/SpectoLabs/hoverfly/authentication"
	"github.com/SpectoLabs/hoverfly/authentication/backends"

	"flag"
	"fmt"
	"net/http"
)

func main() {
	log.SetFormatter(&log.JSONFormatter{})

	// getting proxy configuration
	verbose := flag.Bool("v", false, "should every proxy request be logged to stdout")
	// modes
	capture := flag.Bool("capture", false, "should proxy capture requests")
	synthesize := flag.Bool("synthesize", false, "should proxy capture requests")
	modify := flag.Bool("modify", false, "should proxy only modify requests")

	destination := flag.String("destination", ".", "destination URI to catch")
	middleware := flag.String("middleware", "", "should proxy use middleware")

	// proxy port
	proxyPort := flag.String("pp", "", "proxy port - run proxy on another port (i.e. '-pp 9999' to run proxy on port 9999)")
	// admin port
	adminPort := flag.String("ap", "", "admin port - run admin interface on another port (i.e. '-ap 1234' to run admin UI on port 1234)")

	// metrics
	metrics := flag.Bool("metrics", false, "supply -metrics flag to enable metrics logging to stdout")

	// development
	dev := flag.Bool("dev", false, "supply -dev flag to serve directly from ./static/dist instead from statik binary")

	// import flag
	imp := flag.String("import", "", "import from file or from URL (i.e. '-import my_service.json' or '-import http://mypage.com/service_x.json'")

	// adding new user
	addNew := flag.Bool("add", false, "add new user '-add -username hfadmin -password hfpass'")
	addUser := flag.String("username", "", "username for new user")
	addPassword := flag.String("password", "", "password for new user")

	flag.Parse()

	// getting settings
	cfg := hv.InitSettings()

	if *verbose {
		// Only log the warning severity or above.
		log.SetLevel(log.DebugLevel)
	}
	cfg.Verbose = *verbose

	if *dev {
		// making text pretty
		log.SetFormatter(&log.TextFormatter{})
	}

	// overriding environment variables (proxy and admin ports)
	if *proxyPort != "" {
		cfg.ProxyPort = *proxyPort
	}
	if *adminPort != "" {
		cfg.AdminPort = *adminPort
	}

	// development settings
	cfg.Development = *dev

	// overriding default middleware setting
	cfg.Middleware = *middleware

	// setting default mode
	mode := hv.VirtualizeMode

	if *capture {
		mode = hv.CaptureMode
		// checking whether user supplied other modes
		if *synthesize == true || *modify == true {
			log.Fatal("Two or more modes supplied, check your flags")
		}
	} else if *synthesize {
		mode = hv.SynthesizeMode

		if cfg.Middleware == "" {
			log.Fatal("Synthesize mode chosen although middleware not supplied")
		}

		if *capture == true || *modify == true {
			log.Fatal("Two or more modes supplied, check your flags")
		}
	} else if *modify {
		mode = hv.ModifyMode

		if cfg.Middleware == "" {
			log.Fatal("Modify mode chosen although middleware not supplied")
		}

		if *capture == true || *synthesize == true {
			log.Fatal("Two or more modes supplied, check your flags")
		}
	}

	// overriding default settings
	cfg.Mode = mode

	// overriding destination
	cfg.Destination = *destination

	// getting boltDB
	db := hv.GetDB(cfg.DatabaseName)
	cache := hv.NewBoltDBCache(db, []byte(hv.RequestsBucketName))
	defer cache.CloseDB()

	proxy, dbClient := hv.GetNewHoverfly(cfg, cache)

	ab := backends.NewBoltDBAuthBackend(db, []byte(backends.TokenBucketName), []byte(backends.UserBucketName))
	// loading auth settings
	authentication.Init()

	dbClient.AB = ab

	// if add new user supplied - adding it to database
	if *addNew {
		err := ab.AddUser(*addUser, *addPassword)
		if err != nil {
			log.WithFields(log.Fields{
				"error":    err.Error(),
				"username": *addUser,
			}).Fatal("Failed to add new user")
		}
		return
	}

	// importing stuff
	if *imp != "" {
		err := dbClient.Import(*imp)
		if err != nil {
			log.WithFields(log.Fields{
				"error":  err.Error(),
				"import": *imp,
			}).Fatal("Failed to import given resource")
		}
	}

	// starting admin interface
	dbClient.StartAdminInterface()

	// start metrics registry flush
	if *metrics {
		dbClient.Counter.Init()
	}

	log.Warn(http.ListenAndServe(fmt.Sprintf(":%s", cfg.ProxyPort), proxy))
}
<commit_msg>added cmd flags to create new users<commit_after>// Copyright 2015 SpectoLabs. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// hoverfly is an HTTP/s proxy configurable via flags/environment variables/admin HTTP API
//
// this proxy can be dynamically configured through HTTP calls when it's running, to change modes,
// export and import requests.

package main

import (
	log "github.com/Sirupsen/logrus"
	hv "github.com/SpectoLabs/hoverfly"
	"github.com/SpectoLabs/hoverfly/authentication"
	"github.com/SpectoLabs/hoverfly/authentication/backends"

	"flag"
	"fmt"
	"net/http"
)

func main() {
	log.SetFormatter(&log.JSONFormatter{})

	// getting proxy configuration
	verbose := flag.Bool("v", false, "should every proxy request be logged to stdout")
	// modes
	capture := flag.Bool("capture", false, "should proxy capture requests")
	synthesize := flag.Bool("synthesize", false, "should proxy capture requests")
	modify := flag.Bool("modify", false, "should proxy only modify requests")

	destination := flag.String("destination", ".", "destination URI to catch")
	middleware := flag.String("middleware", "", "should proxy use middleware")

	// proxy port
	proxyPort := flag.String("pp", "", "proxy port - run proxy on another port (i.e. '-pp 9999' to run proxy on port 9999)")
	// admin port
	adminPort := flag.String("ap", "", "admin port - run admin interface on another port (i.e. '-ap 1234' to run admin UI on port 1234)")

	// metrics
	metrics := flag.Bool("metrics", false, "supply -metrics flag to enable metrics logging to stdout")

	// development
	dev := flag.Bool("dev", false, "supply -dev flag to serve directly from ./static/dist instead from statik binary")

	// import flag
	imp := flag.String("import", "", "import from file or from URL (i.e. '-import my_service.json' or '-import http://mypage.com/service_x.json'")

	// adding new user
	addNew := flag.Bool("add", false, "add new user '-add -username hfadmin -password hfpass'")
	addUser := flag.String("username", "", "username for new user")
	addPassword := flag.String("password", "", "password for new user")

	flag.Parse()

	// getting settings
	cfg := hv.InitSettings()

	if *verbose {
		// Only log the warning severity or above.
		log.SetLevel(log.DebugLevel)
	}
	cfg.Verbose = *verbose

	if *dev {
		// making text pretty
		log.SetFormatter(&log.TextFormatter{})
	}

	// overriding environment variables (proxy and admin ports)
	if *proxyPort != "" {
		cfg.ProxyPort = *proxyPort
	}
	if *adminPort != "" {
		cfg.AdminPort = *adminPort
	}

	// development settings
	cfg.Development = *dev

	// overriding default middleware setting
	cfg.Middleware = *middleware

	// setting default mode
	mode := hv.VirtualizeMode

	if *capture {
		mode = hv.CaptureMode
		// checking whether user supplied other modes
		if *synthesize == true || *modify == true {
			log.Fatal("Two or more modes supplied, check your flags")
		}
	} else if *synthesize {
		mode = hv.SynthesizeMode

		if cfg.Middleware == "" {
			log.Fatal("Synthesize mode chosen although middleware not supplied")
		}

		if *capture == true || *modify == true {
			log.Fatal("Two or more modes supplied, check your flags")
		}
	} else if *modify {
		mode = hv.ModifyMode

		if cfg.Middleware == "" {
			log.Fatal("Modify mode chosen although middleware not supplied")
		}

		if *capture == true || *synthesize == true {
			log.Fatal("Two or more modes supplied, check your flags")
		}
	}

	// overriding default settings
	cfg.Mode = mode

	// overriding destination
	cfg.Destination = *destination

	// getting boltDB
	db := hv.GetDB(cfg.DatabaseName)
	cache := hv.NewBoltDBCache(db, []byte(hv.RequestsBucketName))
	defer cache.CloseDB()

	proxy, dbClient := hv.GetNewHoverfly(cfg, cache)

	ab := backends.NewBoltDBAuthBackend(db, []byte(backends.TokenBucketName), []byte(backends.UserBucketName))
	// loading auth settings
	authentication.Init()

	dbClient.AB = ab

	// if add new user supplied - adding it to database
	if *addNew {
		err := ab.AddUser([]byte(*addUser), []byte(*addPassword))
		if err != nil {
			log.WithFields(log.Fields{
				"error":    err.Error(),
				"username": *addUser,
			}).Fatal("failed to add new user")
		} else {
			log.WithFields(log.Fields{
				"username": *addUser,
			}).Info("user added successfuly")
		}
		return
	}

	// importing stuff
	if *imp != "" {
		err := dbClient.Import(*imp)
		if err != nil {
			log.WithFields(log.Fields{
				"error":  err.Error(),
				"import": *imp,
			}).Fatal("Failed to import given resource")
		}
	}

	// starting admin interface
	dbClient.StartAdminInterface()

	// start metrics registry flush
	if *metrics {
		dbClient.Counter.Init()
	}

	log.Warn(http.ListenAndServe(fmt.Sprintf(":%s", cfg.ProxyPort), proxy))
}
<|endoftext|>


<commit_before>/*
i-sudoku is an interactive command-line sudoku tool
*/

package main

import (
	"fmt"
	"github.com/jkomoros/sudoku"
	"github.com/nsf/termbox-go"
	"log"
	"strings"
	"unicode/utf8"
)

const STATUS_DEFAULT = "(→,←,↓,↑) to move cells, (0-9) to enter number, (m)ark mode, other (c)ommand"
const STATUS_MARKING = "MARKING:"
const STATUS_MARKING_POSTFIX = "  (1-9) to toggle marks, (ENTER) to commit, (ESC) to cancel"
const STATUS_COMMAND = "COMMAND: (q)uit, (n)ew puzzle, (ESC) cancel"

const GRID_INVALID = " INVALID "
const GRID_VALID = "  VALID  "
const GRID_SOLVED = "  SOLVED  "
const GRID_NOT_SOLVED = " UNSOLVED "

//A debug override; if true will print a color palette to the screen, wait for
//a keypress, and then quit. Useful for seeing what different colors are
//available to use.
const DRAW_PALETTE = false

func main() {

	//TODO: should be possible to run it and pass in a puzzle to use.

	if err := termbox.Init(); err != nil {
		log.Fatal("Termbox initialization failed:", err)
	}
	defer termbox.Close()

	termbox.SetOutputMode(termbox.Output256)

	model := newModel()

	width, _ := termbox.Size()
	model.outputWidth = width

	if DRAW_PALETTE {
		drawColorPalette()
		//Wait until something happens, generally a key is pressed.
		termbox.PollEvent()
		return
	}

	draw(model)

mainloop:
	for {
		evt := termbox.PollEvent()
		switch evt.Type {
		case termbox.EventKey:
			model.state.handleInput(model, evt)
		}
		draw(model)
		if model.exitNow {
			break mainloop
		}
		model.EndOfEventLoop()
	}
}

func clearScreen() {
	width, height := termbox.Size()
	for x := 0; x < width; x++ {
		for y := 0; y < height; y++ {
			termbox.SetCell(x, y, ' ', termbox.ColorDefault, termbox.ColorDefault)
		}
	}
}

func drawColorPalette() {
	clearScreen()
	x := 0
	y := 0

	for i := 0x00; i <= 0xFF; i++ {
		numToPrint := "  " + fmt.Sprintf("%02X", i) + "  "
		for _, ch := range numToPrint {
			termbox.SetCell(x, y, ch, termbox.ColorBlack, termbox.Attribute(i))
			x++
		}
		//Fit 8 print outs on a line before creating a new one
		if i%8 == 0 {
			x = 0
			y++
		}
	}

	termbox.Flush()
}

func draw(model *mainModel) {

	clearScreen()

	grid := model.grid

	selectedTop, selectedLeft, selectedHeight, selectedWidth := model.Selected().DiagramExtents()

	x := 0
	y := 0

	for _, line := range strings.Split(grid.Diagram(true), "\n") {
		x = 0
		//The first number in range will be byte offset, but for some items like the bullet, it's two bytes.
		//But what we care about is that each item is a character.
		for _, ch := range line {

			defaultColor := termbox.ColorGreen

			numberRune, _ := utf8.DecodeRuneInString(sudoku.DIAGRAM_NUMBER)
			lockedRune, _ := utf8.DecodeRuneInString(sudoku.DIAGRAM_LOCKED)

			if ch == numberRune {
				defaultColor = termbox.ColorBlue
			} else if ch == lockedRune {
				defaultColor = termbox.ColorRed
			} else if runeIsNum(ch) {
				defaultColor = termbox.ColorGreen | termbox.AttrBold
			}

			backgroundColor := termbox.ColorDefault

			if x >= selectedTop && x < (selectedTop+selectedHeight) && y >= selectedLeft && y < (selectedLeft+selectedWidth) {
				//We're on the selected cell
				backgroundColor = 0xf0
			}

			termbox.SetCell(x, y, ch, defaultColor, backgroundColor)
			x++
		}
		y++
	}

	x = 0
	solvedMsg := GRID_NOT_SOLVED
	fg := termbox.ColorBlue
	bg := termbox.ColorBlack
	if grid.Solved() {
		solvedMsg = GRID_SOLVED
		fg, bg = bg, fg
	}

	for _, ch := range solvedMsg {
		termbox.SetCell(x, y, ch, fg, bg)
		x++
	}

	//don't reset x; this next message should go to the right.
	validMsg := GRID_VALID
	fg = termbox.ColorBlue
	bg = termbox.ColorBlack
	if grid.Invalid() {
		validMsg = GRID_INVALID
		fg, bg = bg, fg
	}
	for _, ch := range validMsg {
		termbox.SetCell(x, y, ch, fg, bg)
		x++
	}

	y++

	x = 0
	underlined := false
	for _, ch := range model.StatusLine() {
		//The ( and ) are non-printing control characters
		if ch == '(' {
			underlined = true
			continue
		} else if ch == ')' {
			underlined = false
			continue
		}
		fg := termbox.ColorWhite
		if underlined {
			fg = fg | termbox.AttrUnderline | termbox.AttrBold
		}

		termbox.SetCell(x, y, ch, fg, termbox.ColorDefault)
		x++
	}

	underlined = false

	splitMessage := strings.Split(model.consoleMessage, "\n")

	for _, line := range splitMessage {
		y++
		x = 0
		for _, ch := range line {
			if ch == '(' {
				underlined = true
				continue
			} else if ch == ')' {
				underlined = false
				continue
			}
			fg := termbox.ColorWhite
			if underlined {
				fg = fg | termbox.AttrBold
			}
			termbox.SetCell(x, y, ch, fg, termbox.ColorBlack)
			x++
		}
	}

	termbox.Flush()
}
<commit_msg>Tweaked color of grid output to emphasize numbers<commit_after>/*
i-sudoku is an interactive command-line sudoku tool
*/

package main

import (
	"fmt"
	"github.com/jkomoros/sudoku"
	"github.com/nsf/termbox-go"
	"log"
	"strings"
	"unicode/utf8"
)

const STATUS_DEFAULT = "(→,←,↓,↑) to move cells, (0-9) to enter number, (m)ark mode, other (c)ommand"
const STATUS_MARKING = "MARKING:"
const STATUS_MARKING_POSTFIX = "  (1-9) to toggle marks, (ENTER) to commit, (ESC) to cancel"
const STATUS_COMMAND = "COMMAND: (q)uit, (n)ew puzzle, (ESC) cancel"

const GRID_INVALID = " INVALID "
const GRID_VALID = "  VALID  "
const GRID_SOLVED = "  SOLVED  "
const GRID_NOT_SOLVED = " UNSOLVED "

//A debug override; if true will print a color palette to the screen, wait for
//a keypress, and then quit. Useful for seeing what different colors are
//available to use.
const DRAW_PALETTE = false

func main() {

	//TODO: should be possible to run it and pass in a puzzle to use.

	if err := termbox.Init(); err != nil {
		log.Fatal("Termbox initialization failed:", err)
	}
	defer termbox.Close()

	termbox.SetOutputMode(termbox.Output256)

	model := newModel()

	width, _ := termbox.Size()
	model.outputWidth = width

	if DRAW_PALETTE {
		drawColorPalette()
		//Wait until something happens, generally a key is pressed.
		termbox.PollEvent()
		return
	}

	draw(model)

mainloop:
	for {
		evt := termbox.PollEvent()
		switch evt.Type {
		case termbox.EventKey:
			model.state.handleInput(model, evt)
		}
		draw(model)
		if model.exitNow {
			break mainloop
		}
		model.EndOfEventLoop()
	}
}

func clearScreen() {
	width, height := termbox.Size()
	for x := 0; x < width; x++ {
		for y := 0; y < height; y++ {
			termbox.SetCell(x, y, ' ', termbox.ColorDefault, termbox.ColorDefault)
		}
	}
}

func drawColorPalette() {
	clearScreen()
	x := 0
	y := 0

	for i := 0x00; i <= 0xFF; i++ {
		numToPrint := "  " + fmt.Sprintf("%02X", i) + "  "
		for _, ch := range numToPrint {
			termbox.SetCell(x, y, ch, termbox.ColorBlack, termbox.Attribute(i))
			x++
		}
		//Fit 8 print outs on a line before creating a new one
		if i%8 == 0 {
			x = 0
			y++
		}
	}

	termbox.Flush()
}

func draw(model *mainModel) {

	clearScreen()

	grid := model.grid

	selectedTop, selectedLeft, selectedHeight, selectedWidth := model.Selected().DiagramExtents()

	x := 0
	y := 0

	for _, line := range strings.Split(grid.Diagram(true), "\n") {
		x = 0
		//The first number in range will be byte offset, but for some items like the bullet, it's two bytes.
		//But what we care about is that each item is a character.
		for _, ch := range line {

			defaultColor := termbox.ColorGreen

			numberRune, _ := utf8.DecodeRuneInString(sudoku.DIAGRAM_NUMBER)
			lockedRune, _ := utf8.DecodeRuneInString(sudoku.DIAGRAM_LOCKED)

			if ch == numberRune {
				defaultColor = 0x12
			} else if ch == lockedRune {
				defaultColor = 0x35
			} else if runeIsNum(ch) {
				defaultColor = termbox.ColorWhite | termbox.AttrBold
			}

			backgroundColor := termbox.ColorDefault

			if x >= selectedTop && x < (selectedTop+selectedHeight) && y >= selectedLeft && y < (selectedLeft+selectedWidth) {
				//We're on the selected cell
				backgroundColor = 0xf0
			}

			termbox.SetCell(x, y, ch, defaultColor, backgroundColor)
			x++
		}
		y++
	}

	x = 0
	solvedMsg := GRID_NOT_SOLVED
	fg := termbox.ColorBlue
	bg := termbox.ColorBlack
	if grid.Solved() {
		solvedMsg = GRID_SOLVED
		fg, bg = bg, fg
	}

	for _, ch := range solvedMsg {
		termbox.SetCell(x, y, ch, fg, bg)
		x++
	}

	//don't reset x; this next message should go to the right.
	validMsg := GRID_VALID
	fg = termbox.ColorBlue
	bg = termbox.ColorBlack
	if grid.Invalid() {
		validMsg = GRID_INVALID
		fg, bg = bg, fg
	}
	for _, ch := range validMsg {
		termbox.SetCell(x, y, ch, fg, bg)
		x++
	}

	y++

	x = 0
	underlined := false
	for _, ch := range model.StatusLine() {
		//The ( and ) are non-printing control characters
		if ch == '(' {
			underlined = true
			continue
		} else if ch == ')' {
			underlined = false
			continue
		}
		fg := termbox.ColorWhite
		if underlined {
			fg = fg | termbox.AttrUnderline | termbox.AttrBold
		}

		termbox.SetCell(x, y, ch, fg, termbox.ColorDefault)
		x++
	}

	underlined = false

	splitMessage := strings.Split(model.consoleMessage, "\n")

	for _, line := range splitMessage {
		y++
		x = 0
		for _, ch := range line {
			if ch == '(' {
				underlined = true
				continue
			} else if ch == ')' {
				underlined = false
				continue
			}
			fg := termbox.ColorWhite
			if underlined {
				fg = fg | termbox.AttrBold
			}
			termbox.SetCell(x, y, ch, fg, termbox.ColorBlack)
			x++
		}
	}

	termbox.Flush()
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"errors"
	"flag"
	"fmt"
	"image"
	_ "image/jpeg"
	"image/png"
	"io/ioutil"
	"net"
	"net/http"

	log "github.com/Sirupsen/logrus"
	"github.com/develed/develed/config"
	srv "github.com/develed/develed/services"
	"github.com/nfnt/resize"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/reflection"
)

var (
	debug = flag.Bool("debug", false, "enter debug mode")
	cfg   = flag.String("config", "/etc/develed.toml", "configuration file")
)

var conf *config.Global

type server struct {
	sink srv.ImageSinkClient
}

func downloadImage(url string) ([]byte, error) {
	resp, err := http.Get(url)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("Failed to retrieve image with code %d\n", resp.StatusCode)
	}

	return ioutil.ReadAll(resp.Body)
}

func (s *server) Show(ctx context.Context, req *srv.ImageRequest) (*srv.ImageResponse, error) {
	var err error
	var buf []byte

	switch t := req.Source.(type) {
	case *srv.ImageRequest_Data:
		buf = req.GetData()
	case *srv.ImageRequest_Url:
		buf, err = downloadImage(req.GetUrl())
		if err != nil {
			return nil, err
		}
	case nil:
		log.Warnln("Empty request!")
		return nil, errors.New("Invalid empty request")
	default:
		log.Errorf("Image source has unexpected type %T\n", t)
		return nil, errors.New("Invalid type in request")
	}

	img, _, err := image.Decode(bytes.NewReader(buf))
	if err != nil {
		return nil, err
	}

	var out bytes.Buffer
	png.Encode(&out, resize.Resize(33, 9, img, resize.Lanczos3))

	resp, err := s.sink.Draw(context.Background(), &srv.DrawRequest{
		Data: out.Bytes(),
	})
	if err != nil {
		return nil, err
	}

	return &srv.ImageResponse{
		Code:   resp.Code,
		Status: resp.Status,
	}, nil
}

func main() {
	var err error

	flag.Parse()

	conf, err = config.Load(*cfg)
	if err != nil {
		log.Fatalln(err)
	}

	if *debug {
		log.SetLevel(log.DebugLevel)
	}

	sock, err := net.Listen("tcp", conf.Imaged.GRPCServerAddress)
	if err != nil {
		log.Fatalln(err)
	}

	conn, err := grpc.Dial(conf.DSPD.GRPCServerAddress, grpc.WithInsecure())
	if err != nil {
		log.Fatalln(err)
	}
	defer conn.Close()

	s := grpc.NewServer()
	srv.RegisterImagedServer(s, &server{
		sink: srv.NewImageSinkClient(conn),
	})
	reflection.Register(s)

	if err := s.Serve(sock); err != nil {
		log.Fatalln(err)
	}
}
<commit_msg>imaged: fix resize dimensions<commit_after>package main

import (
	"bytes"
	"errors"
	"flag"
	"fmt"
	"image"
	_ "image/jpeg"
	"image/png"
	"io/ioutil"
	"net"
	"net/http"

	log "github.com/Sirupsen/logrus"
	"github.com/develed/develed/config"
	srv "github.com/develed/develed/services"
	"github.com/nfnt/resize"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/reflection"
)

var (
	debug = flag.Bool("debug", false, "enter debug mode")
	cfg   = flag.String("config", "/etc/develed.toml", "configuration file")
)

var conf *config.Global

type server struct {
	sink srv.ImageSinkClient
}

func downloadImage(url string) ([]byte, error) {
	resp, err := http.Get(url)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("Failed to retrieve image with code %d\n", resp.StatusCode)
	}

	return ioutil.ReadAll(resp.Body)
}

func (s *server) Show(ctx context.Context, req *srv.ImageRequest) (*srv.ImageResponse, error) {
	var err error
	var buf []byte

	switch t := req.Source.(type) {
	case *srv.ImageRequest_Data:
		buf = req.GetData()
	case *srv.ImageRequest_Url:
		buf, err = downloadImage(req.GetUrl())
		if err != nil {
			return nil, err
		}
	case nil:
		log.Warnln("Empty request!")
		return nil, errors.New("Invalid empty request")
	default:
		log.Errorf("Image source has unexpected type %T\n", t)
		return nil, errors.New("Invalid type in request")
	}

	img, _, err := image.Decode(bytes.NewReader(buf))
	if err != nil {
		return nil, err
	}

	var out bytes.Buffer
	png.Encode(&out, resize.Resize(39, 9, img, resize.Lanczos3))

	resp, err := s.sink.Draw(context.Background(), &srv.DrawRequest{
		Data: out.Bytes(),
	})
	if err != nil {
		return nil, err
	}

	return &srv.ImageResponse{
		Code:   resp.Code,
		Status: resp.Status,
	}, nil
}

func main() {
	var err error

	flag.Parse()

	conf, err = config.Load(*cfg)
	if err != nil {
		log.Fatalln(err)
	}

	if *debug {
		log.SetLevel(log.DebugLevel)
	}

	sock, err := net.Listen("tcp", conf.Imaged.GRPCServerAddress)
	if err != nil {
		log.Fatalln(err)
	}

	conn, err := grpc.Dial(conf.DSPD.GRPCServerAddress, grpc.WithInsecure())
	if err != nil {
		log.Fatalln(err)
	}
	defer conn.Close()

	s := grpc.NewServer()
	srv.RegisterImagedServer(s, &server{
		sink: srv.NewImageSinkClient(conn),
	})
	reflection.Register(s)

	if err := s.Serve(sock); err != nil {
		log.Fatalln(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"github.com/carbontwelve/go-irc-stats/ircstats"
	"log"
	"os"
	"strconv"
	"time"
)

var (
	Version string
	Build   string

	logReader ircstats.IrcLogReader

	version    = flag.Bool("version", false, "Display executable version and build.")
	verbose    = flag.Bool("v", false, "Display actual output")
	configPath = flag.String("c", "config.yaml", "Path to config.yaml")
	cwd        = flag.String("d", "", "change to this directory before doing anything")
)

func main() {
	flag.Usage = func() {
		fmt.Fprintln(os.Stderr, `ircstats is a golang port from ruby of 0x263b/Stats
Usage:
        ircstats [options] ...
The options are:
  -h    Display this help text`)
		flag.PrintDefaults()
		os.Exit(1)
	}

	// Parse command line flags
	flag.Parse()

	if *version {
		fmt.Printf("Version: %s Build %s\n", Version, Build)
		os.Exit(0)
	}

	// Should we be noisy?
	// If false, all stdout messages will be muted
	if *verbose {
		fmt.Println("Being Loud!")
	}

	// Should we change the current working directory? (This is super useful when testing)
	if *cwd != "" {
		err := os.Chdir(*cwd)
		if err != nil {
			log.Fatal(err)
		}
	}

	// Load Configuration
	config := ircstats.Config{}
	configErr := config.Load(*configPath)
	if configErr != nil {
		log.Fatal(configErr)
	}

	// Load Data Store (I call it Database, but its actually a binary file)
	db := ircstats.Database{}
	db.Load(config.DatabaseLocation)

	fmt.Println("Last Parsed: ", db.LastGenerated)
	logReader = *ircstats.NewIrcLogReader(config)

	// Load log file and parse any new lines
	logReaderErr := logReader.Load(config.Location, &db)
	if logReaderErr != nil {
		log.Fatal(logReaderErr)
	}

	// Calculate
	calculate(&db, config)

	// Save database to disk
	dbSaveErr := db.Save(config.DatabaseLocation)
	if logReaderErr != nil {
		log.Fatal(dbSaveErr)
	}

	// Lol "stats"
	fmt.Printf("%d number of new lines parsed.\n\n", logReader.NewLinesFound())
	fmt.Println("= [ Dates ] ======================================")
	fmt.Printf("First line date\t\t\t\t\t%d\n", db.Channel.FirstSeen)
	fmt.Printf("Last line date\t\t\t\t\t%d\n", db.Channel.LastSeen)
	fmt.Printf("Total Days Seen:\t\t\t\t%d\n", db.Channel.TotalDaysSeen())
	fmt.Println("= [ Averages ] ===================================")
	fmt.Printf("Mean Lines/Hr:\t\t\t\t\t%f\n", db.Channel.Averages.Hour)
	fmt.Printf("Mean Lines/Day:\t\t\t\t\t%f\n", db.Channel.Averages.Day)
	fmt.Printf("Mean Lines/Week:\t\t\t\t%f\n", db.Channel.Averages.Week)
	fmt.Printf("Mean Lines/Week Day:\t\t\t%f\n", db.Channel.Averages.WeekDay)
	fmt.Println("= [ Counters ] ===================================")
	fmt.Printf("Total Lines Parsed:\t\t\t\t%d\n", db.Channel.LineCount)
	fmt.Printf("Total Unique Users:\t\t\t\t%d\n", db.Channel.UserCount)
	fmt.Printf("Users Active in past 30 days:\t%d\n", len(db.Channel.ActiveUsers))

	fmt.Printf("Peak Day Date:\t\t\t\t\t%s\n", db.Channel.MaxDay.Day)
	fmt.Printf("Peak Day Lines:\t\t\t\t\t%d\n", db.Channel.MaxDay.Lines)

	fmt.Printf("Peak Hour:\t\t\t\t\t\t%d\n", db.Channel.MaxHour.Hour)
	fmt.Printf("Peak Hour Lines:\t\t\t\t%d\n", db.Channel.MaxHour.Lines)

	fmt.Printf("Peak Week:\t\t\t\t\t\t%d\n", db.Channel.MaxWeek.Week)
	fmt.Printf("Peak Week Lines:\t\t\t\t%d\n", db.Channel.MaxWeek.Lines)

	fmt.Println("==================================================")

	vd := *ircstats.NewViewData(config)
	vd.JsonData.Channel = db.Channel;
	j, _ := vd.GetJsonString()
	fmt.Printf("%s\n", j)

	//
	// Generate the template
	//
	v := *ircstats.NewView()
	err := v.Parse("template.html", vd)
	if err != nil {
		panic(err)
	}
}

func calculate(db *ircstats.Database, config ircstats.Config) {
	// Calculate UserCount
	db.Channel.UserCount = int64(len(db.Users))
	db.Channel.MaxDay.Day, db.Channel.MaxDay.Lines = db.Channel.FindPeakDay()
	db.Channel.MaxHour.Hour, db.Channel.MaxHour.Lines = db.Channel.FindPeakHour()
	db.Channel.MaxWeek.Week, db.Channel.MaxWeek.Lines = db.Channel.FindPeakWeek()

	db.Channel.Averages.Hour = db.Channel.FindHourAverage()
	db.Channel.Averages.Week = db.Channel.FindWeekAverage()
	db.Channel.Averages.Day = db.Channel.FindDayAverage()

	// Calculate Active Users
	calculateActiveUsers(db)

	//calculateHeatMapDays(db, config.HeatMapInterval)
}

// Calculate active users within past 30 days
func calculateActiveUsers(db *ircstats.Database) {
	timePeriod := make(map[string]bool)
	db.Channel.ActiveUsers = make(map[string]ircstats.User)

	for i := 1; i < 30; i++ {
		timePeriod[time.Now().AddDate(0, 0, -i).Format("2006-02-01")] = true
	}

	for _, u := range db.Users {
		var (
			wordCount  int64
			daysActive int64
		)

		// Check to see if user has been active within our time period (default past 30 days)
		for timePeriodDate := range timePeriod {
			if _, ok := u.Days[timePeriodDate]; ok {
				daysActive++
				wordCount += u.Days[timePeriodDate]
			}
		}

		// If the user is active, copy the struct and push it to the active users hash
		if daysActive > 0 {
			uc := u
			uc.WordCount = wordCount
			uc.DaysActive = daysActive
			uc.WordsDay = wordCount / daysActive
			db.Channel.ActiveUsers[uc.Username] = uc
		}
	}
}

type WeekValue struct {
	X     int64
	Value int64
	First string
	Last  string
}

type DayValue struct {
	X     int64
	Y     int64
	Date  string
	Class string
	Value int64
}

// @todo move this functionality to javascript
func calculateHeatMapDays(db *ircstats.Database, heatMapInterval uint) {

	var (
		heatMapKey [6]int
		now        time.Time
		totalDays  int
		firstWeek  string
		lastWeek   string
		weekValues []WeekValue
		dayValues  []DayValue
		x          int64
		mx         int64
		y          int64
		weekLines  int64
		dayLines   int64
		cssClass   string
	)

	now = time.Now()
	totalDays = int(db.Channel.TotalDaysSeen())

	// Create heatmap key
	for i := 1; i < 6; i++ {
		heatMapKey[i] = int(heatMapInterval) * i
	}

	// Build Days Data
	for i := 0; i < totalDays; i++ {
		elementTime := now.AddDate(0, 0, int(-(totalDays - i)))

		// Work out first week
		if i == 0 {
			firstWeek = elementTime.Format("Jan-01")
		}

		// Y is bound to week day (Sunday = 0)
		y = int64(elementTime.Weekday())

		// If day is a Sunday then begin new week
		if y == 0 {
			x += 1
			weekLines = 0
			firstWeek = elementTime.Format("Jan-01")
		}

		// If this is the first day of the month
		if elementTime.Day() == 1 {
			mx++
		}

		if db.Channel.HasDay(elementTime.Format("2006-02-01")) {
			dayLines = int64(db.Channel.Days[elementTime.Format("2006-02-01")])
		} else {
			dayLines = 0
		}

		weekLines += dayLines

		// If day is Saturday then end week
		if y == 6 {
			lastWeek = elementTime.Format("Jan-01")
			weekValues = append(weekValues, WeekValue{X: x, Value: weekLines, First: firstWeek, Last: lastWeek})
		}

		// Identify class
		classSet := false
		for i := 1; i < 6; i++ {
			if int(dayLines) < heatMapKey[i] {
				cssClass = "scale-" + strconv.Itoa(i)
				classSet = true
				break
			}
		}
		if classSet == false {
			cssClass = "scale-6"
		}

		// Append days value
		dayValues = append(dayValues, DayValue{X: x, Y: y, Date: elementTime.Format("2006-02-01"), Class: cssClass, Value: dayLines})
	}
}
<commit_msg>Refactored Calculate step into view data<commit_after>package main

import (
	"flag"
	"fmt"
	"github.com/carbontwelve/go-irc-stats/ircstats"
	"log"
	"os"
	"strconv"
	"time"
)

var (
	Version string
	Build   string

	logReader ircstats.IrcLogReader

	version    = flag.Bool("version", false, "Display executable version and build.")
	verbose    = flag.Bool("v", false, "Display actual output")
	configPath = flag.String("c", "config.yaml", "Path to config.yaml")
	cwd        = flag.String("d", "", "change to this directory before doing anything")
)

func main() {
	flag.Usage = func() {
		fmt.Fprintln(os.Stderr, `ircstats is a golang port from ruby of 0x263b/Stats
Usage:
        ircstats [options] ...
The options are:
  -h    Display this help text`)
		flag.PrintDefaults()
		os.Exit(1)
	}

	// Parse command line flags
	flag.Parse()

	if *version {
		fmt.Printf("Version: %s Build %s\n", Version, Build)
		os.Exit(0)
	}

	// Should we be noisy?
	// If false, all stdout messages will be muted
	if *verbose {
		fmt.Println("Being Loud!")
	}

	// Should we change the current working directory? (This is super useful when testing)
	if *cwd != "" {
		err := os.Chdir(*cwd)
		if err != nil {
			log.Fatal(err)
		}
	}

	// Load Configuration
	config := ircstats.Config{}
	configErr := config.Load(*configPath)
	if configErr != nil {
		log.Fatal(configErr)
	}

	// Load Data Store (I call it Database, but its actually a binary file)
	db := ircstats.Database{}
	db.Load(config.DatabaseLocation)

	fmt.Println("Last Parsed: ", db.LastGenerated)
	logReader = *ircstats.NewIrcLogReader(config)

	// Load log file and parse any new lines
	logReaderErr := logReader.Load(config.Location, &db)
	if logReaderErr != nil {
		log.Fatal(logReaderErr)
	}

	// Save database to disk
	dbSaveErr := db.Save(config.DatabaseLocation)
	if logReaderErr != nil {
		log.Fatal(dbSaveErr)
	}

	vd := *ircstats.NewViewData(config)
	vd.Calculate(db);
	vd.JsonData.Debug()

	j, _ := vd.GetJsonString()
	fmt.Printf("%s\n", j)

	//
	// Generate the template
	//
	v := *ircstats.NewView()
	err := v.Parse("template.html", vd)
	if err != nil {
		panic(err)
	}
}
<|endoftext|>


<commit_before>// Copyright 2013, 2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package main

import (
	"fmt"
	"io"

	"github.com/juju/loggo"
	"launchpad.net/gnuflag"

	"launchpad.net/juju-core/cmd"
	"launchpad.net/juju-core/cmd/envcmd"
	"launchpad.net/juju-core/errors"
	"launchpad.net/juju-core/juju"
	"launchpad.net/juju-core/state/api"
)

type DebugLogCommand struct {
	envcmd.EnvCommandBase

	level  string
	params api.DebugLogParams
}

var DefaultLogLocation = "/var/log/juju/all-machines.log"

// defaultLineCount is the default number of lines to
// display, from the end of the consolidated log.
const defaultLineCount = 10

const debuglogDoc = `
Stream the consolidated debug log file. This file contains the log messages
from all nodes in the environment.
`

func (c *DebugLogCommand) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "debug-log",
		Purpose: "display the consolidated log file",
		Doc:     debuglogDoc,
	}
}

func (c *DebugLogCommand) SetFlags(f *gnuflag.FlagSet) {
	c.EnvCommandBase.SetFlags(f)

	f.Var(cmd.NewAppendStringsValue(&c.params.IncludeEntity), "i", "only show log messages for these entities")
	f.Var(cmd.NewAppendStringsValue(&c.params.IncludeEntity), "include", "only show log messages for these entities")
	f.Var(cmd.NewAppendStringsValue(&c.params.ExcludeEntity), "x", "only show log messages for these entities")
	f.Var(cmd.NewAppendStringsValue(&c.params.ExcludeEntity), "exclude", "only show log messages for these entities")
	f.Var(cmd.NewAppendStringsValue(&c.params.IncludeModule), "include-module", "only show log messages for these logging modules")
	f.Var(cmd.NewAppendStringsValue(&c.params.ExcludeModule), "exclude-module", "do not show log messages for these logging modules")

	f.StringVar(&c.level, "l", "", "log level to show, one of [TRACE, DEBUG, INFO, WARNING, ERROR]")
	f.StringVar(&c.level, "level", "", "")

	f.UintVar(&c.params.Backlog, "n", defaultLineCount, "go back this many lines from the end before starting to filter")
	f.UintVar(&c.params.Backlog, "lines", defaultLineCount, "")
	f.UintVar(&c.params.Limit, "limit", 0, "show at most this many lines")
	f.BoolVar(&c.params.Replay, "replay", false, "start filtering from the start")
}

func (c *DebugLogCommand) Init(args []string) error {
	err := c.EnvCommandBase.Init()
	if err != nil {
		return err
	}
	if c.level != "" {
		level, ok := loggo.ParseLevel(c.level)
		if !ok || level < loggo.TRACE || level > loggo.ERROR {
			return fmt.Errorf("level value %q is not one of %q, %q, %q, %q, %q",
				c.level, loggo.TRACE, loggo.DEBUG, loggo.INFO, loggo.WARNING, loggo.ERROR)
		}
		c.params.Level = level
	}
	return cmd.CheckEmpty(args)
}

type DebugLogAPI interface {
	WatchDebugLog(params api.DebugLogParams) (io.ReadCloser, error)
	Close() error
}

var getDebugLogAPI = func(envName string) (DebugLogAPI, error) {
	return juju.NewAPIClientFromName(envName)
}

// Run retrieves the debug log via the API.
func (c *DebugLogCommand) Run(ctx *cmd.Context) (err error) {
	client, err := getDebugLogAPI(c.EnvName)
	if err != nil {
		return err
	}
	defer client.Close()
	debugLog, err := client.WatchDebugLog(c.params)
	if err != nil {
		if errors.IsNotSupportedError(err) {
			return c.watchDebugLog1dot16(ctx)
		}
		return err
	}
	defer debugLog.Close()
	_, err = io.Copy(ctx.Stdout, debugLog)
	return err
}

var runSSHCommand = func(sshCmd *SSHCommand, ctx *cmd.Context) error {
	return sshCmd.Run(ctx)
}

// watchDebugLog1dot16 runs in case of an older API server and uses ssh
// but with server-side grep.
func (c *DebugLogCommand) watchDebugLog1dot16(ctx *cmd.Context) error {
	ctx.Infof("Server does not support new stream log, falling back to tail")
	ctx.Verbosef("filters are not supported with tail")
	sshCmd := &SSHCommand{}
	tailCmd := fmt.Sprintf("tail -n -%d -f %s", c.params.Backlog, DefaultLogLocation)
	// If the api doesn't support WatchDebugLog, then it won't be running in
	// HA either, so machine 0 is where it is all at.
	args := []string{"0", tailCmd}
	err := sshCmd.Init(args)
	if err != nil {
		return err
	}
	sshCmd.EnvName = c.EnvName
	return runSSHCommand(sshCmd, ctx)
}
<commit_msg>Change the 1.16 reference to 1.18.<commit_after>// Copyright 2013, 2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package main

import (
	"fmt"
	"io"

	"github.com/juju/loggo"
	"launchpad.net/gnuflag"

	"launchpad.net/juju-core/cmd"
	"launchpad.net/juju-core/cmd/envcmd"
	"launchpad.net/juju-core/errors"
	"launchpad.net/juju-core/juju"
	"launchpad.net/juju-core/state/api"
)

type DebugLogCommand struct {
	envcmd.EnvCommandBase

	level  string
	params api.DebugLogParams
}

var DefaultLogLocation = "/var/log/juju/all-machines.log"

// defaultLineCount is the default number of lines to
// display, from the end of the consolidated log.
const defaultLineCount = 10

const debuglogDoc = `
Stream the consolidated debug log file. This file contains the log messages
from all nodes in the environment.
`

func (c *DebugLogCommand) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "debug-log",
		Purpose: "display the consolidated log file",
		Doc:     debuglogDoc,
	}
}

func (c *DebugLogCommand) SetFlags(f *gnuflag.FlagSet) {
	c.EnvCommandBase.SetFlags(f)

	f.Var(cmd.NewAppendStringsValue(&c.params.IncludeEntity), "i", "only show log messages for these entities")
	f.Var(cmd.NewAppendStringsValue(&c.params.IncludeEntity), "include", "only show log messages for these entities")
	f.Var(cmd.NewAppendStringsValue(&c.params.ExcludeEntity), "x", "only show log messages for these entities")
	f.Var(cmd.NewAppendStringsValue(&c.params.ExcludeEntity), "exclude", "only show log messages for these entities")
	f.Var(cmd.NewAppendStringsValue(&c.params.IncludeModule), "include-module", "only show log messages for these logging modules")
	f.Var(cmd.NewAppendStringsValue(&c.params.ExcludeModule), "exclude-module", "do not show log messages for these logging modules")

	f.StringVar(&c.level, "l", "", "log level to show, one of [TRACE, DEBUG, INFO, WARNING, ERROR]")
	f.StringVar(&c.level, "level", "", "")

	f.UintVar(&c.params.Backlog, "n", defaultLineCount, "go back this many lines from the end before starting to filter")
	f.UintVar(&c.params.Backlog, "lines", defaultLineCount, "")
	f.UintVar(&c.params.Limit, "limit", 0, "show at most this many lines")
	f.BoolVar(&c.params.Replay, "replay", false, "start filtering from the start")
}

func (c *DebugLogCommand) Init(args []string) error {
	err := c.EnvCommandBase.Init()
	if err != nil {
		return err
	}
	if c.level != "" {
		level, ok := loggo.ParseLevel(c.level)
		if !ok || level < loggo.TRACE || level > loggo.ERROR {
			return fmt.Errorf("level value %q is not one of %q, %q, %q, %q, %q",
				c.level, loggo.TRACE, loggo.DEBUG, loggo.INFO, loggo.WARNING, loggo.ERROR)
		}
		c.params.Level = level
	}
	return cmd.CheckEmpty(args)
}

type DebugLogAPI interface {
	WatchDebugLog(params api.DebugLogParams) (io.ReadCloser, error)
	Close() error
}

var getDebugLogAPI = func(envName string) (DebugLogAPI, error) {
	return juju.NewAPIClientFromName(envName)
}

// Run retrieves the debug log via the API.
func (c *DebugLogCommand) Run(ctx *cmd.Context) (err error) {
	client, err := getDebugLogAPI(c.EnvName)
	if err != nil {
		return err
	}
	defer client.Close()
	debugLog, err := client.WatchDebugLog(c.params)
	if err != nil {
		if errors.IsNotSupportedError(err) {
			return c.watchDebugLog1dot18(ctx)
		}
		return err
	}
	defer debugLog.Close()
	_, err = io.Copy(ctx.Stdout, debugLog)
	return err
}

var runSSHCommand = func(sshCmd *SSHCommand, ctx *cmd.Context) error {
	return sshCmd.Run(ctx)
}

// watchDebugLog1dot18 runs in case of an older API server and uses ssh
// but with server-side grep.
func (c *DebugLogCommand) watchDebugLog1dot18(ctx *cmd.Context) error {
	ctx.Infof("Server does not support new stream log, falling back to tail")
	ctx.Verbosef("filters are not supported with tail")
	sshCmd := &SSHCommand{}
	tailCmd := fmt.Sprintf("tail -n -%d -f %s", c.params.Backlog, DefaultLogLocation)
	// If the api doesn't support WatchDebugLog, then it won't be running in
	// HA either, so machine 0 is where it is all at.
	args := []string{"0", tailCmd}
	err := sshCmd.Init(args)
	if err != nil {
		return err
	}
	sshCmd.EnvName = c.EnvName
	return runSSHCommand(sshCmd, ctx)
}
<|endoftext|>


<commit_before>// Copyright 2021 Google LLC
//
// 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 kvm

import (
	"fmt"

	"github.com/spf13/cobra"
	"github.com/srinandan/apigeecli/apiclient"
	"github.com/srinandan/apigeecli/client/kvm"
)

//ListEntryCmd to create kvm map entry
var ListEntryCmd = &cobra.Command{
	Use:   "list",
	Short: "List KV Map entries",
	Long:  "List KV Map entries",
	Args: func(cmd *cobra.Command, args []string) (err error) {
		if env != "" {
			apiclient.SetApigeeEnv(env)
		}
		if env != "" && proxyName != "" {
			return fmt.Errorf("proxy and env flags cannot be used together")
		}
		return apiclient.SetApigeeOrg(org)
	},
	RunE: func(cmd *cobra.Command, args []string) (err error) {
		_, err = kvm.ListEntries(proxyName, mapName, pageToken)
		return
	},
}

var pageToken string

func init() {
	ListEntryCmd.Flags().StringVarP(&mapName, "map", "m",
		"", "KV Map Name")
	ListEntryCmd.Flags().StringVarP(&env, "env", "e",
		"", "Environment name")
	ListEntryCmd.Flags().StringVarP(&proxyName, "proxy", "p",
		"", "API Proxy name")
	ListEntryCmd.Flags().StringVarP(&pageToken, "page-token", "",
		"", "next_page_token from the prior response to be used to fetch the next dataset")

	_ = ListEntryCmd.MarkFlagRequired("map")
}
<commit_msg>support page size<commit_after>// Copyright 2021 Google LLC
//
// 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 kvm

import (
	"fmt"

	"github.com/spf13/cobra"
	"github.com/srinandan/apigeecli/apiclient"
	"github.com/srinandan/apigeecli/client/kvm"
)

//ListEntryCmd to create kvm map entry
var ListEntryCmd = &cobra.Command{
	Use:   "list",
	Short: "List KV Map entries",
	Long:  "List KV Map entries",
	Args: func(cmd *cobra.Command, args []string) (err error) {
		if env != "" {
			apiclient.SetApigeeEnv(env)
		}
		if env != "" && proxyName != "" {
			return fmt.Errorf("proxy and env flags cannot be used together")
		}
		return apiclient.SetApigeeOrg(org)
	},
	RunE: func(cmd *cobra.Command, args []string) (err error) {
		_, err = kvm.ListEntries(proxyName, mapName, pageSize, pageToken)
		return
	},
}

var pageToken string
var pageSize int

func init() {
	ListEntryCmd.Flags().StringVarP(&mapName, "map", "m",
		"", "KV Map Name")
	ListEntryCmd.Flags().StringVarP(&env, "env", "e",
		"", "Environment name")
	ListEntryCmd.Flags().StringVarP(&proxyName, "proxy", "p",
		"", "API Proxy name")
	ListEntryCmd.Flags().StringVarP(&pageToken, "page-token", "",
		"", "next_page_token from the prior response to be used to fetch the next dataset")
	ListEntryCmd.Flags().IntVarP(&pageSize, "page-size", "",
		-1, "Number of items to return on the list")

	_ = ListEntryCmd.MarkFlagRequired("map")
}
<|endoftext|>


<commit_before>package cmd

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"runtime"
	"strconv"
	"strings"
	"text/template"

	"github.com/MakeNowJust/heredoc/v2"
	"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 mrCreateDiscussionCmd = &cobra.Command{
	Use:     "discussion [remote] <id>",
	Short:   "Start a discussion on an MR on GitLab",
	Aliases: []string{"block", "thread"},
	Example: heredoc.Doc(`
		lab mr discussion origin
		lab mr discussion my_remote -m "discussion comment"
		lab mr discussion upstream -F test_file.txt
		lab mr discussion --commit abcdef123456`),
	PersistentPreRun: labPersistentPreRun,
	Run: func(cmd *cobra.Command, args []string) {
		rn, mrNum, err := parseArgsWithGitBranchMR(args)
		if err != nil {
			log.Fatal(err)
		}

		msgs, err := cmd.Flags().GetStringSlice("message")
		if err != nil {
			log.Fatal(err)
		}

		filename, err := cmd.Flags().GetString("file")
		if err != nil {
			log.Fatal(err)
		}

		commit, err := cmd.Flags().GetString("commit")
		if err != nil {
			log.Fatal(err)
		}

		body := ""
		if filename != "" {
			content, err := ioutil.ReadFile(filename)
			if err != nil {
				log.Fatal(err)
			}
			body = string(content)
		} else if commit == "" {
			body, err = mrDiscussionMsg(msgs)
			if err != nil {
				_, f, l, _ := runtime.Caller(0)
				log.Fatal(f+":"+strconv.Itoa(l)+" ", err)
			}
		} else {
			body = getCommitBody(rn, commit)
			body, err = noteMsg(nil, true, body)
			if err != nil {
				_, f, l, _ := runtime.Caller(0)
				log.Fatal(f+":"+strconv.Itoa(l)+" ", err)
			}
			createCommitComments(rn, int(mrNum), commit, body, true)
			return
		}

		if body == "" {
			log.Fatal("aborting discussion due to empty discussion msg")
		}

		discussionURL, err := lab.MRCreateDiscussion(rn, int(mrNum), &gitlab.CreateMergeRequestDiscussionOptions{
			Body: &body,
		})
		if err != nil {
			log.Fatal(err)
		}
		fmt.Println(discussionURL)
	},
}

func mrDiscussionMsg(msgs []string) (string, error) {
	if len(msgs) > 0 {
		return strings.Join(msgs[0:], "\n\n"), nil
	}

	text, err := mrDiscussionText()
	if err != nil {
		return "", err
	}
	return git.EditFile("MR_DISCUSSION", text)
}

func mrDiscussionText() (string, error) {
	tmpl := heredoc.Doc(`
		{{.InitMsg}}
		{{.CommentChar}} Write a message for this discussion. Commented lines are discarded.`)

	initMsg := "\n"
	commentChar := git.CommentChar()

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

	msg := &struct {
		InitMsg     string
		CommentChar string
	}{
		InitMsg:     initMsg,
		CommentChar: commentChar,
	}

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

	return b.String(), nil
}

func init() {
	mrCreateDiscussionCmd.Flags().StringSliceP("message", "m", []string{}, "use the given <msg>; multiple -m are concatenated as separate paragraphs")
	mrCreateDiscussionCmd.Flags().StringP("file", "F", "", "use the given file as the message")
	mrCreateDiscussionCmd.Flags().StringP("commit", "c", "", "start a thread on a commit")

	mrCmd.AddCommand(mrCreateDiscussionCmd)
	carapace.Gen(mrCreateDiscussionCmd).PositionalCompletion(
		action.Remotes(),
		action.MergeRequests(mrList),
	)
}
<commit_msg>mr_discussion: Use mrDiscussionMsg instead of noteMsg<commit_after>package cmd

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"runtime"
	"strconv"
	"strings"
	"text/template"

	"github.com/MakeNowJust/heredoc/v2"
	"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 mrCreateDiscussionCmd = &cobra.Command{
	Use:     "discussion [remote] <id>",
	Short:   "Start a discussion on an MR on GitLab",
	Aliases: []string{"block", "thread"},
	Example: heredoc.Doc(`
		lab mr discussion origin
		lab mr discussion my_remote -m "discussion comment"
		lab mr discussion upstream -F test_file.txt
		lab mr discussion --commit abcdef123456`),
	PersistentPreRun: labPersistentPreRun,
	Run: func(cmd *cobra.Command, args []string) {
		rn, mrNum, err := parseArgsWithGitBranchMR(args)
		if err != nil {
			log.Fatal(err)
		}

		msgs, err := cmd.Flags().GetStringSlice("message")
		if err != nil {
			log.Fatal(err)
		}

		filename, err := cmd.Flags().GetString("file")
		if err != nil {
			log.Fatal(err)
		}

		commit, err := cmd.Flags().GetString("commit")
		if err != nil {
			log.Fatal(err)
		}

		body := ""
		if filename != "" {
			content, err := ioutil.ReadFile(filename)
			if err != nil {
				log.Fatal(err)
			}
			body = string(content)
		} else if commit == "" {
			body, err = mrDiscussionMsg(msgs, "\n")
			if err != nil {
				_, f, l, _ := runtime.Caller(0)
				log.Fatal(f+":"+strconv.Itoa(l)+" ", err)
			}
		} else {
			body = getCommitBody(rn, commit)
			body, err = mrDiscussionMsg(nil, body)
			if err != nil {
				_, f, l, _ := runtime.Caller(0)
				log.Fatal(f+":"+strconv.Itoa(l)+" ", err)
			}
			createCommitComments(rn, int(mrNum), commit, body, true)
			return
		}

		if body == "" {
			log.Fatal("aborting discussion due to empty discussion msg")
		}

		discussionURL, err := lab.MRCreateDiscussion(rn, int(mrNum), &gitlab.CreateMergeRequestDiscussionOptions{
			Body: &body,
		})
		if err != nil {
			log.Fatal(err)
		}
		fmt.Println(discussionURL)
	},
}

func mrDiscussionMsg(msgs []string, body string) (string, error) {
	if len(msgs) > 0 {
		return strings.Join(msgs[0:], "\n\n"), nil
	}

	text, err := mrDiscussionText(body)
	if err != nil {
		return "", err
	}
	return git.EditFile("MR_DISCUSSION", text)
}

func mrDiscussionText(body string) (string, error) {
	tmpl := heredoc.Doc(`
		{{.InitMsg}}
		{{.CommentChar}} Write a message for this discussion. Commented lines are discarded.`)

	initMsg := body
	commentChar := git.CommentChar()

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

	msg := &struct {
		InitMsg     string
		CommentChar string
	}{
		InitMsg:     initMsg,
		CommentChar: commentChar,
	}

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

	return b.String(), nil
}

func init() {
	mrCreateDiscussionCmd.Flags().StringSliceP("message", "m", []string{}, "use the given <msg>; multiple -m are concatenated as separate paragraphs")
	mrCreateDiscussionCmd.Flags().StringP("file", "F", "", "use the given file as the message")
	mrCreateDiscussionCmd.Flags().StringP("commit", "c", "", "start a thread on a commit")

	mrCmd.AddCommand(mrCreateDiscussionCmd)
	carapace.Gen(mrCreateDiscussionCmd).PositionalCompletion(
		action.Remotes(),
		action.MergeRequests(mrList),
	)
}
<|endoftext|>


<commit_before>/*
Copyright 2017 The Reposeed 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 main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"text/template"

	"github.com/okkur/reposeed/cmd/reposeed/config"
	"github.com/okkur/reposeed/cmd/reposeed/templates"
	yaml "gopkg.in/yaml.v2"
)

const SupportedConfigVersion = "v1"

func parseConfig(path string) config.Config {
	var conf config.Config

	filename, _ := filepath.Abs(path)
	file, err := ioutil.ReadFile(filename)
	if err != nil {
		panic(err)
	}
	err = yaml.Unmarshal(file, &conf)
	if err != nil {
		panic(err)
	}
	return conf
}

func generateFile(config config.Config, fileContent []byte, newPath string, overwrite bool) error {
	if _, e := os.Stat(newPath); os.IsNotExist(e) {
		os.MkdirAll(filepath.Dir(newPath), os.ModePerm)
	}

	if !overwrite {
		if _, e := os.Stat(newPath); !os.IsNotExist(e) {
			return fmt.Errorf("file %s not overwritten", newPath)
		}
	}

	file, err := os.Create(newPath)
	if err != nil {
		return fmt.Errorf("unable to create file: %s", err)
	}
	defer file.Close()

	temp, err := template.New("template").Parse(string(fileContent))
	if err != nil {
		return fmt.Errorf("unable to parse file: %s", err)
	}

	err = temp.Execute(file, config)
	if err != nil {
		return fmt.Errorf("unable to parse template: %s", err)
	}

	return nil
}

func main() {
	var outputDir, conf string
	var overwrite bool
	flag.StringVar(&outputDir, "output", "", "Output directory")
	flag.StringVar(&conf, "conf", ".seed-config.yaml", "Config file")
	flag.BoolVar(&overwrite, "overwrite", false, "Force overwrite files")

	flag.Parse()
	box := templates.GetTemplates()

	// Commands
	if os.Args[1] == "init" {
		seedString := box.String("seed-config.example.yaml")
		file, _ := os.Create(os.Args[2] + "/.seed-config.yaml")
		defer file.Close()
		file.WriteString(seedString)
		os.Exit(1)
	}

	config := parseConfig(conf)
	templatesName := box.List()
	bl := make(map[string]bool)
	bl["seed-config.example.yaml"] = true
	configVersion := config.Reposeed.ConfigVersion

	if configVersion == SupportedConfigVersion {
		for _, templateName := range templatesName {
			file, _ := box.Open(templateName)
			fileStat, _ := file.Stat()
			fileContent := box.Bytes(templateName)
			if bl[fileStat.Name()] {
				log.Println(filepath.SkipDir)
				continue
			}

			if fileStat.IsDir() {
				continue
			}

			err := generateFile(config, fileContent, templateName, overwrite)
			if err != nil {
				log.Println(err)
			}
		}
	} else {
		log.Fatalf("Invalid config version. Currently supported versions: v1")
	}
}
<commit_msg>Parse all templates at start<commit_after>/*
Copyright 2017 The Reposeed 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 main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"text/template"

	"github.com/gobuffalo/packr"
	"github.com/okkur/reposeed/cmd/reposeed/config"
	templatesBox "github.com/okkur/reposeed/cmd/reposeed/templates"
	yaml "gopkg.in/yaml.v2"
)

const SupportedConfigVersion = "v1"

func parseConfig(path string) config.Config {
	var conf config.Config

	filename, _ := filepath.Abs(path)
	file, err := ioutil.ReadFile(filename)
	if err != nil {
		panic(err)
	}
	err = yaml.Unmarshal(file, &conf)
	if err != nil {
		panic(err)
	}
	return conf
}

func parseTemplates(box packr.Box) *template.Template {
	templatesName := box.List()
	templates := &template.Template{}
	for _, templateName := range templatesName {
		templateFile, err := box.Open(templateName)
		if err != nil {
			log.Fatalf("could not open the template file: %s", templateName)
		}
		defer templateFile.Close()
		templateContent := box.String(templateName)
		templates.New(templateName).Parse(templateContent)
	}
	return templates
}

func generateFile(config config.Config, templates *template.Template, newPath string, overwrite bool) error {
	if _, e := os.Stat(newPath); os.IsNotExist(e) {
		os.MkdirAll(filepath.Dir(newPath), os.ModePerm)
	}

	if !overwrite {
		if _, e := os.Stat(newPath); !os.IsNotExist(e) {
			return fmt.Errorf("file %s not overwritten", newPath)
		}
	}

	file, err := os.Create(newPath)
	if err != nil {
		return fmt.Errorf("unable to create file: %s", err)
	}
	defer file.Close()

	err = templates.Lookup(newPath).Execute(file, config)
	if err != nil {
		return fmt.Errorf("unable to parse template: %s", err)
	}

	return nil
}

func main() {
	var outputDir, conf string
	var overwrite bool
	flag.StringVar(&outputDir, "output", "", "Output directory")
	flag.StringVar(&conf, "conf", ".seed-config.yaml", "Config file")
	flag.BoolVar(&overwrite, "overwrite", false, "Force overwrite files")

	flag.Parse()
	box := templatesBox.GetTemplates()

	// Commands
	if os.Args[1] == "init" {
		seedString := box.String("seed-config.example.yaml")
		file, _ := os.Create(os.Args[2] + "/.seed-config.yaml")
		defer file.Close()
		file.WriteString(seedString)
		os.Exit(1)
	}

	config := parseConfig(conf)
	bl := make(map[string]bool)
	bl["seed-config.example.yaml"] = true
	configVersion := config.Reposeed.ConfigVersion
	templates := parseTemplates(box)

	if configVersion == SupportedConfigVersion {
		for _, templateName := range box.List() {
			file, _ := box.Open(templateName)
			fileStat, _ := file.Stat()
			if bl[fileStat.Name()] {
				log.Println(filepath.SkipDir)
				continue
			}

			if fileStat.IsDir() {
				continue
			}

			err := generateFile(config, templates, templateName, overwrite)
			if err != nil {
				log.Println(err)
			}
		}
	} else {
		log.Fatalf("Invalid config version. Currently supported versions: v1")
	}
}
<|endoftext|>