<commit_before>/*
Copyright 2019 The Skaffold 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 cmd

import (
	"reflect"

	"github.com/spf13/pflag"

	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/constants"
)

// Flag defines a Skaffold CLI flag which contains a list of
// subcommands the flag belongs to in `DefinedOn` field.
type Flag struct {
	Name          string
	Shorthand     string
	Usage         string
	Value         interface{}
	DefValue      interface{}
	FlagAddMethod string
	DefinedOn     []string
}

// FlagRegistry is a list of all Skaffold CLI flags.
// When adding a new flag to the registry, please specify the
// command/commands to which the flag belongs in `DefinedOn` field.
// If the flag is a global flag, or belongs to all the subcommands,
/// specify "all"
// FlagAddMethod is method which defines a flag value with specified
// name, default value, and usage string. e.g. `StringVar`, `BoolVar`
var FlagRegistry = []Flag{
	{
		Name:          "filename",
		Shorthand:     "f",
		Usage:         "Filename or URL to the pipeline file",
		Value:         &opts.ConfigurationFile,
		DefValue:      "skaffold.yaml",
		FlagAddMethod: "StringVar",
		DefinedOn:     []string{"all"},
	},
	{
		Name:          "profile",
		Shorthand:     "p",
		Usage:         "Activate profiles by name",
		Value:         &opts.Profiles,
		DefValue:      []string{},
		FlagAddMethod: "StringSliceVar",
		DefinedOn:     []string{"all"},
	},
	{
		Name:          "namespace",
		Shorthand:     "n",
		Usage:         "Run deployments in the specified namespace",
		Value:         &opts.Namespace,
		DefValue:      "",
		FlagAddMethod: "StringVar",
		DefinedOn:     []string{"all"},
	},
	{
		Name:          "default-repo",
		Shorthand:     "d",
		Usage:         "Default repository value (overrides global config)",
		Value:         &opts.DefaultRepo,
		DefValue:      "",
		FlagAddMethod: "StringVar",
		DefinedOn:     []string{"all"},
	},
	{
		Name:          "cache-artifacts",
		Usage:         "Set to false to disable default caching of artifacts",
		Value:         &opts.CacheArtifacts,
		DefValue:      true,
		FlagAddMethod: "BoolVar",
		DefinedOn:     []string{"dev", "build", "run", "debug"},
	},
	{
		Name:          "cache-file",
		Usage:         "Specify the location of the cache file (default $HOME/.skaffold/cache)",
		Value:         &opts.CacheFile,
		DefValue:      "",
		FlagAddMethod: "StringVar",
		DefinedOn:     []string{"dev", "build", "run", "debug"},
	},
	{
		Name:          "insecure-registry",
		Usage:         "Target registries for built images which are not secure",
		Value:         &opts.InsecureRegistries,
		DefValue:      []string{},
		FlagAddMethod: "StringSliceVar",
		DefinedOn:     []string{"dev", "build", "run", "debug"},
	},
	{
		Name:          "enable-rpc",
		Usage:         "Enable gRPC for exposing Skaffold events (true by default for `skaffold dev`)",
		Value:         &opts.EnableRPC,
		DefValue:      false,
		FlagAddMethod: "BoolVar",
		DefinedOn:     []string{"dev", "build", "run", "debug", "deploy"},
	},
	{
		Name:          "rpc-port",
		Usage:         "tcp port to expose event API",
		Value:         &opts.RPCPort,
		DefValue:      constants.DefaultRPCPort,
		FlagAddMethod: "IntVar",
		DefinedOn:     []string{"dev", "build", "run", "debug", "deploy"},
	},
	{
		Name:          "rpc-http-port",
		Usage:         "tcp port to expose event REST API over HTTP",
		Value:         &opts.RPCHTTPPort,
		DefValue:      constants.DefaultRPCHTTPPort,
		FlagAddMethod: "IntVar",
		DefinedOn:     []string{"dev", "build", "run", "debug", "deploy"},
	},
	{
		Name:          "label",
		Shorthand:     "l",
		Usage:         "Add custom labels to deployed objects. Set multiple times for multiple labels",
		Value:         &opts.CustomLabels,
		DefValue:      []string{},
		FlagAddMethod: "StringSliceVar",
		DefinedOn:     []string{"dev", "run", "debug", "deploy"},
	},
	{
		Name:          "toot",
		Usage:         "Emit a terminal beep after the deploy is complete",
		Value:         &opts.Notification,
		DefValue:      false,
		FlagAddMethod: "BoolVar",
		DefinedOn:     []string{"dev", "build", "run", "debug", "deploy"},
	},
	// We need opts.Tail and opts.TailDev since cobra, overwrites the default value
	// when registering the flag twice.
	{
		Name:          "tail",
		Usage:         "Stream logs from deployed objects (default false)",
		Value:         &opts.Tail,
		DefValue:      false,
		FlagAddMethod: "BoolVar",
		DefinedOn:     []string{"deploy", "run"},
	},
	{
		Name:          "tail",
		Usage:         "Stream logs from deployed objects",
		Value:         &opts.TailDev,
		DefValue:      true,
		FlagAddMethod: "BoolVar",
		DefinedOn:     []string{"dev", "debug"},
	},
	{
		Name:          "force",
		Usage:         "Recreate Kubernetes resources if necessary for deployment, warning: might cause downtime! (true by default for `skaffold dev`)",
		Value:         &opts.Force,
		DefValue:      false,
		FlagAddMethod: "BoolVar",
		DefinedOn:     []string{"deploy", "dev", "run", "debug"},
	},
	{
		Name:          "skip-tests",
		Usage:         "Whether to skip the tests after building",
		Value:         &opts.SkipTests,
		DefValue:      false,
		FlagAddMethod: "BoolVar",
		DefinedOn:     []string{"dev", "run", "debug", "build"},
	},
	{
		Name:          "cleanup",
		Usage:         "Delete deployments after dev or debug mode is interrupted",
		Value:         &opts.Cleanup,
		DefValue:      true,
		FlagAddMethod: "BoolVar",
		DefinedOn:     []string{"dev", "run", "debug"},
	},
	{
		Name:          "no-prune",
		Usage:         "Skip removing images and containers built by Skaffold",
		Value:         &opts.NoPrune,
		DefValue:      false,
		FlagAddMethod: "BoolVar",
		DefinedOn:     []string{"dev", "run", "debug"},
	},
	{
		Name:          "no-prune-children",
		Usage:         "Skip removing layers reused by Skaffold",
		Value:         &opts.NoPruneChildren,
		DefValue:      false,
		FlagAddMethod: "BoolVar",
		DefinedOn:     []string{"dev", "run", "debug"},
	},
	{
		Name:          "port-forward",
		Usage:         "Port-forward exposed container ports within pods",
		Value:         &opts.PortForward.Enabled,
		DefValue:      false,
		FlagAddMethod: "BoolVar",
		DefinedOn:     []string{"dev", "debug"},
	},
	{
		Name:          "status-check",
		Usage:         "Wait for deployed resources to stabilize",
		Value:         &opts.StatusCheck,
		DefValue:      false,
		FlagAddMethod: "BoolVar",
		DefinedOn:     []string{"dev", "debug", "deploy", "run"},
	},
	{
		Name:          "render-only",
		Usage:         "Print rendered Kubernetes manifests instead of deploying them",
		Value:         &opts.RenderOnly,
		DefValue:      false,
		FlagAddMethod: "BoolVar",
		DefinedOn:     []string{"dev", "run"},
	},
	{
		Name:          "config",
		Shorthand:     "c",
		Usage:         "File for global configurations (defaults to $HOME/.skaffold/config)",
		Value:         &opts.GlobalConfig,
		DefValue:      "",
		FlagAddMethod: "StringVar",
		DefinedOn:     []string{"run", "dev", "debug", "build", "deploy", "delete", "diagnose"},
	},
	{
		Name:          "kube-context",
		Usage:         "Deploy to this Kubernetes context",
		Value:         &opts.KubeContext,
		DefValue:      "",
		FlagAddMethod: "StringVar",
		DefinedOn:     []string{"build", "debug", "delete", "deploy", "dev", "run"},
	},
	{
		Name:          "kubeconfig",
		Usage:         "Path to the kubeconfig file to use for CLI requests.",
		Value:         &opts.KubeConfig,
		DefValue:      "",
		FlagAddMethod: "StringVar",
		DefinedOn:     []string{"build", "debug", "delete", "deploy", "dev", "run"},
	},
	{
		Name:          "tag",
		Shorthand:     "t",
		Usage:         "The optional custom tag to use for images which overrides the current Tagger configuration",
		Value:         &opts.CustomTag,
		DefValue:      "",
		FlagAddMethod: "StringVar",
		DefinedOn:     []string{"build", "deploy", "dev", "run"},
	},
}

var commandFlags []*pflag.Flag

// SetupFlags creates pflag.Flag for all registered flags
func SetupFlags() {
	commandFlags = make([]*pflag.Flag, len(FlagRegistry))
	for i, fl := range FlagRegistry {
		fs := pflag.NewFlagSet(fl.Name, pflag.ContinueOnError)
		inputs := []reflect.Value{
			reflect.ValueOf(fl.Value),
			reflect.ValueOf(fl.Name),
			reflect.ValueOf(fl.DefValue),
			reflect.ValueOf(fl.Usage),
		}
		reflect.ValueOf(fs).MethodByName(fl.FlagAddMethod).Call(inputs)
		f := fs.Lookup(fl.Name)
		if fl.Shorthand != "" {
			f.Shorthand = fl.Shorthand
		}
		f.Annotations = map[string][]string{
			"cmds": fl.DefinedOn,
		}
		commandFlags[i] = f
	}
}

func AddFlags(fs *pflag.FlagSet, cmdName string) {
	for _, f := range commandFlags {
		if hasCmdAnnotation(cmdName, f.Annotations["cmds"]) {
			fs.AddFlag(f)
		}
	}
	fs.MarkHidden("status-check")
}

func hasCmdAnnotation(cmdName string, annotations []string) bool {
	for _, a := range annotations {
		if cmdName == a || a == "all" {
			return true
		}
	}
	return false
}

func init() {
	SetupFlags()
}
<commit_msg>modify deploy to debug<commit_after>/*
Copyright 2019 The Skaffold 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 cmd

import (
	"reflect"

	"github.com/spf13/pflag"

	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/constants"
)

// Flag defines a Skaffold CLI flag which contains a list of
// subcommands the flag belongs to in `DefinedOn` field.
type Flag struct {
	Name          string
	Shorthand     string
	Usage         string
	Value         interface{}
	DefValue      interface{}
	FlagAddMethod string
	DefinedOn     []string
}

// FlagRegistry is a list of all Skaffold CLI flags.
// When adding a new flag to the registry, please specify the
// command/commands to which the flag belongs in `DefinedOn` field.
// If the flag is a global flag, or belongs to all the subcommands,
/// specify "all"
// FlagAddMethod is method which defines a flag value with specified
// name, default value, and usage string. e.g. `StringVar`, `BoolVar`
var FlagRegistry = []Flag{
	{
		Name:          "filename",
		Shorthand:     "f",
		Usage:         "Filename or URL to the pipeline file",
		Value:         &opts.ConfigurationFile,
		DefValue:      "skaffold.yaml",
		FlagAddMethod: "StringVar",
		DefinedOn:     []string{"all"},
	},
	{
		Name:          "profile",
		Shorthand:     "p",
		Usage:         "Activate profiles by name",
		Value:         &opts.Profiles,
		DefValue:      []string{},
		FlagAddMethod: "StringSliceVar",
		DefinedOn:     []string{"all"},
	},
	{
		Name:          "namespace",
		Shorthand:     "n",
		Usage:         "Run deployments in the specified namespace",
		Value:         &opts.Namespace,
		DefValue:      "",
		FlagAddMethod: "StringVar",
		DefinedOn:     []string{"all"},
	},
	{
		Name:          "default-repo",
		Shorthand:     "d",
		Usage:         "Default repository value (overrides global config)",
		Value:         &opts.DefaultRepo,
		DefValue:      "",
		FlagAddMethod: "StringVar",
		DefinedOn:     []string{"all"},
	},
	{
		Name:          "cache-artifacts",
		Usage:         "Set to false to disable default caching of artifacts",
		Value:         &opts.CacheArtifacts,
		DefValue:      true,
		FlagAddMethod: "BoolVar",
		DefinedOn:     []string{"dev", "build", "run", "debug"},
	},
	{
		Name:          "cache-file",
		Usage:         "Specify the location of the cache file (default $HOME/.skaffold/cache)",
		Value:         &opts.CacheFile,
		DefValue:      "",
		FlagAddMethod: "StringVar",
		DefinedOn:     []string{"dev", "build", "run", "debug"},
	},
	{
		Name:          "insecure-registry",
		Usage:         "Target registries for built images which are not secure",
		Value:         &opts.InsecureRegistries,
		DefValue:      []string{},
		FlagAddMethod: "StringSliceVar",
		DefinedOn:     []string{"dev", "build", "run", "debug"},
	},
	{
		Name:          "enable-rpc",
		Usage:         "Enable gRPC for exposing Skaffold events (true by default for `skaffold dev`)",
		Value:         &opts.EnableRPC,
		DefValue:      false,
		FlagAddMethod: "BoolVar",
		DefinedOn:     []string{"dev", "build", "run", "debug", "deploy"},
	},
	{
		Name:          "rpc-port",
		Usage:         "tcp port to expose event API",
		Value:         &opts.RPCPort,
		DefValue:      constants.DefaultRPCPort,
		FlagAddMethod: "IntVar",
		DefinedOn:     []string{"dev", "build", "run", "debug", "deploy"},
	},
	{
		Name:          "rpc-http-port",
		Usage:         "tcp port to expose event REST API over HTTP",
		Value:         &opts.RPCHTTPPort,
		DefValue:      constants.DefaultRPCHTTPPort,
		FlagAddMethod: "IntVar",
		DefinedOn:     []string{"dev", "build", "run", "debug", "deploy"},
	},
	{
		Name:          "label",
		Shorthand:     "l",
		Usage:         "Add custom labels to deployed objects. Set multiple times for multiple labels",
		Value:         &opts.CustomLabels,
		DefValue:      []string{},
		FlagAddMethod: "StringSliceVar",
		DefinedOn:     []string{"dev", "run", "debug", "deploy"},
	},
	{
		Name:          "toot",
		Usage:         "Emit a terminal beep after the deploy is complete",
		Value:         &opts.Notification,
		DefValue:      false,
		FlagAddMethod: "BoolVar",
		DefinedOn:     []string{"dev", "build", "run", "debug", "deploy"},
	},
	// We need opts.Tail and opts.TailDev since cobra, overwrites the default value
	// when registering the flag twice.
	{
		Name:          "tail",
		Usage:         "Stream logs from deployed objects (default false)",
		Value:         &opts.Tail,
		DefValue:      false,
		FlagAddMethod: "BoolVar",
		DefinedOn:     []string{"deploy", "run"},
	},
	{
		Name:          "tail",
		Usage:         "Stream logs from deployed objects",
		Value:         &opts.TailDev,
		DefValue:      true,
		FlagAddMethod: "BoolVar",
		DefinedOn:     []string{"dev", "debug"},
	},
	{
		Name:          "force",
		Usage:         "Recreate Kubernetes resources if necessary for deployment, warning: might cause downtime! (true by default for `skaffold dev`)",
		Value:         &opts.Force,
		DefValue:      false,
		FlagAddMethod: "BoolVar",
		DefinedOn:     []string{"deploy", "dev", "run", "debug"},
	},
	{
		Name:          "skip-tests",
		Usage:         "Whether to skip the tests after building",
		Value:         &opts.SkipTests,
		DefValue:      false,
		FlagAddMethod: "BoolVar",
		DefinedOn:     []string{"dev", "run", "debug", "build"},
	},
	{
		Name:          "cleanup",
		Usage:         "Delete deployments after dev or debug mode is interrupted",
		Value:         &opts.Cleanup,
		DefValue:      true,
		FlagAddMethod: "BoolVar",
		DefinedOn:     []string{"dev", "run", "debug"},
	},
	{
		Name:          "no-prune",
		Usage:         "Skip removing images and containers built by Skaffold",
		Value:         &opts.NoPrune,
		DefValue:      false,
		FlagAddMethod: "BoolVar",
		DefinedOn:     []string{"dev", "run", "debug"},
	},
	{
		Name:          "no-prune-children",
		Usage:         "Skip removing layers reused by Skaffold",
		Value:         &opts.NoPruneChildren,
		DefValue:      false,
		FlagAddMethod: "BoolVar",
		DefinedOn:     []string{"dev", "run", "debug"},
	},
	{
		Name:          "port-forward",
		Usage:         "Port-forward exposed container ports within pods",
		Value:         &opts.PortForward.Enabled,
		DefValue:      false,
		FlagAddMethod: "BoolVar",
		DefinedOn:     []string{"dev", "debug"},
	},
	{
		Name:          "status-check",
		Usage:         "Wait for deployed resources to stabilize",
		Value:         &opts.StatusCheck,
		DefValue:      false,
		FlagAddMethod: "BoolVar",
		DefinedOn:     []string{"dev", "debug", "deploy", "run"},
	},
	{
		Name:          "render-only",
		Usage:         "Print rendered Kubernetes manifests instead of deploying them",
		Value:         &opts.RenderOnly,
		DefValue:      false,
		FlagAddMethod: "BoolVar",
		DefinedOn:     []string{"dev", "run"},
	},
	{
		Name:          "config",
		Shorthand:     "c",
		Usage:         "File for global configurations (defaults to $HOME/.skaffold/config)",
		Value:         &opts.GlobalConfig,
		DefValue:      "",
		FlagAddMethod: "StringVar",
		DefinedOn:     []string{"run", "dev", "debug", "build", "deploy", "delete", "diagnose"},
	},
	{
		Name:          "kube-context",
		Usage:         "Deploy to this Kubernetes context",
		Value:         &opts.KubeContext,
		DefValue:      "",
		FlagAddMethod: "StringVar",
		DefinedOn:     []string{"build", "debug", "delete", "deploy", "dev", "run"},
	},
	{
		Name:          "kubeconfig",
		Usage:         "Path to the kubeconfig file to use for CLI requests.",
		Value:         &opts.KubeConfig,
		DefValue:      "",
		FlagAddMethod: "StringVar",
		DefinedOn:     []string{"build", "debug", "delete", "deploy", "dev", "run"},
	},
	{
		Name:          "tag",
		Shorthand:     "t",
		Usage:         "The optional custom tag to use for images which overrides the current Tagger configuration",
		Value:         &opts.CustomTag,
		DefValue:      "",
		FlagAddMethod: "StringVar",
		DefinedOn:     []string{"build", "debug", "dev", "run"},
	},
}

var commandFlags []*pflag.Flag

// SetupFlags creates pflag.Flag for all registered flags
func SetupFlags() {
	commandFlags = make([]*pflag.Flag, len(FlagRegistry))
	for i, fl := range FlagRegistry {
		fs := pflag.NewFlagSet(fl.Name, pflag.ContinueOnError)
		inputs := []reflect.Value{
			reflect.ValueOf(fl.Value),
			reflect.ValueOf(fl.Name),
			reflect.ValueOf(fl.DefValue),
			reflect.ValueOf(fl.Usage),
		}
		reflect.ValueOf(fs).MethodByName(fl.FlagAddMethod).Call(inputs)
		f := fs.Lookup(fl.Name)
		if fl.Shorthand != "" {
			f.Shorthand = fl.Shorthand
		}
		f.Annotations = map[string][]string{
			"cmds": fl.DefinedOn,
		}
		commandFlags[i] = f
	}
}

func AddFlags(fs *pflag.FlagSet, cmdName string) {
	for _, f := range commandFlags {
		if hasCmdAnnotation(cmdName, f.Annotations["cmds"]) {
			fs.AddFlag(f)
		}
	}
	fs.MarkHidden("status-check")
}

func hasCmdAnnotation(cmdName string, annotations []string) bool {
	for _, a := range annotations {
		if cmdName == a || a == "all" {
			return true
		}
	}
	return false
}

func init() {
	SetupFlags()
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	tc "github.com/thijzert/go-termcolours"
	"github.com/thijzert/speeldoos"
	"github.com/thijzert/speeldoos/lib/zipmap"
	"io"
	"log"
	"os"
	"os/exec"
	"path"
	"strconv"
	"strings"
	"sync"
	"time"
)

type condenseJob struct {
	Carrier   *speeldoos.Carrier
	OutputDir string
}

func condense_main(args []string) {
	d, err := os.Open(Config.LibraryDir)
	croak(err)

	files, err := d.Readdir(0)
	croak(err)

	croak(os.MkdirAll(Config.Condense.OutputDir, 0755))

	jobs := make(chan condenseJob)
	wg := &sync.WaitGroup{}

	for i := 0; i < Config.ConcurrentJobs; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()

		NextJob:
			for job := range jobs {

				zm := zipmap.New()
				defer zm.Close()

				shout := func(e error) bool {
					if e != nil {
						log.Printf("%s: %s", tc.Red(job.Carrier.ID), e)
						return true
					}
					return false
				}

				done := false
				for _, pf := range job.Carrier.Performances {
					for _, sf := range pf.SourceFiles {
						dn := path.Join(Config.LibraryDir, path.Dir(sf.Filename), "folder.jpg")
						if zm.Exists(dn) {
							if !shout(zm.CopyTo(dn, path.Join(job.OutputDir, "folder.jpg"))) {
								done = true
								break
							}
						}
					}
					if done {
						break
					}
				}

				for _, pf := range job.Carrier.Performances {
					title := "(no title)"
					if len(pf.Work.Title) > 0 {
						title = pf.Work.Title[0].Title
					}

					log.Printf("%s: now processing: %s - %s", tc.Green(job.Carrier.ID), pf.Work.Composer.Name, title)

					if len(pf.SourceFiles) == 0 {
						log.Printf("%s - %s has no source files!\n", pf.Work.Composer.Name, title)
					}
					outp := fmt.Sprintf("%s - %s.mp3", pf.Work.Composer.Name, title)
					outp = path.Join(job.OutputDir, outp)

					inp := ""
					for i, _ := range pf.SourceFiles {
						inp = fmt.Sprintf("%s|/proc/self/fd/%d", inp, i+3)
					}
					inp = fmt.Sprintf("concat:%s", inp[1:])

					cmd := exec.Command("ffmpeg", "-v", "8", "-y", "-i", inp, "-c:a", "libmp3lame", "-q:a", strconv.Itoa(Config.Condense.Quality), outp)
					cmd.Stdout = os.Stdout
					cmd.Stderr = os.Stderr
					cmd.ExtraFiles = make([]*os.File, len(pf.SourceFiles))

					pipes := make([]*os.File, len(pf.SourceFiles))
					for i, _ := range pf.SourceFiles {
						cmd.ExtraFiles[i], pipes[i], err = os.Pipe()
						if shout(err) {
							continue NextJob
						}
					}

					cmd.Start()

					for i, fn := range pf.SourceFiles {
						f, err := zm.Get(path.Join(Config.LibraryDir, fn.Filename))
						if shout(err) {
							continue NextJob
						}

						_, err = io.Copy(pipes[i], f)
						if shout(err) {
							continue NextJob
						}
						f.Close()
						pipes[i].Close()
					}

					if shout(cmd.Wait()) {
						continue NextJob
					}

					tags := &mFile{
						Artist:     pf.Work.Composer.Name, // MP3 players are dumb
						Soloist:    pf.Work.Composer.Name, // very dumb
						Album:      job.Carrier.Name,
						Composer:   pf.Work.Composer.Name,
						Performers: make([]string, 0, 2),
						Year:       pf.Work.Year, // Furthermore, the `id3v2` program is also extremely dumb, as it seems to ignore pre-1900 dates
					}
					for _, tit := range pf.Work.Title {
						tags.Title = tit.Title
						break
					}
					for _, p := range pf.Performers {
						tags.Performers = append(tags.Performers, p.Name)

						if p.Role == "soloist" || p.Role == "performer" || p.Role == "" || p.Role == "orchestra" || p.Role == "ensemble" {
							if tags.Orchestra == "" {
								tags.Orchestra = p.Name
							} else {
								tags.Orchestra = tags.Orchestra + "/" + p.Name
							}
						} else if p.Role == "conductor" {
							if tags.Conductor == "" {
								tags.Conductor = p.Name
							} else {
								tags.Conductor = tags.Conductor + "/" + p.Name
							}
						}
					}

					cmd = id3tags(tags, outp)
					if shout(cmd.Run()) {
						continue NextJob
					}
				}

				if shout(os.Chtimes(job.OutputDir, time.Now(), time.Now())) {
					continue NextJob
				}
			}
		}()
	}

	for _, file := range files {
		if file.IsDir() {
			continue
		}
		xml := path.Join(Config.LibraryDir, file.Name())
		if len(xml) < 5 || xml[len(xml)-4:] != ".xml" {
			continue
		}

		foo, err := speeldoos.ImportCarrier(xml)
		if err != nil {
			log.Print(err)
			continue
		}

		if foo.ID == "" {
			log.Printf("Carrier in file '%s' has an empty ID. Skipping.", file.Name())
			continue
		}

		outdir := foo.ID
		outdir = strings.Replace(outdir, "/", "-", -1)
		outdir = strings.Replace(outdir, "\n", " ", -1)
		outdir = path.Join(Config.Condense.OutputDir, outdir)
		iout, err := os.Stat(outdir)
		if err == nil {
			if iout.ModTime().Before(file.ModTime()) {
				log.Printf("removing %s", outdir)
				os.RemoveAll(outdir)
			} else {
				log.Printf("skipping '%s' - up to date", foo.ID)
				continue
			}
		}
		croak(os.Mkdir(outdir, 0755))
		tim := file.ModTime().Add(-24 * time.Hour)
		croak(os.Chtimes(outdir, tim, tim))

		jobs <- condenseJob{foo, outdir}
	}

	close(jobs)

	wg.Wait()
}
<commit_msg>Make 'sd condense' use the new hivemind worker pool<commit_after>package main

import (
	"fmt"
	tc "github.com/thijzert/go-termcolours"
	"github.com/thijzert/speeldoos"
	"github.com/thijzert/speeldoos/lib/hivemind"
	"github.com/thijzert/speeldoos/lib/zipmap"
	"io"
	"log"
	"os"
	"os/exec"
	"path"
	"strconv"
	"strings"
	"time"
)

type condenseJob struct {
	Carrier   *speeldoos.Carrier
	OutputDir string
}

func (job condenseJob) Run(h hivemind.JC) error {
	zm := zipmap.New()
	defer zm.Close()

	h.SetTitle(job.Carrier.ID)
	var err error

	done := false
	for _, pf := range job.Carrier.Performances {
		for _, sf := range pf.SourceFiles {
			dn := path.Join(Config.LibraryDir, path.Dir(sf.Filename), "folder.jpg")
			if zm.Exists(dn) {
				if err = zm.CopyTo(dn, path.Join(job.OutputDir, "folder.jpg")); err != nil {
					done = true
					break
				}
			}
		}
		if done {
			break
		}
	}

	for _, pf := range job.Carrier.Performances {
		title := "(no title)"
		if len(pf.Work.Title) > 0 {
			title = pf.Work.Title[0].Title
		}

		h.Printf("%s: now processing: %s - %s", tc.Green(job.Carrier.ID), pf.Work.Composer.Name, title)

		if len(pf.SourceFiles) == 0 {
			h.Printf("%s - %s has no source files!\n", pf.Work.Composer.Name, title)
		}
		outp := fmt.Sprintf("%s - %s.mp3", pf.Work.Composer.Name, title)
		outp = path.Join(job.OutputDir, outp)

		inp := ""
		for i, _ := range pf.SourceFiles {
			inp = fmt.Sprintf("%s|/proc/self/fd/%d", inp, i+3)
		}
		inp = fmt.Sprintf("concat:%s", inp[1:])

		cmd := exec.Command("ffmpeg", "-v", "8", "-y", "-i", inp, "-c:a", "libmp3lame", "-q:a", strconv.Itoa(Config.Condense.Quality), outp)
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr
		cmd.ExtraFiles = make([]*os.File, len(pf.SourceFiles))

		pipes := make([]*os.File, len(pf.SourceFiles))
		for i, _ := range pf.SourceFiles {
			cmd.ExtraFiles[i], pipes[i], err = os.Pipe()
			if err != nil {
				return err
			}
		}

		cmd.Start()

		for i, fn := range pf.SourceFiles {
			f, err := zm.Get(path.Join(Config.LibraryDir, fn.Filename))
			if err != nil {
				return err
			}

			_, err = io.Copy(pipes[i], f)
			if err != nil {
				return err
			}
			f.Close()
			pipes[i].Close()
		}

		if err := cmd.Wait(); err != nil {
			return err
		}

		tags := &mFile{
			Artist:     pf.Work.Composer.Name, // MP3 players are dumb
			Soloist:    pf.Work.Composer.Name, // very dumb
			Album:      job.Carrier.Name,
			Composer:   pf.Work.Composer.Name,
			Performers: make([]string, 0, 2),
			Year:       pf.Work.Year, // Furthermore, the `id3v2` program is also extremely dumb, as it seems to ignore pre-1900 dates
		}
		for _, tit := range pf.Work.Title {
			tags.Title = tit.Title
			break
		}
		for _, p := range pf.Performers {
			tags.Performers = append(tags.Performers, p.Name)

			if p.Role == "soloist" || p.Role == "performer" || p.Role == "" || p.Role == "orchestra" || p.Role == "ensemble" {
				if tags.Orchestra == "" {
					tags.Orchestra = p.Name
				} else {
					tags.Orchestra = tags.Orchestra + "/" + p.Name
				}
			} else if p.Role == "conductor" {
				if tags.Conductor == "" {
					tags.Conductor = p.Name
				} else {
					tags.Conductor = tags.Conductor + "/" + p.Name
				}
			}
		}

		cmd = id3tags(tags, outp)
		if err := cmd.Run(); err != nil {
			return err
		}
	}

	if err := os.Chtimes(job.OutputDir, time.Now(), time.Now()); err != nil {
		return err
	}
	return nil
}

func condense_main(args []string) {
	d, err := os.Open(Config.LibraryDir)
	croak(err)

	files, err := d.Readdir(0)
	croak(err)

	croak(os.MkdirAll(Config.Condense.OutputDir, 0755))

	hive := hivemind.New(Config.ConcurrentJobs)

	for _, file := range files {
		if file.IsDir() {
			continue
		}
		xml := path.Join(Config.LibraryDir, file.Name())
		if len(xml) < 5 || xml[len(xml)-4:] != ".xml" {
			continue
		}

		foo, err := speeldoos.ImportCarrier(xml)
		if err != nil {
			log.Print(err)
			continue
		}

		if foo.ID == "" {
			log.Printf("Carrier in file '%s' has an empty ID. Skipping.", file.Name())
			continue
		}

		outdir := foo.ID
		outdir = strings.Replace(outdir, "/", "-", -1)
		outdir = strings.Replace(outdir, "\n", " ", -1)
		outdir = path.Join(Config.Condense.OutputDir, outdir)
		iout, err := os.Stat(outdir)
		if err == nil {
			if iout.ModTime().Before(file.ModTime()) {
				log.Printf("removing %s", outdir)
				os.RemoveAll(outdir)
			} else {
				log.Printf("skipping '%s' - up to date", foo.ID)
				continue
			}
		}
		croak(os.Mkdir(outdir, 0755))
		tim := file.ModTime().Add(-24 * time.Hour)
		croak(os.Chtimes(outdir, tim, tim))

		hive.AddJob(condenseJob{foo, outdir})
	}

	hive.Wait()
}
<|endoftext|>


<commit_before>// Copyright (C) 2015 Thomas de Zeeuw.
//
// Licensed under the MIT license that can be found in the LICENSE file.

package logger

import (
	"errors"
	"fmt"
	"math"
	"testing"
	"time"
)

type stringer struct{}

func (s *stringer) String() string {
	return "data"
}

func TestEvent(t *testing.T) {
	defer resetEventTypes()

	now := time.Now()
	tStr := now.UTC().Format(TimeFormat)
	tStrNano := now.UTC().Format(time.RFC3339Nano)

	var msgTests = []struct {
		event        Event
		expected     string
		expectedJSON string
	}{
		{Event{DebugEvent, now, Tags{"tag1", "tag2", "tag3"}, "Message6", 0},
			tStr + " [Debug] tag1, tag2, tag3: Message6, 0",
			`{"type": "Debug", "timestamp": "` + tStrNano + `", "tags": ["tag1", "tag2", "tag3"], ` +
				`"message": "Message6", "data": "0"}`},
		{Event{InfoEvent, now, Tags{"tag1", "tag2"}, "Message4", []byte("data")},
			tStr + " [Info] tag1, tag2: Message4, data",
			`{"type": "Info", "timestamp": "` + tStrNano + `", "tags": ["tag1", "tag2"], ` +
				`"message": "Message4", "data": "data"}`},
		{Event{WarnEvent, now, Tags{"tag1"}, "Message3", &stringer{}},
			tStr + " [Warn] tag1: Message3, data",
			`{"type": "Warn", "timestamp": "` + tStrNano + `", "tags": ["tag1"], ` +
				`"message": "Message3", "data": "data"}`},
		{Event{ErrorEvent, now, Tags{"tag1"}, "Message2", "data"},
			tStr + " [Error] tag1: Message2, data",
			`{"type": "Error", "timestamp": "` + tStrNano + `", "tags": ["tag1"], ` +
				`"message": "Message2", "data": "data"}`},
		{Event{FatalEvent, now, Tags{}, "Message1", nil},
			tStr + " [Fatal] : Message1",
			`{"type": "Fatal", "timestamp": "` + tStrNano + `", "tags": [], ` +
				`"message": "Message1"}`},
		{Event{ThumbEvent, now, Tags{"tag1", "tag2", "tag3"}, "Message5", errors.New("error data")},
			tStr + " [Thumb] tag1, tag2, tag3: Message5, error data",
			`{"type": "Thumb", "timestamp": "` + tStrNano + `", "tags": ["tag1", "tag2", "tag3"], ` +
				`"message": "Message5", "data": "error data"}`},
		{Event{NewEventType("My-event-type"), now, Tags{"tag1"}, "Message7", nil},
			tStr + " [My-event-type] tag1: Message7",
			`{"type": "My-event-type", "timestamp": "` + tStrNano + `", "tags": ["tag1"], ` +
				`"message": "Message7"}`},
		{Event{NewEventType(`my-"event"-type`), now, Tags{`tag"1"`}, "Message7", `"`},
			tStr + " [my-\"event\"-type] tag\"1\": Message7, \"",
			`{"type": "my-\"event\"-type", "timestamp": "` + tStrNano + `", "tags": ["tag\"1\""], ` +
				`"message": "Message7", "data": "\""}`},
	}

	for _, test := range msgTests {
		got, gotBytes := test.event.String(), string(test.event.Bytes())
		if gotBytes != test.expected {
			t.Errorf("Expected Event(%v).Bytes() to return %q, but got %q",
				test.event, test.expected, gotBytes)
		} else if got != test.expected {
			t.Errorf("Expected Event(%v).String() to return %q, but got %q",
				test.event, test.expected, got)
		}

		if json, err := test.event.MarshalJSON(); err != nil {
			t.Errorf("Unexpected error marshaling %v into json: %s", test.event, err.Error())
		} else if got := string(json); got != test.expectedJSON {
			t.Errorf("Expected Event(%v).MarshalJSON() to return %q, but got %q",
				test.event, test.expectedJSON, got)
		}
	}
}

func TestEventType(t *testing.T) {
	defer resetEventTypes()

	tests := []struct {
		eventType    EventType
		expected     string
		expectedJSON string
	}{
		{DebugEvent, "Debug", `"Debug"`},
		{ThumbEvent, "Thumb", `"Thumb"`},
		{InfoEvent, "Info", `"Info"`},
		{WarnEvent, "Warn", `"Warn"`},
		{ErrorEvent, "Error", `"Error"`},
		{FatalEvent, "Fatal", `"Fatal"`},
		{EventType(255), "EventType(255)", `"EventType(255)"`},
		{NewEventType("my-event-type"), "my-event-type", `"my-event-type"`},
		{NewEventType("my-\"event\"-type"), "my-\"event\"-type", `"my-\"event\"-type"`},
	}

	for _, test := range tests {
		got, gotBytes := test.eventType.String(), string(test.eventType.Bytes())
		if gotBytes != test.expected {
			t.Errorf("Expected EventType(%v).Bytes() to return %q, but got %q",
				test.eventType, test.expected, gotBytes)
		} else if got != test.expected {
			t.Errorf("Expected EventType(%v).String() to return %q, but got %q",
				test.eventType, test.expected, got)
		}

		if json, err := test.eventType.MarshalJSON(); err != nil {
			t.Errorf("Unexpected error marshaling %v into json: %s", test.eventType, err.Error())
		} else if got := string(json); got != test.expectedJSON {
			t.Errorf("Expected EventType(%v).MarshalJSON() to return %q, but got %q",
				test.eventType, test.expectedJSON, got)
		}
	}
}

const maxCostumEventTypes = math.MaxUint16 - 7 // minus builtin event types.

var (
	oldEventTypeNames   = eventTypeNames
	oldEventTypeIndices = eventTypeIndices
)

func resetEventTypes() {
	eventTypeNames = oldEventTypeNames
	eventTypeIndices = oldEventTypeIndices
}

func TestNewLogLevelLimit(t *testing.T) {
	if testing.Short() {
		t.Skip("Skipping TestNewLogLevelLimit in short mode")
	}
	defer resetEventTypes()

	for i := 1; i <= maxCostumEventTypes; i++ {
		expected := fmt.Sprintf("EventType-%d", i)
		eventType := NewEventType(expected)
		if got := eventType.String(); got != expected {
			t.Fatalf("Expected NewEventType(%q).String() to return %q, but got %q",
				expected, expected, got)
		}
	}

	defer func() {
		recv := recover()
		if recv == nil {
			t.Fatal("Expected a panic after creating 65528 log levels, but didn't get one")
		}

		got, ok := recv.(string)
		if !ok {
			t.Fatalf("Expected the recoverd panic to be a string, but it's %v", recv)
		}

		expected := "logger: can't have more then 65535 EventTypes"
		if got != expected {
			t.Fatalf("Expected the recoverd panic to be %s, but got %s", expected, got)
		}
	}()

	NewEventType(fmt.Sprintf("EventType-%d", maxCostumEventTypes+1))
}
<commit_msg>Fix TestNewLogLevelLimit<commit_after>// Copyright (C) 2015 Thomas de Zeeuw.
//
// Licensed under the MIT license that can be found in the LICENSE file.

package logger

import (
	"errors"
	"fmt"
	"math"
	"testing"
	"time"
)

type stringer struct{}

func (s *stringer) String() string {
	return "data"
}

func TestEvent(t *testing.T) {
	defer resetEventTypes()

	now := time.Now()
	tStr := now.UTC().Format(TimeFormat)
	tStrNano := now.UTC().Format(time.RFC3339Nano)

	var msgTests = []struct {
		event        Event
		expected     string
		expectedJSON string
	}{
		{Event{DebugEvent, now, Tags{"tag1", "tag2", "tag3"}, "Message6", 0},
			tStr + " [Debug] tag1, tag2, tag3: Message6, 0",
			`{"type": "Debug", "timestamp": "` + tStrNano + `", "tags": ["tag1", "tag2", "tag3"], ` +
				`"message": "Message6", "data": "0"}`},
		{Event{InfoEvent, now, Tags{"tag1", "tag2"}, "Message4", []byte("data")},
			tStr + " [Info] tag1, tag2: Message4, data",
			`{"type": "Info", "timestamp": "` + tStrNano + `", "tags": ["tag1", "tag2"], ` +
				`"message": "Message4", "data": "data"}`},
		{Event{WarnEvent, now, Tags{"tag1"}, "Message3", &stringer{}},
			tStr + " [Warn] tag1: Message3, data",
			`{"type": "Warn", "timestamp": "` + tStrNano + `", "tags": ["tag1"], ` +
				`"message": "Message3", "data": "data"}`},
		{Event{ErrorEvent, now, Tags{"tag1"}, "Message2", "data"},
			tStr + " [Error] tag1: Message2, data",
			`{"type": "Error", "timestamp": "` + tStrNano + `", "tags": ["tag1"], ` +
				`"message": "Message2", "data": "data"}`},
		{Event{FatalEvent, now, Tags{}, "Message1", nil},
			tStr + " [Fatal] : Message1",
			`{"type": "Fatal", "timestamp": "` + tStrNano + `", "tags": [], ` +
				`"message": "Message1"}`},
		{Event{ThumbEvent, now, Tags{"tag1", "tag2", "tag3"}, "Message5", errors.New("error data")},
			tStr + " [Thumb] tag1, tag2, tag3: Message5, error data",
			`{"type": "Thumb", "timestamp": "` + tStrNano + `", "tags": ["tag1", "tag2", "tag3"], ` +
				`"message": "Message5", "data": "error data"}`},
		{Event{NewEventType("My-event-type"), now, Tags{"tag1"}, "Message7", nil},
			tStr + " [My-event-type] tag1: Message7",
			`{"type": "My-event-type", "timestamp": "` + tStrNano + `", "tags": ["tag1"], ` +
				`"message": "Message7"}`},
		{Event{NewEventType(`my-"event"-type`), now, Tags{`tag"1"`}, "Message7", `"`},
			tStr + " [my-\"event\"-type] tag\"1\": Message7, \"",
			`{"type": "my-\"event\"-type", "timestamp": "` + tStrNano + `", "tags": ["tag\"1\""], ` +
				`"message": "Message7", "data": "\""}`},
	}

	for _, test := range msgTests {
		got, gotBytes := test.event.String(), string(test.event.Bytes())
		if gotBytes != test.expected {
			t.Errorf("Expected Event(%v).Bytes() to return %q, but got %q",
				test.event, test.expected, gotBytes)
		} else if got != test.expected {
			t.Errorf("Expected Event(%v).String() to return %q, but got %q",
				test.event, test.expected, got)
		}

		if json, err := test.event.MarshalJSON(); err != nil {
			t.Errorf("Unexpected error marshaling %v into json: %s", test.event, err.Error())
		} else if got := string(json); got != test.expectedJSON {
			t.Errorf("Expected Event(%v).MarshalJSON() to return %q, but got %q",
				test.event, test.expectedJSON, got)
		}
	}
}

func TestEventType(t *testing.T) {
	defer resetEventTypes()

	tests := []struct {
		eventType    EventType
		expected     string
		expectedJSON string
	}{
		{DebugEvent, "Debug", `"Debug"`},
		{ThumbEvent, "Thumb", `"Thumb"`},
		{InfoEvent, "Info", `"Info"`},
		{WarnEvent, "Warn", `"Warn"`},
		{ErrorEvent, "Error", `"Error"`},
		{FatalEvent, "Fatal", `"Fatal"`},
		{EventType(255), "EventType(255)", `"EventType(255)"`},
		{NewEventType("my-event-type"), "my-event-type", `"my-event-type"`},
		{NewEventType("my-\"event\"-type"), "my-\"event\"-type", `"my-\"event\"-type"`},
	}

	for _, test := range tests {
		got, gotBytes := test.eventType.String(), string(test.eventType.Bytes())
		if gotBytes != test.expected {
			t.Errorf("Expected EventType(%v).Bytes() to return %q, but got %q",
				test.eventType, test.expected, gotBytes)
		} else if got != test.expected {
			t.Errorf("Expected EventType(%v).String() to return %q, but got %q",
				test.eventType, test.expected, got)
		}

		if json, err := test.eventType.MarshalJSON(); err != nil {
			t.Errorf("Unexpected error marshaling %v into json: %s", test.eventType, err.Error())
		} else if got := string(json); got != test.expectedJSON {
			t.Errorf("Expected EventType(%v).MarshalJSON() to return %q, but got %q",
				test.eventType, test.expectedJSON, got)
		}
	}
}

var (
	// Minus builtin event types.
	maxCostumEventTypes = math.MaxUint16 - len(eventTypeIndices)

	oldEventTypeNames   = eventTypeNames
	oldEventTypeIndices = eventTypeIndices
)

func resetEventTypes() {
	eventTypeNames = oldEventTypeNames
	eventTypeIndices = oldEventTypeIndices
}

func TestNewLogLevelLimit(t *testing.T) {
	if testing.Short() {
		t.Skip("Skipping TestNewLogLevelLimit in short mode")
	}
	defer resetEventTypes()

	for i := 1; i <= maxCostumEventTypes; i++ {
		expected := fmt.Sprintf("EventType-%d", i)
		eventType := NewEventType(expected)
		if got := eventType.String(); got != expected {
			t.Fatalf("Expected NewEventType(%q).String() to return %q, but got %q",
				expected, expected, got)
		}
	}

	defer func() {
		recv := recover()
		if recv == nil {
			t.Fatal("Expected a panic after creating 65528 log levels, but didn't get one")
		}

		got, ok := recv.(string)
		if !ok {
			t.Fatalf("Expected the recoverd panic to be a string, but it's %v", recv)
		}

		expected := "logger: can't have more then 65535 EventTypes"
		if got != expected {
			t.Fatalf("Expected the recoverd panic to be %s, but got %s", expected, got)
		}
	}()

	NewEventType(fmt.Sprintf("EventType-%d", maxCostumEventTypes+1))
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Kubernetes 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 drain

import (
	"fmt"

	corev1 "k8s.io/api/core/v1"
	utilerrors "k8s.io/apimachinery/pkg/util/errors"
)

// This file contains default implementations of how to
// drain/cordon/uncordon nodes.  These functions may be called
// directly, or their functionality copied into your own code, for
// example if you want different output behaviour.

// RunNodeDrain shows the canonical way to drain a node.
// You should first cordon the node, e.g. using RunCordonOrUncordon
func RunNodeDrain(drainer *Helper, nodeName string) error {
	// TODO(justinsb): Ensure we have adequate e2e coverage of this function in library consumers
	list, errs := drainer.GetPodsForDeletion(nodeName)
	if errs != nil {
		return utilerrors.NewAggregate(errs)
	}
	if warnings := list.Warnings(); warnings != "" {
		fmt.Fprintf(drainer.ErrOut, "WARNING: %s\n", warnings)
	}

	if err := drainer.DeleteOrEvictPods(list.Pods()); err != nil {
		// Maybe warn about non-deleted pods here
		return err
	}
	return nil
}

// RunCordonOrUncordon demonstrates the canonical way to cordon or uncordon a Node
func RunCordonOrUncordon(drainer *Helper, node *corev1.Node, desired bool) error {
	// TODO(justinsb): Ensure we have adequate e2e coverage of this function in library consumers
	c := NewCordonHelper(node)

	if updateRequired := c.UpdateIfRequired(desired); !updateRequired {
		// Already done
		return nil
	}

	err, patchErr := c.PatchOrReplaceWithContext(drainer.Ctx, drainer.Client, false)
	if err != nil {
		if patchErr != nil {
			return fmt.Errorf("cordon error: %s; merge patch error: %s", err.Error(), patchErr.Error())
		}
		return fmt.Errorf("cordon error: %s", err.Error())
	}

	return nil
}
<commit_msg>wrap error from RunCordonOrUncordon<commit_after>/*
Copyright 2019 The Kubernetes 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 drain

import (
	"fmt"

	corev1 "k8s.io/api/core/v1"
	utilerrors "k8s.io/apimachinery/pkg/util/errors"
)

// This file contains default implementations of how to
// drain/cordon/uncordon nodes.  These functions may be called
// directly, or their functionality copied into your own code, for
// example if you want different output behaviour.

// RunNodeDrain shows the canonical way to drain a node.
// You should first cordon the node, e.g. using RunCordonOrUncordon
func RunNodeDrain(drainer *Helper, nodeName string) error {
	// TODO(justinsb): Ensure we have adequate e2e coverage of this function in library consumers
	list, errs := drainer.GetPodsForDeletion(nodeName)
	if errs != nil {
		return utilerrors.NewAggregate(errs)
	}
	if warnings := list.Warnings(); warnings != "" {
		fmt.Fprintf(drainer.ErrOut, "WARNING: %s\n", warnings)
	}

	if err := drainer.DeleteOrEvictPods(list.Pods()); err != nil {
		// Maybe warn about non-deleted pods here
		return err
	}
	return nil
}

// RunCordonOrUncordon demonstrates the canonical way to cordon or uncordon a Node
func RunCordonOrUncordon(drainer *Helper, node *corev1.Node, desired bool) error {
	// TODO(justinsb): Ensure we have adequate e2e coverage of this function in library consumers
	c := NewCordonHelper(node)

	if updateRequired := c.UpdateIfRequired(desired); !updateRequired {
		// Already done
		return nil
	}

	err, patchErr := c.PatchOrReplaceWithContext(drainer.Ctx, drainer.Client, false)
	if err != nil {
		if patchErr != nil {
			return fmt.Errorf("cordon error: %s; merge patch error: %w", err.Error(), patchErr)
		}
		return fmt.Errorf("cordon error: %w", err)
	}

	return nil
}
<|endoftext|>


<commit_before>// Copyright (c) 2017, CodeBoy. All rights reserved.
//
// This Source Code Form is subject to the terms of the
// license that can be found in the LICENSE file.

package model

import (
	"time"
)

// MapInfo is info struct for FileMap.
type MapInfo struct {
	ID     int       `json:"id"`
	Title  string    `json:"title"`
	Base   string    `json:"base"`
	File   string    `json:"file"`
	Opened time.Time `json:"opened"`
}

// MapInfos is a collection of MapInfo pointers.
type MapInfos []MapInfo

// Implementation of sort.Interface for MapInfos.
func (slice MapInfos) Len() int {
	return len(slice)
}

func (slice MapInfos) Less(i, j int) bool {
	return slice[i].Opened.Before(slice[j].Opened)
}

func (slice MapInfos) Swap(i, j int) {
	slice[i], slice[j] = slice[j], slice[i]
}
<commit_msg>Sort map list: last opened first<commit_after>// Copyright (c) 2017, CodeBoy. All rights reserved.
//
// This Source Code Form is subject to the terms of the
// license that can be found in the LICENSE file.

package model

import (
	"time"
)

// MapInfo is info struct for FileMap.
type MapInfo struct {
	ID     int       `json:"id"`
	Title  string    `json:"title"`
	Base   string    `json:"base"`
	File   string    `json:"file"`
	Opened time.Time `json:"opened"`
}

// MapInfos is a collection of MapInfo pointers.
type MapInfos []MapInfo

// Implementation of sort.Interface for MapInfos.
func (slice MapInfos) Len() int {
	return len(slice)
}

func (slice MapInfos) Less(i, j int) bool {
	return slice[i].Opened.After(slice[j].Opened)
}

func (slice MapInfos) Swap(i, j int) {
	slice[i], slice[j] = slice[j], slice[i]
}
<|endoftext|>


<commit_before>package server

import (
	"os"
	"net"

	"junta/util"
	"junta/paxos"
	"junta/proto"
	"junta/store"
	"strconv"
	"time"
)

type ReadFromWriteToer interface {
	ReadFrom([]byte) (int, net.Addr, os.Error)
	WriteTo([]byte, net.Addr) (int, os.Error)
	LocalAddr() net.Addr
}

const packetSize = 3000

type conn struct {
	net.Conn
	s *Server
}

type Manager interface {
	PutFrom(string, paxos.Msg)
	Propose(string) (uint64, string, os.Error)
	Alpha() int
}

type Server struct {
	Addr string
	St *store.Store
	Mg Manager
}

func (sv *Server) ListenAndServe() os.Error {
	logger := util.NewLogger("server %s", sv.Addr)

	logger.Log("binding")
	l, err := net.Listen("tcp", sv.Addr)
	if err != nil {
		logger.Log(err)
		return err
	}
	defer l.Close()
	logger.Log("listening")

	err = sv.Serve(l)
	if err != nil {
		logger.Logf("%s: %s", l, err)
}
	return err
}

func (sv *Server) ListenAndServeUdp(outs chan paxos.Packet) os.Error {
	logger := util.NewLogger("udp server %s", sv.Addr)

	logger.Log("binding")
	u, err := net.ListenPacket("udp", sv.Addr)
	if err != nil {
		logger.Log(err)
		return err
	}
	defer u.Close()
	logger.Log("listening")

	err = sv.ServeUdp(u, outs)
	if err != nil {
		logger.Logf("%s: %s", u, err)
	}
	return err
}

func (sv *Server) ServeUdp(u ReadFromWriteToer, outs chan paxos.Packet) os.Error {
	recvd := make(chan paxos.Packet)
	sent := make(chan paxos.Packet)

	logger := util.NewLogger("udp server %s", u.LocalAddr())
	go func() {
		logger.Log("reading messages...")
		for {
			msg, addr, err := paxos.ReadMsg(u, packetSize)
			if err != nil {
				logger.Log(err)
				continue
			}
			logger.Logf("read %v from %s", msg, addr)
			recvd <- paxos.Packet{msg, addr}
			sv.Mg.PutFrom(addr, msg)
		}
	}()

	go func() {
		logger.Log("sending messages...")
		for pk := range outs {
			logger.Logf("sending %v", pk)
			udpAddr, err := net.ResolveUDPAddr(pk.Addr)
			if err != nil {
				logger.Log(err)
				continue
			}

			_, err = u.WriteTo(pk.Msg.WireBytes(), udpAddr)
			if err != nil {
				logger.Log(err)
				continue
			}
			sent <- paxos.Packet{pk.Msg, pk.Addr}
		}
	}()

	needsAck := make(map[string]bool)
	resend := make(chan paxos.Packet)
	for {
		select {
		case pk := <-recvd:
			if pk.Msg.HasFlags(paxos.Ack) {
				logger.Logf("got ack %s %v", pk.Addr, pk.Msg)
				needsAck[pk.Id()] = false
			} else {
				logger.Logf("sending ack %s %v", pk.Addr, pk.Msg)
				udpAddr, err := net.ResolveUDPAddr(pk.Addr)
				if err != nil {
					break
				}
				ack := pk.Msg.Dup().SetFlags(paxos.Ack)
				u.WriteTo(ack.WireBytes(), udpAddr)
			}
		case pk := <-sent:
			needsAck[pk.Id()] = true
			logger.Logf("needs ack %s %v", pk.Addr, pk.Msg)
			go func() {
				time.Sleep(100000000) // ns == 0.1s
				resend <- pk
			}()
		case pk := <-resend:
			if needsAck[pk.Id()] {
				logger.Logf("resending %s %v", pk.Addr, pk.Msg)
				go func() {
					outs <- pk
				}()
			} else {
				needsAck[pk.Id()] = false, false
			}
		}
	}

	panic("not reached")
}

func (s *Server) Serve(l net.Listener) os.Error {
	for {
		rw, e := l.Accept()
		if e != nil {
			return e
		}
		c := &conn{rw, s}
		go c.serve()
	}

	panic("not reached")
}

func (sv *Server) setOnce(path, body, cas string) (uint64, os.Error) {
	mut, err := store.EncodeSet(path, body, cas)
	if err != nil {
		return 0, err
	}

	seqn, v, err := sv.Mg.Propose(mut)
	if err != nil {
		return 0, err
	}

	// We failed, but only because of a competing proposal. The client should
	// retry.
	if v != mut {
		return 0, os.EAGAIN
	}

	return seqn, nil
}

func (sv *Server) Set(path, body, cas string) (seqn uint64, err os.Error) {
	err = os.EAGAIN
	for err == os.EAGAIN {
		seqn, err = sv.setOnce(path, body, cas)
	}
	return
}

func (sv *Server) delOnce(path, cas string) (uint64, os.Error) {
	mut, err := store.EncodeDel(path, cas)
	if err != nil {
		return 0, err
	}

	seqn, v, err := sv.Mg.Propose(mut)
	if err != nil {
		return 0, err
	}

	// We failed, but only because of a competing proposal. The client should
	// retry.
	if v != mut {
		return 0, os.EAGAIN
	}

	return seqn, nil
}

func (sv *Server) Del(path, cas string) (seqn uint64, err os.Error) {
	err = os.EAGAIN
	for err == os.EAGAIN {
		seqn, err = sv.delOnce(path, cas)
	}
	return
}

// Repeatedly propose nop values until a successful read from `done`.
func (sv *Server) AdvanceUntil(done chan int) {
	for _, ok := <-done; !ok; _, ok = <-done {
		sv.Mg.Propose(store.Nop)
	}
}

func (c *conn) serve() {
	pc := proto.NewConn(c)
	logger := util.NewLogger("%v", c.RemoteAddr())
	logger.Log("accepted connection")
	for {
		rid, parts, err := pc.ReadRequest()
		if err != nil {
			if err == os.EOF {
				logger.Log("connection closed by peer")
			} else {
				logger.Log(err)
			}
			return
		}

		rlogger := util.NewLogger("%v - req [%d]", c.RemoteAddr(), rid)
		rlogger.Logf("received <%v>", parts)

		if len(parts) == 0 {
			rlogger.Log("zero parts supplied")
			pc.SendError(rid, proto.InvalidCommand)
			continue
		}

		switch parts[0] {
		default:
			rlogger.Logf("unknown command <%s>", parts[0])
			pc.SendError(rid, proto.InvalidCommand)
		case "set":
			if len(parts) != 4 {
				rlogger.Logf("invalid set command: %#v", parts)
				pc.SendError(rid, "wrong number of parts")
				break
			}
			rlogger.Logf("set %q=%q (cas %q)", parts[1], parts[2], parts[3])
			_, err := c.s.Set(parts[1], parts[2], parts[3])
			if err != nil {
				rlogger.Logf("bad: %s", err)
				pc.SendError(rid, err.String())
			} else {
				rlogger.Logf("good")
				pc.SendResponse(rid, "true")
			}
		case "del":
			if len(parts) != 3 {
				rlogger.Logf("invalid del command: %v", parts)
				pc.SendError(rid, "wrong number of parts")
				break
			}
			rlogger.Logf("del %q (cas %q)", parts[1], parts[2])
			_, err := c.s.Del(parts[1], parts[2])
			if err != nil {
				rlogger.Logf("bad: %s", err)
				pc.SendError(rid, err.String())
			} else {
				rlogger.Logf("good")
				pc.SendResponse(rid, "true")
			}
		case "join":
			// join abc123 1.2.3.4:999
			if len(parts) != 3 {
				rlogger.Logf("invalid join command: %v", parts)
				pc.SendError(rid, "wrong number of parts")
				break
			}

			who, addr := parts[1], parts[2]
			rlogger.Logf("membership requested for %s at %s", who, addr)

			key := "/j/junta/members/" + who

			seqn, err := c.s.Set(key, addr, store.Missing)
			if err != nil {
				rlogger.Logf("bad: %s", err)
				pc.SendError(rid, err.String())
			} else {
				rlogger.Logf("good")
				done := make(chan int)
				go c.s.AdvanceUntil(done)
				c.s.St.Sync(seqn + uint64(c.s.Mg.Alpha()))
				close(done)
				seqn, snap := c.s.St.Snapshot()
				pc.SendResponse(rid, strconv.Uitoa64(seqn), snap)
			}
		}
	}
}
<commit_msg>wait-for-path-set<commit_after>package server

import (
	"os"
	"net"

	"junta/util"
	"junta/paxos"
	"junta/proto"
	"junta/store"
	"strconv"
	"time"
)

type ReadFromWriteToer interface {
	ReadFrom([]byte) (int, net.Addr, os.Error)
	WriteTo([]byte, net.Addr) (int, os.Error)
	LocalAddr() net.Addr
}

const packetSize = 3000

type conn struct {
	net.Conn
	s *Server
}

type Manager interface {
	PutFrom(string, paxos.Msg)
	Propose(string) (uint64, string, os.Error)
	Alpha() int
}

type Server struct {
	Addr string
	St *store.Store
	Mg Manager
}

func (sv *Server) ListenAndServe() os.Error {
	logger := util.NewLogger("server %s", sv.Addr)

	logger.Log("binding")
	l, err := net.Listen("tcp", sv.Addr)
	if err != nil {
		logger.Log(err)
		return err
	}
	defer l.Close()
	logger.Log("listening")

	err = sv.Serve(l)
	if err != nil {
		logger.Logf("%s: %s", l, err)
}
	return err
}

func (sv *Server) ListenAndServeUdp(outs chan paxos.Packet) os.Error {
	logger := util.NewLogger("udp server %s", sv.Addr)

	logger.Log("binding")
	u, err := net.ListenPacket("udp", sv.Addr)
	if err != nil {
		logger.Log(err)
		return err
	}
	defer u.Close()
	logger.Log("listening")

	err = sv.ServeUdp(u, outs)
	if err != nil {
		logger.Logf("%s: %s", u, err)
	}
	return err
}

func (sv *Server) ServeUdp(u ReadFromWriteToer, outs chan paxos.Packet) os.Error {
	recvd := make(chan paxos.Packet)
	sent := make(chan paxos.Packet)

	logger := util.NewLogger("udp server %s", u.LocalAddr())
	go func() {
		logger.Log("reading messages...")
		for {
			msg, addr, err := paxos.ReadMsg(u, packetSize)
			if err != nil {
				logger.Log(err)
				continue
			}
			logger.Logf("read %v from %s", msg, addr)
			recvd <- paxos.Packet{msg, addr}
			sv.Mg.PutFrom(addr, msg)
		}
	}()

	go func() {
		logger.Log("sending messages...")
		for pk := range outs {
			logger.Logf("sending %v", pk)
			udpAddr, err := net.ResolveUDPAddr(pk.Addr)
			if err != nil {
				logger.Log(err)
				continue
			}

			_, err = u.WriteTo(pk.Msg.WireBytes(), udpAddr)
			if err != nil {
				logger.Log(err)
				continue
			}
			sent <- paxos.Packet{pk.Msg, pk.Addr}
		}
	}()

	needsAck := make(map[string]bool)
	resend := make(chan paxos.Packet)
	for {
		select {
		case pk := <-recvd:
			if pk.Msg.HasFlags(paxos.Ack) {
				logger.Logf("got ack %s %v", pk.Addr, pk.Msg)
				needsAck[pk.Id()] = false
			} else {
				logger.Logf("sending ack %s %v", pk.Addr, pk.Msg)
				udpAddr, err := net.ResolveUDPAddr(pk.Addr)
				if err != nil {
					break
				}
				ack := pk.Msg.Dup().SetFlags(paxos.Ack)
				u.WriteTo(ack.WireBytes(), udpAddr)
			}
		case pk := <-sent:
			needsAck[pk.Id()] = true
			logger.Logf("needs ack %s %v", pk.Addr, pk.Msg)
			go func() {
				time.Sleep(100000000) // ns == 0.1s
				resend <- pk
			}()
		case pk := <-resend:
			if needsAck[pk.Id()] {
				logger.Logf("resending %s %v", pk.Addr, pk.Msg)
				go func() {
					outs <- pk
				}()
			} else {
				needsAck[pk.Id()] = false, false
			}
		}
	}

	panic("not reached")
}

func (s *Server) Serve(l net.Listener) os.Error {
	for {
		rw, e := l.Accept()
		if e != nil {
			return e
		}
		c := &conn{rw, s}
		go c.serve()
	}

	panic("not reached")
}

func (sv *Server) setOnce(path, body, cas string) (uint64, os.Error) {
	mut, err := store.EncodeSet(path, body, cas)
	if err != nil {
		return 0, err
	}

	seqn, v, err := sv.Mg.Propose(mut)
	if err != nil {
		return 0, err
	}

	// We failed, but only because of a competing proposal. The client should
	// retry.
	if v != mut {
		return 0, os.EAGAIN
	}

	return seqn, nil
}

func (sv *Server) Set(path, body, cas string) (seqn uint64, err os.Error) {
	err = os.EAGAIN
	for err == os.EAGAIN {
		seqn, err = sv.setOnce(path, body, cas)
	}
	return
}

func (sv *Server) delOnce(path, cas string) (uint64, os.Error) {
	mut, err := store.EncodeDel(path, cas)
	if err != nil {
		return 0, err
	}

	seqn, v, err := sv.Mg.Propose(mut)
	if err != nil {
		return 0, err
	}

	// We failed, but only because of a competing proposal. The client should
	// retry.
	if v != mut {
		return 0, os.EAGAIN
	}

	return seqn, nil
}

func (sv *Server) Del(path, cas string) (seqn uint64, err os.Error) {
	err = os.EAGAIN
	for err == os.EAGAIN {
		seqn, err = sv.delOnce(path, cas)
	}
	return
}

func (sv *Server) WaitForPathSet(path string) (body string, err os.Error) {
	evs := make(chan store.Event)
	defer close(evs)
	sv.St.Watch(path, evs)

	parts, cas := sv.St.Lookup(path)
	if cas != store.Dir && cas != store.Missing {
		return parts[0], nil
	}

	for ev := range evs {
		if ev.IsSet() {
			return ev.Body, nil
		}
	}

	panic("not reached")
}

// Repeatedly propose nop values until a successful read from `done`.
func (sv *Server) AdvanceUntil(done chan int) {
	for _, ok := <-done; !ok; _, ok = <-done {
		sv.Mg.Propose(store.Nop)
	}
}

func (c *conn) serve() {
	pc := proto.NewConn(c)
	logger := util.NewLogger("%v", c.RemoteAddr())
	logger.Log("accepted connection")
	for {
		rid, parts, err := pc.ReadRequest()
		if err != nil {
			if err == os.EOF {
				logger.Log("connection closed by peer")
			} else {
				logger.Log(err)
			}
			return
		}

		rlogger := util.NewLogger("%v - req [%d]", c.RemoteAddr(), rid)
		rlogger.Logf("received <%v>", parts)

		if len(parts) == 0 {
			rlogger.Log("zero parts supplied")
			pc.SendError(rid, proto.InvalidCommand)
			continue
		}

		switch parts[0] {
		default:
			rlogger.Logf("unknown command <%s>", parts[0])
			pc.SendError(rid, proto.InvalidCommand)
		case "set":
			if len(parts) != 4 {
				rlogger.Logf("invalid set command: %#v", parts)
				pc.SendError(rid, "wrong number of parts")
				break
			}
			rlogger.Logf("set %q=%q (cas %q)", parts[1], parts[2], parts[3])
			_, err := c.s.Set(parts[1], parts[2], parts[3])
			if err != nil {
				rlogger.Logf("bad: %s", err)
				pc.SendError(rid, err.String())
			} else {
				rlogger.Logf("good")
				pc.SendResponse(rid, "true")
			}
		case "del":
			if len(parts) != 3 {
				rlogger.Logf("invalid del command: %v", parts)
				pc.SendError(rid, "wrong number of parts")
				break
			}
			rlogger.Logf("del %q (cas %q)", parts[1], parts[2])
			_, err := c.s.Del(parts[1], parts[2])
			if err != nil {
				rlogger.Logf("bad: %s", err)
				pc.SendError(rid, err.String())
			} else {
				rlogger.Logf("good")
				pc.SendResponse(rid, "true")
			}
		case "wait-for-path-set": // TODO this is for demo purposes only
			if len(parts) != 2 {
				rlogger.Logf("invalid del command: %v", parts)
				pc.SendError(rid, "wrong number of parts")
				break
			}
			rlogger.Logf("wait-for-path-set %q", parts[1])
			body, err := c.s.WaitForPathSet(parts[1])
			if err != nil {
				rlogger.Logf("bad: %s", err)
				pc.SendError(rid, err.String())
			} else {
				rlogger.Logf("good %q", body)
				pc.SendResponse(rid, body)
			}
		case "join":
			// join abc123 1.2.3.4:999
			if len(parts) != 3 {
				rlogger.Logf("invalid join command: %v", parts)
				pc.SendError(rid, "wrong number of parts")
				break
			}

			who, addr := parts[1], parts[2]
			rlogger.Logf("membership requested for %s at %s", who, addr)

			key := "/j/junta/members/" + who

			seqn, err := c.s.Set(key, addr, store.Missing)
			if err != nil {
				rlogger.Logf("bad: %s", err)
				pc.SendError(rid, err.String())
			} else {
				rlogger.Logf("good")
				done := make(chan int)
				go c.s.AdvanceUntil(done)
				c.s.St.Sync(seqn + uint64(c.s.Mg.Alpha()))
				close(done)
				seqn, snap := c.s.St.Snapshot()
				pc.SendResponse(rid, strconv.Uitoa64(seqn), snap)
			}
		}
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Kubernetes 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 server

import (
	"context"
	"fmt"
	"io"
	"math/rand"
	"net/http"
	"time"

	"k8s.io/klog/v2"
	"sigs.k8s.io/apiserver-network-proxy/konnectivity-client/proto/client"
)

// Tunnel implements Proxy based on HTTP Connect, which tunnels the traffic to
// the agent registered in ProxyServer.
type Tunnel struct {
	Server *ProxyServer
}

func (t *Tunnel) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	klog.V(2).InfoS("Received request for host", "method", r.Method, "host", r.Host, "userAgent", r.UserAgent())
	if r.TLS != nil {
		klog.V(2).InfoS("TLS", "commonName", r.TLS.PeerCertificates[0].Subject.CommonName)
	}
	if r.Method != http.MethodConnect {
		http.Error(w, "this proxy only supports CONNECT passthrough", http.StatusMethodNotAllowed)
		return
	}

	hijacker, ok := w.(http.Hijacker)
	if !ok {
		http.Error(w, "hijacking not supported", http.StatusInternalServerError)
		return
	}
	w.WriteHeader(http.StatusOK)

	conn, bufrw, err := hijacker.Hijack()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	random := rand.Int63()
	dialRequest := &client.Packet{
		Type: client.PacketType_DIAL_REQ,
		Payload: &client.Packet_DialRequest{
			DialRequest: &client.DialRequest{
				Protocol: "tcp",
				Address:  r.Host,
				Random:   random,
			},
		},
	}
	klog.V(4).InfoS("Set pending", "random", random, "value", w)
	backend, err := t.Server.BackendManager.Backend(context.TODO())
	if err != nil {
		http.Error(w, fmt.Sprintf("currently no tunnels available: %v", err), http.StatusInternalServerError)
		return
	}
	connected := make(chan struct{})
	connection := &ProxyClientConnection{
		Mode:      "http-connect",
		HTTP:      conn,
		connected: connected,
		start:     time.Now(),
		backend:   backend,
	}
	t.Server.PendingDial.Add(random, connection)
	if err := backend.Send(dialRequest); err != nil {
		klog.ErrorS(err, "failed to tunnel dial request")
		return
	}
	ctxt := backend.Context()
	if ctxt.Err() != nil {
		klog.ErrorS(err, "context reports failure")
	}

	select {
	case <-ctxt.Done():
		klog.V(5).Infoln("context reports done")
	default:
	}

	select {
	case <-connection.connected: // Waiting for response before we begin full communication.
	}

	defer conn.Close()

	klog.V(3).InfoS("Starting proxy to host", "host", r.Host)
	pkt := make([]byte, 1<<12)

	connID := connection.connectID
	agentID := connection.agentID
	var acc int

	for {
		n, err := bufrw.Read(pkt[:])
		acc += n
		if err == io.EOF {
			klog.V(1).InfoS("EOF from host", "host", r.Host)
			break
		}
		if err != nil {
			klog.ErrorS(err, "Received failure on connection")
			break
		}

		packet := &client.Packet{
			Type: client.PacketType_DATA,
			Payload: &client.Packet_Data{
				Data: &client.Data{
					ConnectID: connID,
					Data:      pkt[:n],
				},
			},
		}
		err = backend.Send(packet)
		if err != nil {
			klog.ErrorS(err, "error sending packet")
			break
		}
		klog.V(5).InfoS("Forwarding data on tunnel to agent",
			"bytes", n,
			"totalBytes", acc,
			"agentID", connection.agentID,
			"connectionID", connection.connectID)
	}

	klog.V(5).InfoS("Stopping transfer to host", "host", r.Host, "agentID", agentID, "connectionID", connID)
}
<commit_msg>send PacketType_CLOSE_REQ to agent when tunnel serve exits to prevent conn between agent and remote leakage.<commit_after>/*
Copyright 2019 The Kubernetes 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 server

import (
	"context"
	"fmt"
	"io"
	"math/rand"
	"net/http"
	"time"

	"k8s.io/klog/v2"
	"sigs.k8s.io/apiserver-network-proxy/konnectivity-client/proto/client"
)

// Tunnel implements Proxy based on HTTP Connect, which tunnels the traffic to
// the agent registered in ProxyServer.
type Tunnel struct {
	Server *ProxyServer
}

func (t *Tunnel) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	klog.V(2).InfoS("Received request for host", "method", r.Method, "host", r.Host, "userAgent", r.UserAgent())
	if r.TLS != nil {
		klog.V(2).InfoS("TLS", "commonName", r.TLS.PeerCertificates[0].Subject.CommonName)
	}
	if r.Method != http.MethodConnect {
		http.Error(w, "this proxy only supports CONNECT passthrough", http.StatusMethodNotAllowed)
		return
	}

	hijacker, ok := w.(http.Hijacker)
	if !ok {
		http.Error(w, "hijacking not supported", http.StatusInternalServerError)
		return
	}
	w.WriteHeader(http.StatusOK)

	conn, bufrw, err := hijacker.Hijack()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	random := rand.Int63()
	dialRequest := &client.Packet{
		Type: client.PacketType_DIAL_REQ,
		Payload: &client.Packet_DialRequest{
			DialRequest: &client.DialRequest{
				Protocol: "tcp",
				Address:  r.Host,
				Random:   random,
			},
		},
	}
	klog.V(4).InfoS("Set pending", "random", random, "value", w)
	backend, err := t.Server.BackendManager.Backend(context.TODO())
	if err != nil {
		http.Error(w, fmt.Sprintf("currently no tunnels available: %v", err), http.StatusInternalServerError)
		return
	}
	connected := make(chan struct{})
	connection := &ProxyClientConnection{
		Mode:      "http-connect",
		HTTP:      conn,
		connected: connected,
		start:     time.Now(),
		backend:   backend,
	}
	t.Server.PendingDial.Add(random, connection)
	if err := backend.Send(dialRequest); err != nil {
		klog.ErrorS(err, "failed to tunnel dial request")
		return
	}
	ctxt := backend.Context()
	if ctxt.Err() != nil {
		klog.ErrorS(err, "context reports failure")
	}

	select {
	case <-ctxt.Done():
		klog.V(5).Infoln("context reports done")
	default:
	}

	select {
	case <-connection.connected: // Waiting for response before we begin full communication.
	}

	defer func() {
		packet := &client.Packet{
			Type: client.PacketType_CLOSE_REQ,
			Payload: &client.Packet_CloseRequest{
				CloseRequest: &client.CloseRequest{
					ConnectID: connection.connectID,
				},
			},
		}

		if err = backend.Send(packet); err != nil {
			klog.V(2).InfoS("failed to send close request packet", "host", r.Host, "agentID", connection.agentID, "connID", connection.connectID)
		}
		conn.Close()
	}()

	klog.V(3).InfoS("Starting proxy to host", "host", r.Host)
	pkt := make([]byte, 1<<12)

	connID := connection.connectID
	agentID := connection.agentID
	var acc int

	for {
		n, err := bufrw.Read(pkt[:])
		acc += n
		if err == io.EOF {
			klog.V(1).InfoS("EOF from host", "host", r.Host)
			break
		}
		if err != nil {
			klog.ErrorS(err, "Received failure on connection")
			break
		}

		packet := &client.Packet{
			Type: client.PacketType_DATA,
			Payload: &client.Packet_Data{
				Data: &client.Data{
					ConnectID: connID,
					Data:      pkt[:n],
				},
			},
		}
		err = backend.Send(packet)
		if err != nil {
			klog.ErrorS(err, "error sending packet")
			break
		}
		klog.V(5).InfoS("Forwarding data on tunnel to agent",
			"bytes", n,
			"totalBytes", acc,
			"agentID", connection.agentID,
			"connectionID", connection.connectID)
	}

	klog.V(5).InfoS("Stopping transfer to host", "host", r.Host, "agentID", agentID, "connectionID", connID)
}
<|endoftext|>


<commit_before>package testutils

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"testing"
)

// NewCommand TODO: comment
func NewCommand(cmd string) *exec.Cmd {
	return exec.Command("sh", "-c", cmd)
}

// CreateLocalDirectory TODO: comment
func CreateLocalDirectory(t *testing.T) string {
	dir, err := ioutil.TempDir(os.TempDir(), "kompose-test-")
	if err != nil {
		t.Fatal(err)
	}
	return dir
}

// CreateLocalGitDirectory TODO: comment
func CreateLocalGitDirectory(t *testing.T) string {
	dir := CreateLocalDirectory(t)
	cmd := NewCommand(
		`git init && touch README &&
		git add README &&
		git commit -m 'testcommit'`)
	cmd.Dir = dir
	_, err := cmd.Output()
	if err != nil {
		t.Logf("create local git dir: %v", err)
		t.Fatal(err)
	}
	return dir
}

// SetGitRemote TODO: comment
func SetGitRemote(t *testing.T, dir string, remote string, remoteURL string) {
	cmd := NewCommand(fmt.Sprintf("git remote add %s %s", remote, remoteURL))
	cmd.Dir = dir
	_, err := cmd.Output()
	if err != nil {
		t.Logf("set git remote: %v", err)
		t.Fatal(err)
	}
}

// CreateGitRemoteBranch TODO: comment
func CreateGitRemoteBranch(t *testing.T, dir string, branch string, remote string) {
	cmd := NewCommand(
		fmt.Sprintf(`git checkout -b %s &&
		    git config branch.%s.remote %s &&
		 	git config branch.%s.merge refs/heads/%s`,
			branch, branch, remote, branch, branch))
	cmd.Dir = dir

	_, err := cmd.Output()
	if err != nil {
		t.Logf("create git branch: %v", err)
		t.Fatal(err)
	}
}

// CreateSubdir TODO: comment
func CreateSubdir(t *testing.T, dir string, subdir string) {
	cmd := NewCommand(fmt.Sprintf("mkdir -p %s", subdir))
	cmd.Dir = dir

	_, err := cmd.Output()
	if err != nil {
		t.Fatal(err)
	}
}
<commit_msg>Fix CreateLocalGitDirectory for tests.<commit_after>package testutils

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"testing"
)

// NewCommand TODO: comment
func NewCommand(cmd string) *exec.Cmd {
	return exec.Command("sh", "-c", cmd)
}

// CreateLocalDirectory TODO: comment
func CreateLocalDirectory(t *testing.T) string {
	dir, err := ioutil.TempDir(os.TempDir(), "kompose-test-")
	if err != nil {
		t.Fatal(err)
	}
	return dir
}

// CreateLocalGitDirectory TODO: comment
func CreateLocalGitDirectory(t *testing.T) string {
	dir := CreateLocalDirectory(t)
	cmd := NewCommand(
		`git init &&
		 git config  user.email "you@example.com" &&
		 git config  user.name "Your Name" &&
		 touch README &&
		 git add README &&
		 git commit --no-gpg-sign -m 'testcommit'`)
	cmd.Dir = dir
	_, err := cmd.Output()
	if err != nil {
		t.Logf("create local git dir: %v", err)
		t.Fatal(err)
	}
	return dir
}

// SetGitRemote TODO: comment
func SetGitRemote(t *testing.T, dir string, remote string, remoteURL string) {
	cmd := NewCommand(fmt.Sprintf("git remote add %s %s", remote, remoteURL))
	cmd.Dir = dir
	_, err := cmd.Output()
	if err != nil {
		t.Logf("set git remote: %v", err)
		t.Fatal(err)
	}
}

// CreateGitRemoteBranch TODO: comment
func CreateGitRemoteBranch(t *testing.T, dir string, branch string, remote string) {
	cmd := NewCommand(
		fmt.Sprintf(`git checkout -b %s &&
		    git config branch.%s.remote %s &&
		 	git config branch.%s.merge refs/heads/%s`,
			branch, branch, remote, branch, branch))
	cmd.Dir = dir

	_, err := cmd.Output()
	if err != nil {
		t.Logf("create git branch: %v", err)
		t.Fatal(err)
	}
}

// CreateSubdir TODO: comment
func CreateSubdir(t *testing.T, dir string, subdir string) {
	cmd := NewCommand(fmt.Sprintf("mkdir -p %s", subdir))
	cmd.Dir = dir

	_, err := cmd.Output()
	if err != nil {
		t.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package txtdirect

import (
	"net/http"
	"net/http/httptest"
	"testing"
)

func TestParsePlaceholders(t *testing.T) {
	tests := []struct {
		url         string
		placeholder string
		expected    string
	}{
		{
			"example.com{uri}",
			"/?test=test",
			"example.com/?test=test",
		},
		{
			"example.com{uri}/{~test}",
			"/?test=test",
			"example.com/?test=test/test",
		},
		{
			"example.com{uri}/{>Test}",
			"/?test=test",
			"example.com/?test=test/test-header",
		},
		{
			"example.com{uri}/{?test}",
			"/?test=test",
			"example.com/?test=test/test",
		},
		{
			"subdomain.example.com/{label1}",
			"/subdomain",
			"subdomain.example.com/subdomain",
		},
		{
			"subdomain.example.com/{label2}",
			"/example",
			"subdomain.example.com/example",
		},
		{
			"subdomain.example.com/{label3}",
			"/com",
			"subdomain.example.com/com",
		},
	}
	for _, test := range tests {
		req := httptest.NewRequest("GET", "https://subdomain.example.com"+test.placeholder, nil)
		req.AddCookie(&http.Cookie{Name: "test", Value: "test"})
		req.Header.Add("Test", "test-header")
		result, err := parsePlaceholders(test.url, req)
		if err != nil {
			t.Fatal(err)
		}
		if result != test.expected {
			t.Errorf("Expected %s, got %s", test.expected, result)
		}
	}
}

func TestParseLabelLessThanOneFails(t *testing.T) {
	url := "example.com/{label0}"
	uri := "test"
	req := httptest.NewRequest("GET", "https://example.com"+uri, nil)
	_, err := parsePlaceholders(url, req)
	if err == nil {
		t.Errorf("Expected error, got nil")
	}
}

func TestParseLabelTooHighFails(t *testing.T) {
	url := "example.com/{label9000}"
	uri := "test"
	req := httptest.NewRequest("GET", "https://example.com"+uri, nil)
	_, err := parsePlaceholders(url, req)
	if err == nil {
		t.Errorf("Expected error, got nil")
	}
}
<commit_msg>Rename test 'placeholder' field to 'uri'<commit_after>package txtdirect

import (
	"net/http"
	"net/http/httptest"
	"testing"
)

func TestParsePlaceholders(t *testing.T) {
	tests := []struct {
		url      string
		uri      string
		expected string
	}{
		{
			"example.com{uri}",
			"/?test=test",
			"example.com/?test=test",
		},
		{
			"example.com{uri}/{~test}",
			"/?test=test",
			"example.com/?test=test/test",
		},
		{
			"example.com{uri}/{>Test}",
			"/?test=test",
			"example.com/?test=test/test-header",
		},
		{
			"example.com{uri}/{?test}",
			"/?test=test",
			"example.com/?test=test/test",
		},
		{
			"subdomain.example.com/{label1}",
			"/subdomain",
			"subdomain.example.com/subdomain",
		},
		{
			"subdomain.example.com/{label2}",
			"/example",
			"subdomain.example.com/example",
		},
		{
			"subdomain.example.com/{label3}",
			"/com",
			"subdomain.example.com/com",
		},
	}
	for _, test := range tests {
		req := httptest.NewRequest("GET", "https://subdomain.example.com"+test.uri, nil)
		req.AddCookie(&http.Cookie{Name: "test", Value: "test"})
		req.Header.Add("Test", "test-header")
		result, err := parsePlaceholders(test.url, req)
		if err != nil {
			t.Fatal(err)
		}
		if result != test.expected {
			t.Errorf("Expected %s, got %s", test.expected, result)
		}
	}
}

func TestParseLabelLessThanOneFails(t *testing.T) {
	url := "example.com/{label0}"
	uri := "test"
	req := httptest.NewRequest("GET", "https://example.com"+uri, nil)
	_, err := parsePlaceholders(url, req)
	if err == nil {
		t.Errorf("Expected error, got nil")
	}
}

func TestParseLabelTooHighFails(t *testing.T) {
	url := "example.com/{label9000}"
	uri := "test"
	req := httptest.NewRequest("GET", "https://example.com"+uri, nil)
	_, err := parsePlaceholders(url, req)
	if err == nil {
		t.Errorf("Expected error, got nil")
	}
}
<|endoftext|>


<commit_before>package player

import (
	"encoding/json"
	"io/ioutil"
)

/*

Ban list: uuid, reason (omitempty)

Op list: uuid

*/

type BanList struct {
	players map[string]string
}

type JsonProfile struct {
	UUID   string `json:"uuid"`
	Reason string `json:"reason"`
}

func NewBanList() *BanList {
	return &BanList{
		make(map[string]string),
	}
}

// Loads the list from the given file.
func (list *BanList) LoadFile(path string) error {
	content, err := ioutil.ReadFile(path)

	if err != nil {
		return err
	}

	bans := make([]JsonProfile, 0)
	err = json.Unmarshal(content, &bans)

	if err != nil {
		return err
	}

	for _, profile := range bans {
		list.players[profile.UUID] = profile.Reason
	}

	return nil
}

// Saves the list to the given file.
func (list *BanList) SaveFile(path string) error {
	return nil
}

// Adds the given player to the list.
func (list *BanList) AddPlayer(uuid, reason string) {
	list.players[uuid] = reason
}

// Removes the given player from the list.
func (list *BanList) RemovePlayer(uuid, reason string) {
	delete(list.players, uuid)
}

// Returns the UUIDs that the list contains. (Can be empty.)
func (list *BanList) GetPlayers() []string {
	ret := make([]string, len(list.players))
	i := 0
	for _, player := range list.players {
		ret[i] = player
		i++
	}
	return ret
}

// Returns true if the list has the given UUID.
func (list *BanList) HasPlayer(uuid string) bool {
	if _, ok := list.players[uuid]; ok {
		return true
	}
	return false
}
<commit_msg>Quickfix.<commit_after>package player

import (
	"encoding/json"
	"io/ioutil"
)

/*

Ban list: uuid, reason (omitempty)

Op list: uuid

*/

type BanList struct {
	players map[string]string
}

type JsonProfile struct {
	UUID   string `json:"uuid"`
	Reason string `json:"reason"`
}

func NewBanList() *BanList {
	return &BanList{
		make(map[string]string),
	}
}

// Loads the list from the given file.
func (list *BanList) LoadFile(path string) error {
	content, err := ioutil.ReadFile(path)

	if err != nil {
		return err
	}

	bans := make([]JsonProfile, 0)
	err = json.Unmarshal(content, &bans)

	if err != nil {
		return err
	}

	for _, profile := range bans {
		list.players[profile.UUID] = profile.Reason
	}

	return nil
}

// Saves the list to the given file.
func (list *BanList) SaveFile(path string) error {
	return nil
}

// Adds the given player to the list.
func (list *BanList) AddPlayer(uuid, reason string) {
	list.players[uuid] = reason
}

// Removes the given player from the list.
func (list *BanList) RemovePlayer(uuid string) {
	delete(list.players, uuid)
}

// Returns the UUIDs that the list contains. (Can be empty.)
func (list *BanList) GetPlayers() []string {
	ret := make([]string, len(list.players))
	i := 0
	for _, player := range list.players {
		ret[i] = player
		i++
	}
	return ret
}

// Returns true if the list has the given UUID.
func (list *BanList) HasPlayer(uuid string) bool {
	if _, ok := list.players[uuid]; ok {
		return true
	}
	return false
}
<|endoftext|>


<commit_before>// Brunobot notifies a Discord channel when Professional Dota 2 games are live.
// This should be run via cron every minute to ensure only one notification.
package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"net/http"
	"os"
	"strconv"
	"strings"
	"time"
)

type payload struct {
	Content string `json:"content"`
}

type configuration struct {
	Teams     []string
	Webhook   string
	Whitelist bool
}

type api struct {
	Matches []struct {
		Team1 struct {
			TeamName string `json:"team_name"`
		} `json:"team1"`
		Link          string `json:"link"`
		StarttimeUnix string `json:"starttime_unix"`
		Team2         struct {
			TeamName string `json:"team_name"`
		} `json:"team2"`
	} `json:"matches"`
}

func getMatches(url string, target interface{}) error {
	req, err := http.NewRequest("GET", url, nil)
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	return json.NewDecoder(resp.Body).Decode(target)
}

func sendNotification(text string, webhook string) {
	payload := payload{text}
	blob, err := json.Marshal(payload)
	if err != nil {
		panic(err)
	}
	req, err := http.NewRequest("POST", webhook, bytes.NewBuffer(blob))
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()
}

func usage() {
	fmt.Println("Usage: brunobot --config=/path/to/config.json")
	os.Exit(1)
}

func whitelisted(team1 string, team2 string, whitelist []string) bool {
	a := strings.ToLower(team1)
	b := strings.ToLower(team2)
	for _, team := range whitelist {
		team = strings.ToLower(team)
		if a == team || b == team {
			return true
		}
	}
	return false
}

// Webhook must be set in configuration
func loadConfiguration(path string, config *configuration) {
	file, err := os.Open(path)
	if err != nil {
		fmt.Println("Configuration file not found.. exiting")
		usage()
	}
	decoder := json.NewDecoder(file)

	err = decoder.Decode(config)
	if err != nil {
		panic(err)
	}

	if config.Webhook == "" {
		fmt.Println("Webhook is not set.. exiting")
		usage()
	}
}

func main() {
	configFile := flag.String("config", "", "Configuration file")
	flag.Parse()
	if *configFile == "" {
		fmt.Println("Configuration file not found.. exiting")
		usage()
	}
	configuration := &configuration{}
	loadConfiguration(*configFile, configuration)

	api := new(api)
	getMatches("http://dailydota2.com/match-api", api)
	if len(api.Matches) != 0 {
		for _, match := range api.Matches {
			team1 := match.Team1.TeamName
			team2 := match.Team2.TeamName
			send := false

			if configuration.Whitelist {
				send = whitelisted(team1, team2, configuration.Teams)
			} else {
				send = true
			}

			// Prevent multiple notifications by checking time difference
			startTime, _ := strconv.Atoi(match.StarttimeUnix)
			delta := time.Now().Unix() - int64(startTime)
			if send && delta <= 60 {
				// Link points to stream but the stats page is nicer, so replace
				// with the stats URL instead
				url := strings.Replace(match.Link, "match", "stats", 1)
				notification := fmt.Sprintf("%s vs %s :: %s", team1, team2, url)
				sendNotification(notification, configuration.Webhook)
			}
		}
	}
}
<commit_msg>Return Parsed Config Instead Of Passing By Pointer<commit_after>// Brunobot notifies a Discord channel when Professional Dota 2 games are live.
// This should be run via cron every minute to ensure only one notification.
package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"net/http"
	"os"
	"strconv"
	"strings"
	"time"
)

type payload struct {
	Content string `json:"content"`
}

type configuration struct {
	Teams     []string
	Webhook   string
	Whitelist bool
}

type api struct {
	Matches []struct {
		Team1 struct {
			TeamName string `json:"team_name"`
		} `json:"team1"`
		Link          string `json:"link"`
		StarttimeUnix string `json:"starttime_unix"`
		Team2         struct {
			TeamName string `json:"team_name"`
		} `json:"team2"`
	} `json:"matches"`
}

func getMatches(url string, target interface{}) error {
	req, err := http.NewRequest("GET", url, nil)
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	return json.NewDecoder(resp.Body).Decode(target)
}

func sendNotification(text string, webhook string) {
	payload := payload{text}
	blob, err := json.Marshal(payload)
	if err != nil {
		panic(err)
	}
	req, err := http.NewRequest("POST", webhook, bytes.NewBuffer(blob))
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()
}

func usage() {
	fmt.Println("Usage: brunobot --config=/path/to/config.json")
	os.Exit(1)
}

func whitelisted(team1 string, team2 string, whitelist []string) bool {
	a := strings.ToLower(team1)
	b := strings.ToLower(team2)
	for _, team := range whitelist {
		team = strings.ToLower(team)
		if a == team || b == team {
			return true
		}
	}
	return false
}

// Webhook must be set in configuration
func parseConfiguration(path string) (config configuration, err error) {
	file, err := os.Open(path)
	if err != nil {
		return
	}
	defer file.Close()

	decoder := json.NewDecoder(file)
	err = decoder.Decode(&config)
	if err != nil {
		return
	}

	if config.Webhook == "" {
		err = fmt.Errorf("Webhook is not set")
		return
	}

	return
}

func main() {
	configFile := flag.String("config", "", "Configuration file")
	flag.Parse()
	if *configFile == "" {
		fmt.Println("Configuration file not found.. exiting")
		usage()
	}

	// parse configuration
	configuration, err := parseConfiguration(*configFile)
	if err != nil {
		fmt.Println(err)
		usage()
	}

	api := new(api)
	getMatches("http://dailydota2.com/match-api", api)
	if len(api.Matches) != 0 {
		for _, match := range api.Matches {
			team1 := match.Team1.TeamName
			team2 := match.Team2.TeamName
			send := false

			if configuration.Whitelist {
				send = whitelisted(team1, team2, configuration.Teams)
			} else {
				send = true
			}

			// Prevent multiple notifications by checking time difference
			startTime, _ := strconv.Atoi(match.StarttimeUnix)
			delta := time.Now().Unix() - int64(startTime)
			if send && delta <= 60 {
				// Link points to stream but the stats page is nicer, so replace
				// with the stats URL instead
				url := strings.Replace(match.Link, "match", "stats", 1)
				notification := fmt.Sprintf("%s vs %s :: %s", team1, team2, url)
				sendNotification(notification, configuration.Webhook)
			}
		}
	}
}
<|endoftext|>


<commit_before>package hwaflib

func (ctx *Context) Version() string {
	version := "20131009"
	return version
}

func (ctx *Context) Revision() string {
	revision := "aa8c983"
	return revision
}

// EOF

<commit_msg>version: 20131010<commit_after>package hwaflib

func (ctx *Context) Version() string {
	version := "20131010"
	return version
}

func (ctx *Context) Revision() string {
	revision := "aa5c1dc"
	return revision
}

// EOF

<|endoftext|>


<commit_before>package projects

type Project struct {
	Name       string
	Owner      string
	Repository string
	Version    string
	Identifier string
	Domain     string
	Subdomain  string
	Type       string
}

func (p Project) Path() string {
	var buffer bytes.Buffer

	if p.Type == "static" {
		buffer.WriteString("/srv/")
		buffer.WriteString(p.Domain)
		buffer.WriteString("/")
		buffer.WriteString(p.Subdomain)
		buffer.WriteString("/")
	}

	return string(buffer.Bytes())
}
<commit_msg>Implemented a function which returns the archive location<commit_after>package projects

import (
	"bytes"
)

type Project struct {
	Name       string
	Owner      string
	Repository string
	Version    string
	Identifier string
	Domain     string
	Subdomain  string
	Type       string
}

func (p Project) Path() string {
	var buffer bytes.Buffer

	if p.Type == "static" {
		buffer.WriteString("/srv/")
		buffer.WriteString(p.Domain)
		buffer.WriteString("/")
		buffer.WriteString(p.Subdomain)
		buffer.WriteString("/")
	}

	return string(buffer.Bytes())
}

func (p Project) ArchiveLocation() string {
	var buffer bytes.Buffer

	buffer.WriteString("https://s3.amazonaws.com/")
	buffer.WriteString(p.Identifier)
	buffer.WriteString("/")
	buffer.WriteString(p.Version)
	buffer.WriteString(".zip")

	return string(buffer.Bytes())
}
<|endoftext|>


<commit_before>package flags

import (
	"reflect"
	"unicode/utf8"
	"unsafe"
)

type scanHandler func(reflect.Value, *reflect.StructField) (bool, error)

func newGroup(shortDescription string, longDescription string, data interface{}) *Group {
	return &Group{
		ShortDescription: shortDescription,
		LongDescription:  longDescription,

		data: data,
	}
}

func (g *Group) optionByName(name string, namematch func(*Option, string) bool) *Option {
	prio := 0
	var retopt *Option

	for _, opt := range g.options {
		if namematch != nil && namematch(opt, name) && prio < 4 {
			retopt = opt
			prio = 4
		}

		if name == opt.field.Name && prio < 3 {
			retopt = opt
			prio = 3
		}

		if name == opt.LongName && prio < 2 {
			retopt = opt
			prio = 2
		}

		if opt.ShortName != 0 && name == string(opt.ShortName) && prio < 1 {
			retopt = opt
			prio = 1
		}
	}

	return retopt
}

func (g *Group) storeDefaults() {
	for _, option := range g.options {
		// First. empty out the value
		if len(option.Default) > 0 {
			option.clear()
		}

		for _, d := range option.Default {
			option.set(&d)
		}

		if !option.value.CanSet() {
			continue
		}

		option.defaultValue = reflect.ValueOf(option.value.Interface())
	}
}

func (g *Group) eachGroup(f func(*Group)) {
	f(g)

	for _, gg := range g.groups {
		gg.eachGroup(f)
	}
}

func (g *Group) scanStruct(realval reflect.Value, sfield *reflect.StructField, handler scanHandler) error {
	stype := realval.Type()

	if sfield != nil {
		if ok, err := handler(realval, sfield); err != nil {
			return err
		} else if ok {
			return nil
		}
	}

	for i := 0; i < stype.NumField(); i++ {
		field := stype.Field(i)

		// PkgName is set only for non-exported fields, which we ignore
		if field.PkgPath != "" {
			continue
		}

		mtag := newMultiTag(string(field.Tag))

		// Skip fields with the no-flag tag
		if mtag.Get("no-flag") != "" {
			continue
		}

		// Dive deep into structs or pointers to structs
		kind := field.Type.Kind()
		fld := realval.Field(i)

		if kind == reflect.Struct {
			if err := g.scanStruct(fld, &field, handler); err != nil {
				return err
			}
		} else if kind == reflect.Ptr && field.Type.Elem().Kind() == reflect.Struct && !fld.IsNil() {
			if err := g.scanStruct(reflect.Indirect(fld), &field, handler); err != nil {
				return err
			}
		}

		longname := mtag.Get("long")
		shortname := mtag.Get("short")

		// Need at least either a short or long name
		if longname == "" && shortname == "" {
			continue
		}

		short := rune(0)
		rc := utf8.RuneCountInString(shortname)

		if rc > 1 {
			return newErrorf(ErrShortNameTooLong,
				"short names can only be 1 character long, not `%s'",
				shortname)

		} else if rc == 1 {
			short, _ = utf8.DecodeRuneInString(shortname)
		}

		description := mtag.Get("description")
		def := mtag.GetMany("default")
		optionalValue := mtag.GetMany("optional-value")
		valueName := mtag.Get("value-name")
		defaultMask := mtag.Get("default-mask")
		ininame := mtag.Get("ini-name")

		optional := (mtag.Get("optional") != "")
		required := (mtag.Get("required") != "")

		option := &Option{
			Description:      description,
			ShortName:        short,
			LongName:         longname,
			Default:          def,
			OptionalArgument: optional,
			OptionalValue:    optionalValue,
			Required:         required,
			ValueName:        valueName,
			DefaultMask:      defaultMask,
			IniName:          ininame,

			field: field,
			value: realval.Field(i),
			tag:   mtag,
		}

		g.options = append(g.options, option)
	}

	return nil
}

func (g *Group) scanSubGroupHandler(realval reflect.Value, sfield *reflect.StructField) (bool, error) {
	mtag := newMultiTag(string(sfield.Tag))

	subgroup := mtag.Get("group")

	if len(subgroup) != 0 {
		ptrval := reflect.NewAt(realval.Type(), unsafe.Pointer(realval.UnsafeAddr()))
		description := mtag.Get("description")

		if _, err := g.AddGroup(subgroup, description, ptrval.Interface()); err != nil {
			return true, err
		}

		return true, nil
	}

	return false, nil
}

func (g *Group) scanType(handler scanHandler) error {
	// Get all the public fields in the data struct
	ptrval := reflect.ValueOf(g.data)

	if ptrval.Type().Kind() != reflect.Ptr {
		panic(ErrNotPointerToStruct)
	}

	stype := ptrval.Type().Elem()

	if stype.Kind() != reflect.Struct {
		panic(ErrNotPointerToStruct)
	}

	realval := reflect.Indirect(ptrval)

	return g.scanStruct(realval, nil, handler)
}

func (g *Group) scan() error {
	return g.scanType(g.scanSubGroupHandler)
}

func (g *Group) groupByName(name string) *Group {
	if len(name) == 0 {
		return g
	}

	return g.Find(name)
}
<commit_msg>Initialize substruct pointers automatically when scanning<commit_after>package flags

import (
	"reflect"
	"unicode/utf8"
	"unsafe"
)

type scanHandler func(reflect.Value, *reflect.StructField) (bool, error)

func newGroup(shortDescription string, longDescription string, data interface{}) *Group {
	return &Group{
		ShortDescription: shortDescription,
		LongDescription:  longDescription,

		data: data,
	}
}

func (g *Group) optionByName(name string, namematch func(*Option, string) bool) *Option {
	prio := 0
	var retopt *Option

	for _, opt := range g.options {
		if namematch != nil && namematch(opt, name) && prio < 4 {
			retopt = opt
			prio = 4
		}

		if name == opt.field.Name && prio < 3 {
			retopt = opt
			prio = 3
		}

		if name == opt.LongName && prio < 2 {
			retopt = opt
			prio = 2
		}

		if opt.ShortName != 0 && name == string(opt.ShortName) && prio < 1 {
			retopt = opt
			prio = 1
		}
	}

	return retopt
}

func (g *Group) storeDefaults() {
	for _, option := range g.options {
		// First. empty out the value
		if len(option.Default) > 0 {
			option.clear()
		}

		for _, d := range option.Default {
			option.set(&d)
		}

		if !option.value.CanSet() {
			continue
		}

		option.defaultValue = reflect.ValueOf(option.value.Interface())
	}
}

func (g *Group) eachGroup(f func(*Group)) {
	f(g)

	for _, gg := range g.groups {
		gg.eachGroup(f)
	}
}

func (g *Group) scanStruct(realval reflect.Value, sfield *reflect.StructField, handler scanHandler) error {
	stype := realval.Type()

	if sfield != nil {
		if ok, err := handler(realval, sfield); err != nil {
			return err
		} else if ok {
			return nil
		}
	}

	for i := 0; i < stype.NumField(); i++ {
		field := stype.Field(i)

		// PkgName is set only for non-exported fields, which we ignore
		if field.PkgPath != "" {
			continue
		}

		mtag := newMultiTag(string(field.Tag))

		// Skip fields with the no-flag tag
		if mtag.Get("no-flag") != "" {
			continue
		}

		// Dive deep into structs or pointers to structs
		kind := field.Type.Kind()
		fld := realval.Field(i)

		if kind == reflect.Struct {
			if err := g.scanStruct(fld, &field, handler); err != nil {
				return err
			}
		} else if kind == reflect.Ptr && field.Type.Elem().Kind() == reflect.Struct {
			if fld.IsNil() {
				fld.Set(reflect.New(fld.Type().Elem()))
			}

			if err := g.scanStruct(reflect.Indirect(fld), &field, handler); err != nil {
				return err
			}
		}

		longname := mtag.Get("long")
		shortname := mtag.Get("short")

		// Need at least either a short or long name
		if longname == "" && shortname == "" {
			continue
		}

		short := rune(0)
		rc := utf8.RuneCountInString(shortname)

		if rc > 1 {
			return newErrorf(ErrShortNameTooLong,
				"short names can only be 1 character long, not `%s'",
				shortname)

		} else if rc == 1 {
			short, _ = utf8.DecodeRuneInString(shortname)
		}

		description := mtag.Get("description")
		def := mtag.GetMany("default")
		optionalValue := mtag.GetMany("optional-value")
		valueName := mtag.Get("value-name")
		defaultMask := mtag.Get("default-mask")
		ininame := mtag.Get("ini-name")

		optional := (mtag.Get("optional") != "")
		required := (mtag.Get("required") != "")

		option := &Option{
			Description:      description,
			ShortName:        short,
			LongName:         longname,
			Default:          def,
			OptionalArgument: optional,
			OptionalValue:    optionalValue,
			Required:         required,
			ValueName:        valueName,
			DefaultMask:      defaultMask,
			IniName:          ininame,

			field: field,
			value: realval.Field(i),
			tag:   mtag,
		}

		g.options = append(g.options, option)
	}

	return nil
}

func (g *Group) scanSubGroupHandler(realval reflect.Value, sfield *reflect.StructField) (bool, error) {
	mtag := newMultiTag(string(sfield.Tag))

	subgroup := mtag.Get("group")

	if len(subgroup) != 0 {
		ptrval := reflect.NewAt(realval.Type(), unsafe.Pointer(realval.UnsafeAddr()))
		description := mtag.Get("description")

		if _, err := g.AddGroup(subgroup, description, ptrval.Interface()); err != nil {
			return true, err
		}

		return true, nil
	}

	return false, nil
}

func (g *Group) scanType(handler scanHandler) error {
	// Get all the public fields in the data struct
	ptrval := reflect.ValueOf(g.data)

	if ptrval.Type().Kind() != reflect.Ptr {
		panic(ErrNotPointerToStruct)
	}

	stype := ptrval.Type().Elem()

	if stype.Kind() != reflect.Struct {
		panic(ErrNotPointerToStruct)
	}

	realval := reflect.Indirect(ptrval)

	return g.scanStruct(realval, nil, handler)
}

func (g *Group) scan() error {
	return g.scanType(g.scanSubGroupHandler)
}

func (g *Group) groupByName(name string) *Group {
	if len(name) == 0 {
		return g
	}

	return g.Find(name)
}
<|endoftext|>