<commit_before>package plg_video_transcoder

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/gorilla/mux"
	. "github.com/mickael-kerjean/filestash/server/common"
	. "github.com/mickael-kerjean/filestash/server/middleware"
	"io"
	"math"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"
	"time"
)

const (
	HLS_SEGMENT_LENGTH = 10
	CLEAR_CACHE_AFTER = 12
	VideoCachePath = "data/cache/video/"
)

func init(){
	ffmpegIsInstalled := false
	ffprobeIsInstalled := false
	if _, err := exec.LookPath("ffmpeg"); err == nil {
		ffmpegIsInstalled = true
	}
	if _, err := exec.LookPath("ffprobe"); err == nil {
		ffprobeIsInstalled = true
	}
	plugin_enable := func() bool {
		return Config.Get("features.video.enable_transcoder").Schema(func(f *FormElement) *FormElement {
			if f == nil {
				f = &FormElement{}
			}
			f.Name = "enable_transcoder"
			f.Type = "boolean"
			f.Description = "Enable/Disable on demand video transcoding. The transcoder"
			f.Default = true
			if ffmpegIsInstalled == false || ffprobeIsInstalled == false {
				f.Default = false
			}
			return f
		}).Bool()
	}
	if plugin_enable() == false {
		return
	} else if ffmpegIsInstalled == false {
		Log.Warning("[plugin video transcoder] ffmpeg needs to be installed")
		return
	} else if ffprobeIsInstalled == false {
		Log.Warning("[plugin video transcoder] ffprobe needs to be installed")
		return
	}

	cachePath := filepath.Join(GetCurrentDir(), VideoCachePath)
	os.RemoveAll(cachePath)
	os.MkdirAll(cachePath, os.ModePerm)

	Hooks.Register.ProcessFileContentBeforeSend(hls_playlist)
	Hooks.Register.HttpEndpoint(func(r *mux.Router, app *App) error {
		r.PathPrefix("/hls/hls_{segment}.ts").Handler(NewMiddlewareChain(
			hls_transcode,
			[]Middleware{ SecureHeaders },
			*app,
		)).Methods("GET")
		return nil
	})

	Hooks.Register.HttpEndpoint(func(r *mux.Router, app *App) error {
		r.HandleFunc(OverrideVideoSourceMapper, func(res http.ResponseWriter, req *http.Request) {
			res.Header().Set("Content-Type", "application/javascript")
			res.Write([]byte(`
                window.overrides["video-map-sources"] = function(sources){
                    return sources.map(function(source){
                        if(source.type == "video/mp4") return source;
                        else if(source.type == "video/webm") return source;
                        else if(source.type == "application/ogg") return source;
                        source.src = source.src + "&transcode=hls";
                        source.type = "application/x-mpegURL";
                        return source;
                    })
                }
`))
		})
		return nil
	})
}

func hls_playlist(reader io.ReadCloser, ctx *App, res *http.ResponseWriter, req *http.Request) (io.ReadCloser, error) {
	query := req.URL.Query()
	if query.Get("transcode") != "hls" {
		return reader, nil
	}
	path := query.Get("path")
	if strings.HasPrefix(GetMimeType(path), "video/") == false {
		return reader, nil
	}

	cacheName := "vid_" + GenerateID(ctx) + "_" + QuickHash(path, 10) + ".dat"
	cachePath := filepath.Join(
		GetCurrentDir(),
		VideoCachePath,
		cacheName,
	)
	f, err := os.OpenFile(cachePath, os.O_CREATE | os.O_RDWR, os.ModePerm)
	if err != nil {
		Log.Stdout("ERR %+v", err)
		return reader, err
	}
	io.Copy(f, reader)
	reader.Close()
	f.Close()
	time.AfterFunc(CLEAR_CACHE_AFTER * time.Hour, func() { os.Remove(cachePath) })

	p, err := ffprobe(cachePath)
	if err != nil {
		return reader, err
	}

	var response string
	var i int
	response =  "#EXTM3U\n"
	response += "#EXT-X-VERSION:3\n"
	response += "#EXT-X-MEDIA-SEQUENCE:0\n"
	response += "#EXT-X-ALLOW-CACHE:YES\n"
	response += fmt.Sprintf("#EXT-X-TARGETDURATION:%d\n", HLS_SEGMENT_LENGTH)
	for i=0; i< int(p.Format.Duration) / HLS_SEGMENT_LENGTH; i++ {
		response += fmt.Sprintf("#EXTINF:%d.0000, nodesc\n", HLS_SEGMENT_LENGTH)
		response += fmt.Sprintf("/hls/hls_%d.ts?path=%s\n", i, cacheName)
	}
	if md := math.Mod(p.Format.Duration, HLS_SEGMENT_LENGTH); md > 0 {
		response += fmt.Sprintf("#EXTINF:%.4f, nodesc\n", md)
		response += fmt.Sprintf("/hls/hls_%d.ts?path=%s\n", i, cacheName)
	}
	response += "#EXT-X-ENDLIST\n"
	(*res).Header().Set("Content-Type", "application/x-mpegURL")
	return NewReadCloserFromBytes([]byte(response)), nil
}

func hls_transcode(ctx App, res http.ResponseWriter, req *http.Request) {
	segmentNumber, err := strconv.Atoi(mux.Vars(req)["segment"])
	if err != nil {
		Log.Info("[plugin hls] invalid segment request '%s'", mux.Vars(req)["segment"])
		res.WriteHeader(http.StatusBadRequest)
		return
	}
	startTime := segmentNumber * HLS_SEGMENT_LENGTH
	cachePath := filepath.Join(
		GetCurrentDir(),
		VideoCachePath,
		req.URL.Query().Get("path"),
	)
	if _, err := os.Stat(cachePath); os.IsNotExist(err) {
		Log.Info("[plugin hls]: invalid video")
		res.WriteHeader(http.StatusServiceUnavailable)
		return
	}

	cmd := exec.Command("ffmpeg", []string{
		"-timelimit", "30",
		"-ss", fmt.Sprintf("%d.00", startTime),
		"-i", cachePath,
		"-t", fmt.Sprintf("%d.00", HLS_SEGMENT_LENGTH),
		"-vf", fmt.Sprintf("scale=-2:%d", 720),
		"-vcodec", "libx264",
		"-preset", "veryfast",
		"-acodec", "aac",
		"-pix_fmt", "yuv420p",
		"-x264opts:0", "subme=0:me_range=4:rc_lookahead=10:me=dia:no_chroma_me:8x8dct=0:partitions=none",
		"-force_key_frames", fmt.Sprintf("expr:gte(t,n_forced*%d.000)", HLS_SEGMENT_LENGTH),
		"-f", "ssegment",
		"-segment_time", fmt.Sprintf("%d.00", HLS_SEGMENT_LENGTH),
		"-segment_start_number", fmt.Sprintf("%d", segmentNumber),
		"-initial_offset", fmt.Sprintf("%d.00", startTime),
		"-vsync", "2",
		"pipe:out%03d.ts",
	}...)

	var str bytes.Buffer
	cmd.Stdout = res
	cmd.Stderr = &str
	_ = cmd.Run()
}

type FFProbeData struct {
	Format struct {
		Duration float64 `json:"duration,string"`
		BitRate int `json:"bit_rate,string"`
	} `json: "format"`
	Streams []struct {
		CodecType string `json:"codec_type"`
		CodecName string `json:"codec_name"`
		PixelFormat string `json:"pix_fmt"`
	} `json:"streams"`
}

func ffprobe(videoPath string) (FFProbeData, error) {
	var stream bytes.Buffer
	var probe FFProbeData

	cmd := exec.Command(
		"ffprobe", strings.Split(fmt.Sprintf(
			"-v quiet -print_format json -show_format -show_streams %s",
			videoPath,
		), " ")...
	)
	cmd.Stdout = &stream
	if err := cmd.Run(); err != nil {
		return probe, nil
	}
	cmd.Run()
	if err := json.Unmarshal([]byte(stream.String()), &probe); err != nil {
		return probe, err
	}
	return probe, nil
}
<commit_msg>feature (transcoding): video transcoding blacklist<commit_after>package plg_video_transcoder

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/gorilla/mux"
	. "github.com/mickael-kerjean/filestash/server/common"
	. "github.com/mickael-kerjean/filestash/server/middleware"
	"io"
	"math"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"
	"time"
)

const (
	HLS_SEGMENT_LENGTH = 10
	CLEAR_CACHE_AFTER = 12
	VideoCachePath = "data/cache/video/"
)

func init(){
	ffmpegIsInstalled := false
	ffprobeIsInstalled := false
	if _, err := exec.LookPath("ffmpeg"); err == nil {
		ffmpegIsInstalled = true
	}
	if _, err := exec.LookPath("ffprobe"); err == nil {
		ffprobeIsInstalled = true
	}
	plugin_enable := func() bool {
		return Config.Get("features.video.enable_transcoder").Schema(func(f *FormElement) *FormElement {
			if f == nil {
				f = &FormElement{}
			}
			f.Name = "enable_transcoder"
			f.Type = "enable"
			f.Target = []string{"transcoding_blacklist_format"}
			f.Description = "Enable/Disable on demand video transcoding. The transcoder"
			f.Default = true
			if ffmpegIsInstalled == false || ffprobeIsInstalled == false {
				f.Default = false
			}
			return f
		}).Bool()
	}

	blacklist_format := func() string {
		return Config.Get("features.video.blacklist_format").Schema(func(f *FormElement) *FormElement {
			if f == nil {
				f = &FormElement{}
			}
			f.Id = "transcoding_blacklist_format"
			f.Name = "blacklist_format"
			f.Type = "text"
			f.Description = "Video format that won't be transcoded"
			f.Default = os.Getenv("FEATURE_TRANSCODING_VIDEO_BLACKLIST")
			if f.Default != "" {
				f.Placeholder = fmt.Sprintf("Default: '%s'", f.Default)
			}
			return f
		}).String()
	}

	if plugin_enable() == false {
		return
	} else if ffmpegIsInstalled == false {
		Log.Warning("[plugin video transcoder] ffmpeg needs to be installed")
		return
	} else if ffprobeIsInstalled == false {
		Log.Warning("[plugin video transcoder] ffprobe needs to be installed")
		return
	}

	cachePath := filepath.Join(GetCurrentDir(), VideoCachePath)
	os.RemoveAll(cachePath)
	os.MkdirAll(cachePath, os.ModePerm)

	Hooks.Register.ProcessFileContentBeforeSend(hls_playlist)
	Hooks.Register.HttpEndpoint(func(r *mux.Router, app *App) error {
		r.PathPrefix("/hls/hls_{segment}.ts").Handler(NewMiddlewareChain(
			hls_transcode,
			[]Middleware{ SecureHeaders },
			*app,
		)).Methods("GET")
		return nil
	})

	Hooks.Register.HttpEndpoint(func(r *mux.Router, app *App) error {
		r.HandleFunc(OverrideVideoSourceMapper, func(res http.ResponseWriter, req *http.Request) {
			res.Header().Set("Content-Type", "application/javascript")
			res.Write([]byte(`window.overrides["video-map-sources"] = function(sources){`))
			res.Write([]byte(`    return sources.map(function(source){`))

			blacklists := strings.Split(blacklist_format(), ",")
			for i:=0; i<len(blacklists); i++ {
				blacklists[i] = strings.TrimSpace(blacklists[i])
				res.Write([]byte(fmt.Sprintf(`if(source.type == "%s"){ return source; } `, GetMimeType("." + blacklists[i]))))
			}
			res.Write([]byte(`        source.src = source.src + "&transcode=hls";`))
			res.Write([]byte(`        source.type = "application/x-mpegURL";`))
			res.Write([]byte(`        return source;`))
			res.Write([]byte(`    })`))
			res.Write([]byte(`}`))
		})
		return nil
	})
}

func hls_playlist(reader io.ReadCloser, ctx *App, res *http.ResponseWriter, req *http.Request) (io.ReadCloser, error) {
	query := req.URL.Query()
	if query.Get("transcode") != "hls" {
		return reader, nil
	}
	path := query.Get("path")
	if strings.HasPrefix(GetMimeType(path), "video/") == false {
		return reader, nil
	}

	cacheName := "vid_" + GenerateID(ctx) + "_" + QuickHash(path, 10) + ".dat"
	cachePath := filepath.Join(
		GetCurrentDir(),
		VideoCachePath,
		cacheName,
	)
	f, err := os.OpenFile(cachePath, os.O_CREATE | os.O_RDWR, os.ModePerm)
	if err != nil {
		Log.Stdout("ERR %+v", err)
		return reader, err
	}
	io.Copy(f, reader)
	reader.Close()
	f.Close()
	time.AfterFunc(CLEAR_CACHE_AFTER * time.Hour, func() { os.Remove(cachePath) })

	p, err := ffprobe(cachePath)
	if err != nil {
		return reader, err
	}

	var response string
	var i int
	response =  "#EXTM3U\n"
	response += "#EXT-X-VERSION:3\n"
	response += "#EXT-X-MEDIA-SEQUENCE:0\n"
	response += "#EXT-X-ALLOW-CACHE:YES\n"
	response += fmt.Sprintf("#EXT-X-TARGETDURATION:%d\n", HLS_SEGMENT_LENGTH)
	for i=0; i< int(p.Format.Duration) / HLS_SEGMENT_LENGTH; i++ {
		response += fmt.Sprintf("#EXTINF:%d.0000, nodesc\n", HLS_SEGMENT_LENGTH)
		response += fmt.Sprintf("/hls/hls_%d.ts?path=%s\n", i, cacheName)
	}
	if md := math.Mod(p.Format.Duration, HLS_SEGMENT_LENGTH); md > 0 {
		response += fmt.Sprintf("#EXTINF:%.4f, nodesc\n", md)
		response += fmt.Sprintf("/hls/hls_%d.ts?path=%s\n", i, cacheName)
	}
	response += "#EXT-X-ENDLIST\n"
	(*res).Header().Set("Content-Type", "application/x-mpegURL")
	return NewReadCloserFromBytes([]byte(response)), nil
}

func hls_transcode(ctx App, res http.ResponseWriter, req *http.Request) {
	segmentNumber, err := strconv.Atoi(mux.Vars(req)["segment"])
	if err != nil {
		Log.Info("[plugin hls] invalid segment request '%s'", mux.Vars(req)["segment"])
		res.WriteHeader(http.StatusBadRequest)
		return
	}
	startTime := segmentNumber * HLS_SEGMENT_LENGTH
	cachePath := filepath.Join(
		GetCurrentDir(),
		VideoCachePath,
		req.URL.Query().Get("path"),
	)
	if _, err := os.Stat(cachePath); os.IsNotExist(err) {
		Log.Info("[plugin hls]: invalid video")
		res.WriteHeader(http.StatusServiceUnavailable)
		return
	}

	cmd := exec.Command("ffmpeg", []string{
		"-timelimit", "30",
		"-ss", fmt.Sprintf("%d.00", startTime),
		"-i", cachePath,
		"-t", fmt.Sprintf("%d.00", HLS_SEGMENT_LENGTH),
		"-vf", fmt.Sprintf("scale=-2:%d", 720),
		"-vcodec", "libx264",
		"-preset", "veryfast",
		"-acodec", "aac",
		"-pix_fmt", "yuv420p",
		"-x264opts:0", "subme=0:me_range=4:rc_lookahead=10:me=dia:no_chroma_me:8x8dct=0:partitions=none",
		"-force_key_frames", fmt.Sprintf("expr:gte(t,n_forced*%d.000)", HLS_SEGMENT_LENGTH),
		"-f", "ssegment",
		"-segment_time", fmt.Sprintf("%d.00", HLS_SEGMENT_LENGTH),
		"-segment_start_number", fmt.Sprintf("%d", segmentNumber),
		"-initial_offset", fmt.Sprintf("%d.00", startTime),
		"-vsync", "2",
		"pipe:out%03d.ts",
	}...)

	var str bytes.Buffer
	cmd.Stdout = res
	cmd.Stderr = &str
	_ = cmd.Run()
}

type FFProbeData struct {
	Format struct {
		Duration float64 `json:"duration,string"`
		BitRate int `json:"bit_rate,string"`
	} `json: "format"`
	Streams []struct {
		CodecType string `json:"codec_type"`
		CodecName string `json:"codec_name"`
		PixelFormat string `json:"pix_fmt"`
	} `json:"streams"`
}

func ffprobe(videoPath string) (FFProbeData, error) {
	var stream bytes.Buffer
	var probe FFProbeData

	cmd := exec.Command(
		"ffprobe", strings.Split(fmt.Sprintf(
			"-v quiet -print_format json -show_format -show_streams %s",
			videoPath,
		), " ")...
	)
	cmd.Stdout = &stream
	if err := cmd.Run(); err != nil {
		return probe, nil
	}
	cmd.Run()
	if err := json.Unmarshal([]byte(stream.String()), &probe); err != nil {
		return probe, err
	}
	return probe, nil
}
<|endoftext|>


<commit_before>// Copyright Project Harbor 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 native

import (
	"errors"

	"github.com/goharbor/harbor/src/common/utils/log"
	adp "github.com/goharbor/harbor/src/replication/adapter"
	"github.com/goharbor/harbor/src/replication/model"
)

const registryTypeNative model.RegistryType = "native"

func init() {
	if err := adp.RegisterFactory(registryTypeNative, func(registry *model.Registry) (adp.Adapter, error) {
		reg, err := adp.NewDefaultImageRegistry(registry)
		if err != nil {
			return nil, err
		}
		return &native{
			registry:             registry,
			DefaultImageRegistry: reg,
		}, nil
	}); err != nil {
		log.Errorf("failed to register factory for %s: %v", registryTypeNative, err)
		return
	}
	log.Infof("the factory for adapter %s registered", registryTypeNative)
}

type native struct {
	*adp.DefaultImageRegistry
	registry *model.Registry
}

var _ adp.Adapter = native{}

func (native) Info() (info *model.RegistryInfo, err error) {
	return &model.RegistryInfo{
		Type: registryTypeNative,
		SupportedResourceTypes: []model.ResourceType{
			model.ResourceTypeRepository,
		},
		SupportedResourceFilters: []*model.FilterStyle{
			{
				Type:  model.FilterTypeName,
				Style: model.FilterStyleTypeText,
			},
			{
				Type:  model.FilterTypeTag,
				Style: model.FilterStyleTypeText,
			},
		},
		SupportedTriggers: []model.TriggerType{
			model.TriggerTypeManual,
			model.TriggerTypeScheduled,
		},
	}, nil
}

// ConvertResourceMetadata convert src to dst resource
func (native) ConvertResourceMetadata(metadata *model.ResourceMetadata, namespace *model.Namespace) (*model.ResourceMetadata, error) {
	if metadata == nil {
		return nil, errors.New("the metadata cannot be null")
	}

	var result = &model.ResourceMetadata{
		Namespace:  metadata.Namespace,
		Repository: metadata.Repository,
		Vtags:      metadata.Vtags,
	}

	// if dest namespace is set, rename metadata namespace
	if namespace != nil {
		result.Namespace = namespace
	}

	result.Repository = &model.Repository{Name: result.GetResourceName()}
	result.Namespace = nil

	return result, nil
}

// PrepareForPush nothing need to do.
func (native) PrepareForPush(*model.Resource) error { return nil }

// ListNamespaces native registry no namespaces, so list empty array.
func (native) ListNamespaces(*model.NamespaceQuery) ([]*model.Namespace, error) {
	return []*model.Namespace{}, nil
}
<commit_msg>change to testable.<commit_after>// Copyright Project Harbor 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 native

import (
	"errors"

	"github.com/goharbor/harbor/src/common/utils/log"
	adp "github.com/goharbor/harbor/src/replication/adapter"
	"github.com/goharbor/harbor/src/replication/model"
)

const registryTypeNative model.RegistryType = "native"

func init() {
	if err := adp.RegisterFactory(registryTypeNative, func(registry *model.Registry) (adp.Adapter, error) {
		return newAdapter(registry)
	}); err != nil {
		log.Errorf("failed to register factory for %s: %v", registryTypeNative, err)
		return
	}
	log.Infof("the factory for adapter %s registered", registryTypeNative)
}

func newAdapter(registry *model.Registry) (*native, error) {
	reg, err := adp.NewDefaultImageRegistry(registry)
	if err != nil {
		return nil, err
	}
	return &native{
		registry:             registry,
		DefaultImageRegistry: reg,
	}, nil
}

type native struct {
	*adp.DefaultImageRegistry
	registry *model.Registry
}

var _ adp.Adapter = native{}

func (native) Info() (info *model.RegistryInfo, err error) {
	return &model.RegistryInfo{
		Type: registryTypeNative,
		SupportedResourceTypes: []model.ResourceType{
			model.ResourceTypeRepository,
		},
		SupportedResourceFilters: []*model.FilterStyle{
			{
				Type:  model.FilterTypeName,
				Style: model.FilterStyleTypeText,
			},
			{
				Type:  model.FilterTypeTag,
				Style: model.FilterStyleTypeText,
			},
		},
		SupportedTriggers: []model.TriggerType{
			model.TriggerTypeManual,
			model.TriggerTypeScheduled,
		},
	}, nil
}

// ConvertResourceMetadata convert src to dst resource
func (native) ConvertResourceMetadata(metadata *model.ResourceMetadata, namespace *model.Namespace) (*model.ResourceMetadata, error) {
	if metadata == nil {
		return nil, errors.New("the metadata cannot be null")
	}

	var result = &model.ResourceMetadata{
		Namespace:  metadata.Namespace,
		Repository: metadata.Repository,
		Vtags:      metadata.Vtags,
	}

	// if dest namespace is set, rename metadata namespace
	if namespace != nil {
		result.Namespace = namespace
	}

	result.Repository = &model.Repository{Name: result.GetResourceName()}
	result.Namespace = nil

	return result, nil
}

// PrepareForPush nothing need to do.
func (native) PrepareForPush(*model.Resource) error { return nil }

// ListNamespaces native registry no namespaces, so list empty array.
func (native) ListNamespaces(*model.NamespaceQuery) ([]*model.Namespace, error) {
	return []*model.Namespace{}, nil
}
<|endoftext|>


<commit_before>package flags

import (
	"fmt"
	"path/filepath"
	"reflect"
	"sort"
	"strings"
	"unicode/utf8"
)

// Completion is a type containing information of a completion.
type Completion struct {
	// The completed item
	Item string

	// A description of the completed item (optional)
	Description string
}

type completions []Completion

func (c completions) Len() int {
	return len(c)
}

func (c completions) Less(i, j int) bool {
	return c[i].Item < c[j].Item
}

func (c completions) Swap(i, j int) {
	c[i], c[j] = c[j], c[i]
}

// Completer is an interface which can be implemented by types
// to provide custom command line argument completion.
type Completer interface {
	// Complete receives a prefix representing a (partial) value
	// for its type and should provide a list of possible valid
	// completions.
	Complete(match string) []Completion
}

type completion struct {
	parser *Parser

	ShowDescriptions bool `short:"d" long:"show-descriptions" description:"Show descriptions next to completion items"`
}

// Filename is a string alias which provides filename completion.
type Filename string

func completionsWithoutDescriptions(items []string) []Completion {
	ret := make([]Completion, len(items))

	for i, v := range items {
		ret[i].Item = v
	}

	return ret
}

// Complete returns a list of existing files with the given
// prefix.
func (f *Filename) Complete(match string) []Completion {
	ret, _ := filepath.Glob(match + "*")
	return completionsWithoutDescriptions(ret)
}

func (c *completion) skipPositional(s *parseState, n int) {
	if n >= len(s.positional) {
		s.positional = nil
	} else {
		s.positional = s.positional[n:]
	}
}

func (c *completion) completeOptionNames(names map[string]*Option, prefix string, match string) []Completion {
	n := make([]Completion, 0, len(names))

	for k, opt := range names {
		if strings.HasPrefix(k, match) {
			n = append(n, Completion{
				Item:        prefix + k,
				Description: opt.Description,
			})
		}
	}

	return n
}

func (c *completion) completeLongNames(s *parseState, prefix string, match string) []Completion {
	return c.completeOptionNames(s.lookup.longNames, prefix, match)
}

func (c *completion) completeShortNames(s *parseState, prefix string, match string) []Completion {
	if len(match) != 0 {
		return []Completion{
			Completion{
				Item: prefix + match,
			},
		}
	}

	return c.completeOptionNames(s.lookup.shortNames, prefix, match)
}

func (c *completion) completeCommands(s *parseState, match string) []Completion {
	n := make([]Completion, 0, len(s.command.commands))

	for _, cmd := range s.command.commands {
		if cmd.data != c && strings.HasPrefix(cmd.Name, match) {
			n = append(n, Completion{
				Item:        cmd.Name,
				Description: cmd.ShortDescription,
			})
		}
	}

	return n
}

func (c *completion) completeValue(value reflect.Value, prefix string, match string) []Completion {
	// For slices/arrays in positional args (that take the rest of the args),
	// complete based on the element type.
	if typ := value.Type(); typ.Kind() == reflect.Array || typ.Kind() == reflect.Slice {
		value = reflect.New(typ.Elem())
	}

	i := value.Interface()

	var ret []Completion

	if cmp, ok := i.(Completer); ok {
		ret = cmp.Complete(match)
	} else if value.CanAddr() {
		if cmp, ok = value.Addr().Interface().(Completer); ok {
			ret = cmp.Complete(match)
		}
	}

	for i, v := range ret {
		ret[i].Item = prefix + v.Item
	}

	return ret
}

func (c *completion) complete(args []string) []Completion {
	if len(args) == 0 {
		args = []string{""}
	}

	s := &parseState{
		args: args,
	}

	c.parser.fillParseState(s)

	var opt *Option

	for len(s.args) > 1 {
		arg := s.pop()

		if (c.parser.Options&PassDoubleDash) != None && arg == "--" {
			opt = nil
			c.skipPositional(s, len(s.args)-1)

			break
		}

		if argumentIsOption(arg) {
			prefix, optname, islong := stripOptionPrefix(arg)
			optname, _, argument := splitOption(prefix, optname, islong)

			if argument == nil {
				var o *Option
				canarg := true

				if islong {
					o = s.lookup.longNames[optname]
				} else {
					for i, r := range optname {
						sname := string(r)
						o = s.lookup.shortNames[sname]

						if o == nil {
							break
						}

						if i == 0 && o.canArgument() && len(optname) != len(sname) {
							canarg = false
							break
						}
					}
				}

				if o == nil && (c.parser.Options&PassAfterNonOption) != None {
					opt = nil
					c.skipPositional(s, len(s.args)-1)

					break
				} else if o != nil && o.canArgument() && !o.OptionalArgument && canarg {
					if len(s.args) > 1 {
						s.pop()
					} else {
						opt = o
					}
				}
			}
		} else {
			if len(s.positional) > 0 {
				if t := s.positional[0].value.Type(); t.Kind() != reflect.Array && t.Kind() != reflect.Slice {
					// Don't advance beyond a slice/array positional (because
					// they consume all subsequent args).
					s.positional = s.positional[1:]
				}
			} else if cmd, ok := s.lookup.commands[arg]; ok {
				cmd.fillParseState(s)
			}

			opt = nil
		}
	}

	lastarg := s.args[len(s.args)-1]
	var ret []Completion

	if opt != nil {
		// Completion for the argument of 'opt'
		ret = c.completeValue(opt.value, "", lastarg)
	} else if argumentIsOption(lastarg) {
		// Complete the option
		prefix, optname, islong := stripOptionPrefix(lastarg)
		optname, split, argument := splitOption(prefix, optname, islong)

		if argument == nil && !islong {
			rname, n := utf8.DecodeRuneInString(optname)
			sname := string(rname)

			if opt := s.lookup.shortNames[sname]; opt != nil && opt.canArgument() {
				ret = c.completeValue(opt.value, prefix+sname, optname[n:])
			} else {
				ret = c.completeShortNames(s, prefix, optname)
			}
		} else if argument != nil {
			if islong {
				opt = s.lookup.longNames[optname]
			} else {
				opt = s.lookup.shortNames[optname]
			}

			if opt != nil {
				ret = c.completeValue(opt.value, prefix+optname+split, *argument)
			}
		} else if islong {
			ret = c.completeLongNames(s, prefix, optname)
		} else {
			ret = c.completeShortNames(s, prefix, optname)
		}
	} else if len(s.positional) > 0 {
		// Complete for positional argument
		ret = c.completeValue(s.positional[0].value, "", lastarg)
	} else if len(s.command.commands) > 0 {
		// Complete for command
		ret = c.completeCommands(s, lastarg)
	}

	sort.Sort(completions(ret))
	return ret
}

func (c *completion) Execute(args []string) error {
	ret := c.complete(args)

	if c.ShowDescriptions && len(ret) > 1 {
		maxl := 0

		for _, v := range ret {
			if len(v.Item) > maxl {
				maxl = len(v.Item)
			}
		}

		for _, v := range ret {
			fmt.Printf("%s", v.Item)

			if len(v.Description) > 0 {
				fmt.Printf("%s  # %s", strings.Repeat(" ", maxl-len(v.Item)), v.Description)
			}

			fmt.Printf("\n")
		}
	} else {
		for _, v := range ret {
			fmt.Println(v.Item)
		}
	}

	return nil
}
<commit_msg>Move typ outside of the if-block<commit_after>package flags

import (
	"fmt"
	"path/filepath"
	"reflect"
	"sort"
	"strings"
	"unicode/utf8"
)

// Completion is a type containing information of a completion.
type Completion struct {
	// The completed item
	Item string

	// A description of the completed item (optional)
	Description string
}

type completions []Completion

func (c completions) Len() int {
	return len(c)
}

func (c completions) Less(i, j int) bool {
	return c[i].Item < c[j].Item
}

func (c completions) Swap(i, j int) {
	c[i], c[j] = c[j], c[i]
}

// Completer is an interface which can be implemented by types
// to provide custom command line argument completion.
type Completer interface {
	// Complete receives a prefix representing a (partial) value
	// for its type and should provide a list of possible valid
	// completions.
	Complete(match string) []Completion
}

type completion struct {
	parser *Parser

	ShowDescriptions bool `short:"d" long:"show-descriptions" description:"Show descriptions next to completion items"`
}

// Filename is a string alias which provides filename completion.
type Filename string

func completionsWithoutDescriptions(items []string) []Completion {
	ret := make([]Completion, len(items))

	for i, v := range items {
		ret[i].Item = v
	}

	return ret
}

// Complete returns a list of existing files with the given
// prefix.
func (f *Filename) Complete(match string) []Completion {
	ret, _ := filepath.Glob(match + "*")
	return completionsWithoutDescriptions(ret)
}

func (c *completion) skipPositional(s *parseState, n int) {
	if n >= len(s.positional) {
		s.positional = nil
	} else {
		s.positional = s.positional[n:]
	}
}

func (c *completion) completeOptionNames(names map[string]*Option, prefix string, match string) []Completion {
	n := make([]Completion, 0, len(names))

	for k, opt := range names {
		if strings.HasPrefix(k, match) {
			n = append(n, Completion{
				Item:        prefix + k,
				Description: opt.Description,
			})
		}
	}

	return n
}

func (c *completion) completeLongNames(s *parseState, prefix string, match string) []Completion {
	return c.completeOptionNames(s.lookup.longNames, prefix, match)
}

func (c *completion) completeShortNames(s *parseState, prefix string, match string) []Completion {
	if len(match) != 0 {
		return []Completion{
			Completion{
				Item: prefix + match,
			},
		}
	}

	return c.completeOptionNames(s.lookup.shortNames, prefix, match)
}

func (c *completion) completeCommands(s *parseState, match string) []Completion {
	n := make([]Completion, 0, len(s.command.commands))

	for _, cmd := range s.command.commands {
		if cmd.data != c && strings.HasPrefix(cmd.Name, match) {
			n = append(n, Completion{
				Item:        cmd.Name,
				Description: cmd.ShortDescription,
			})
		}
	}

	return n
}

func (c *completion) completeValue(value reflect.Value, prefix string, match string) []Completion {
	// For slices/arrays in positional args (that take the rest of the args),
	// complete based on the element type.
	typ := value.Type()
	if typ.Kind() == reflect.Array || typ.Kind() == reflect.Slice {
		value = reflect.New(typ.Elem())
	}

	i := value.Interface()

	var ret []Completion

	if cmp, ok := i.(Completer); ok {
		ret = cmp.Complete(match)
	} else if value.CanAddr() {
		if cmp, ok = value.Addr().Interface().(Completer); ok {
			ret = cmp.Complete(match)
		}
	}

	for i, v := range ret {
		ret[i].Item = prefix + v.Item
	}

	return ret
}

func (c *completion) complete(args []string) []Completion {
	if len(args) == 0 {
		args = []string{""}
	}

	s := &parseState{
		args: args,
	}

	c.parser.fillParseState(s)

	var opt *Option

	for len(s.args) > 1 {
		arg := s.pop()

		if (c.parser.Options&PassDoubleDash) != None && arg == "--" {
			opt = nil
			c.skipPositional(s, len(s.args)-1)

			break
		}

		if argumentIsOption(arg) {
			prefix, optname, islong := stripOptionPrefix(arg)
			optname, _, argument := splitOption(prefix, optname, islong)

			if argument == nil {
				var o *Option
				canarg := true

				if islong {
					o = s.lookup.longNames[optname]
				} else {
					for i, r := range optname {
						sname := string(r)
						o = s.lookup.shortNames[sname]

						if o == nil {
							break
						}

						if i == 0 && o.canArgument() && len(optname) != len(sname) {
							canarg = false
							break
						}
					}
				}

				if o == nil && (c.parser.Options&PassAfterNonOption) != None {
					opt = nil
					c.skipPositional(s, len(s.args)-1)

					break
				} else if o != nil && o.canArgument() && !o.OptionalArgument && canarg {
					if len(s.args) > 1 {
						s.pop()
					} else {
						opt = o
					}
				}
			}
		} else {
			if len(s.positional) > 0 {
				if t := s.positional[0].value.Type(); t.Kind() != reflect.Array && t.Kind() != reflect.Slice {
					// Don't advance beyond a slice/array positional (because
					// they consume all subsequent args).
					s.positional = s.positional[1:]
				}
			} else if cmd, ok := s.lookup.commands[arg]; ok {
				cmd.fillParseState(s)
			}

			opt = nil
		}
	}

	lastarg := s.args[len(s.args)-1]
	var ret []Completion

	if opt != nil {
		// Completion for the argument of 'opt'
		ret = c.completeValue(opt.value, "", lastarg)
	} else if argumentIsOption(lastarg) {
		// Complete the option
		prefix, optname, islong := stripOptionPrefix(lastarg)
		optname, split, argument := splitOption(prefix, optname, islong)

		if argument == nil && !islong {
			rname, n := utf8.DecodeRuneInString(optname)
			sname := string(rname)

			if opt := s.lookup.shortNames[sname]; opt != nil && opt.canArgument() {
				ret = c.completeValue(opt.value, prefix+sname, optname[n:])
			} else {
				ret = c.completeShortNames(s, prefix, optname)
			}
		} else if argument != nil {
			if islong {
				opt = s.lookup.longNames[optname]
			} else {
				opt = s.lookup.shortNames[optname]
			}

			if opt != nil {
				ret = c.completeValue(opt.value, prefix+optname+split, *argument)
			}
		} else if islong {
			ret = c.completeLongNames(s, prefix, optname)
		} else {
			ret = c.completeShortNames(s, prefix, optname)
		}
	} else if len(s.positional) > 0 {
		// Complete for positional argument
		ret = c.completeValue(s.positional[0].value, "", lastarg)
	} else if len(s.command.commands) > 0 {
		// Complete for command
		ret = c.completeCommands(s, lastarg)
	}

	sort.Sort(completions(ret))
	return ret
}

func (c *completion) Execute(args []string) error {
	ret := c.complete(args)

	if c.ShowDescriptions && len(ret) > 1 {
		maxl := 0

		for _, v := range ret {
			if len(v.Item) > maxl {
				maxl = len(v.Item)
			}
		}

		for _, v := range ret {
			fmt.Printf("%s", v.Item)

			if len(v.Description) > 0 {
				fmt.Printf("%s  # %s", strings.Repeat(" ", maxl-len(v.Item)), v.Description)
			}

			fmt.Printf("\n")
		}
	} else {
		for _, v := range ret {
			fmt.Println(v.Item)
		}
	}

	return nil
}
<|endoftext|>


<commit_before>// Copyright 2016 The Cockroach 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.
//
// Author: Matt Jibson (mjibson@cockroachlabs.com)

package acceptance

import (
	"strings"
	"testing"
)

func TestDockerC(t *testing.T) {
	testDockerSuccess(t, "c", []string{"/bin/sh", "-c", strings.Replace(c, "%v", "3", 1)})
	testDockerFail(t, "c", []string{"/bin/sh", "-c", strings.Replace(c, "%v", "a", 1)})
}

const c = `
set -e
cat > main.c << 'EOF'
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <libpq-fe.h>

int
main(int argc, char **argv)
{
	PGconn *conn;
	PGresult *res;
	const char *paramValues[1];
	int paramLengths[1];
	int paramFormats[1];
	uint32_t binaryIntVal;

	conn = PQconnectdb("");
	if (PQstatus(conn) != CONNECTION_OK) {
		fprintf(stderr, "Connection to database failed: %s", PQerrorMessage(conn));
		exit(1);
	}

	paramValues[0] = "%v";

	// TODO(mjibson): test with binary results
	res = PQexecParams(conn,
		"SELECT 1, 2 > $1, $1",
		1, /* one param */
		NULL, /* let the backend deduce param type */
		paramValues,
		NULL, /* don't need param lengths since text */
		NULL, /* default to all text params */
		0); /* ask for text results */

	if (PQresultStatus(res) != PGRES_TUPLES_OK) {
		fprintf(stderr, "SELECT failed: %s", PQerrorMessage(conn));
		exit(1);
	}

	char *aptr = PQgetvalue(res, 0, 0);
	char *bptr = PQgetvalue(res, 0, 1);
	char *cptr = PQgetvalue(res, 0, 2);

	if (strcmp(aptr, "1") || strcmp(bptr, "f") || strcmp(cptr, "3")) {
		printf("unexpected: %s, %s, %s\n", aptr, bptr, cptr);
		exit(1);
	}

	return 0;
}
EOF
gcc -lpq main.c
./a.out
`
<commit_msg>acceptance: make c example compile on debian gcc<commit_after>// Copyright 2016 The Cockroach 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.
//
// Author: Matt Jibson (mjibson@cockroachlabs.com)

package acceptance

import (
	"strings"
	"testing"
)

func TestDockerC(t *testing.T) {
	testDockerSuccess(t, "c", []string{"/bin/sh", "-c", strings.Replace(c, "%v", "3", 1)})
	testDockerFail(t, "c", []string{"/bin/sh", "-c", strings.Replace(c, "%v", "a", 1)})
}

const c = `
set -e
cat > main.c << 'EOF'
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <libpq-fe.h>

int
main(int argc, char **argv)
{
	PGconn *conn;
	PGresult *res;
	const char *paramValues[1];
	int paramLengths[1];
	int paramFormats[1];
	uint32_t binaryIntVal;

	conn = PQconnectdb("");
	if (PQstatus(conn) != CONNECTION_OK) {
		fprintf(stderr, "Connection to database failed: %s", PQerrorMessage(conn));
		exit(1);
	}

	paramValues[0] = "%v";

	// TODO(mjibson): test with binary results
	res = PQexecParams(conn,
		"SELECT 1, 2 > $1, $1",
		1, /* one param */
		NULL, /* let the backend deduce param type */
		paramValues,
		NULL, /* don't need param lengths since text */
		NULL, /* default to all text params */
		0); /* ask for text results */

	if (PQresultStatus(res) != PGRES_TUPLES_OK) {
		fprintf(stderr, "SELECT failed: %s", PQerrorMessage(conn));
		exit(1);
	}

	char *aptr = PQgetvalue(res, 0, 0);
	char *bptr = PQgetvalue(res, 0, 1);
	char *cptr = PQgetvalue(res, 0, 2);

	if (strcmp(aptr, "1") || strcmp(bptr, "f") || strcmp(cptr, "3")) {
		printf("unexpected: %s, %s, %s\n", aptr, bptr, cptr);
		exit(1);
	}

	return 0;
}
EOF
gcc -std=c99 -I/usr/include/postgresql/ -lpq main.c
./a.out
`
<|endoftext|>


<commit_before>package template

import (
	"encoding/json"
	"errors"
	"fmt"
	"os"
	"strconv"
	"text/template"
	"time"

	consul "github.com/hashicorp/consul/api"
	"github.com/rs/zerolog/log"
)

// funcMap builds the template functions and passes the consulClient where this
// is required.
func funcMap(consulClient *consul.Client) template.FuncMap {
	return template.FuncMap{
		"consulKey":          consulKeyFunc(consulClient),
		"consulKeyExists":    consulKeyExistsFunc(consulClient),
		"consulKeyOrDefault": consulKeyOrDefaultFunc(consulClient),
		"loop":               loop,
		"parseBool":          parseBool,
		"parseFloat":         parseFloat,
		"parseInt":           parseInt,
		"parseJSON":          parseJSON,
		"parseUint":          parseUint,
		"timeNow":            timeNowFunc,
		"timeNowUTC":         timeNowUTCFunc,
		"timeNowTimezone":    timeNowTimezoneFunc(),
		"env":                envFunc(),
	}
}

func consulKeyFunc(consulClient *consul.Client) func(string) (string, error) {
	return func(s string) (string, error) {

		if len(s) == 0 {
			return "", nil
		}

		kv, _, err := consulClient.KV().Get(s, nil)
		if err != nil {
			return "", err
		}

		if kv == nil {
			return "", errors.New("Consul KV not found")
		}

		v := string(kv.Value[:])
		log.Info().Msgf("template/funcs: using Consul KV variable with key %s and value %s",
			s, v)

		return v, nil
	}
}

func consulKeyExistsFunc(consulClient *consul.Client) func(string) (bool, error) {
	return func(s string) (bool, error) {

		if len(s) == 0 {
			return false, nil
		}

		kv, _, err := consulClient.KV().Get(s, nil)
		if err != nil {
			return false, err
		}

		if kv == nil {
			return false, nil
		}

		log.Info().Msgf("template/funcs: found Consul KV variable with key %s", s)

		return true, nil
	}
}

func consulKeyOrDefaultFunc(consulClient *consul.Client) func(string, string) (string, error) {
	return func(s, d string) (string, error) {

		if len(s) == 0 {
			log.Info().Msgf("template/funcs: using default Consul KV variable with value %s", d)
			return d, nil
		}

		kv, _, err := consulClient.KV().Get(s, nil)
		if err != nil {
			return "", err
		}

		if kv == nil {
			log.Info().Msgf("template/funcs: using default Consul KV variable with value %s", d)
			return d, nil
		}

		v := string(kv.Value[:])
		log.Info().Msgf("template/funcs: using Consul KV variable with key %s and value %s",
			s, v)

		return v, nil
	}
}

func loop(ints ...int64) (<-chan int64, error) {
	var start, stop int64
	switch len(ints) {
	case 1:
		start, stop = 0, ints[0]
	case 2:
		start, stop = ints[0], ints[1]
	default:
		return nil, fmt.Errorf("loop: wrong number of arguments, expected 1 or 2"+
			", but got %d", len(ints))
	}

	ch := make(chan int64)

	go func() {
		for i := start; i < stop; i++ {
			ch <- i
		}
		close(ch)
	}()

	return ch, nil
}

func parseBool(s string) (bool, error) {
	if s == "" {
		return false, nil
	}

	result, err := strconv.ParseBool(s)
	if err != nil {
		return false, err
	}
	return result, nil
}

func parseFloat(s string) (float64, error) {
	if s == "" {
		return 0.0, nil
	}

	result, err := strconv.ParseFloat(s, 10)
	if err != nil {
		return 0, err
	}
	return result, nil
}

func parseInt(s string) (int64, error) {
	if s == "" {
		return 0, nil
	}

	result, err := strconv.ParseInt(s, 10, 64)
	if err != nil {
		return 0, err
	}
	return result, nil
}

func parseJSON(s string) (interface{}, error) {
	if s == "" {
		return map[string]interface{}{}, nil
	}

	var data interface{}
	if err := json.Unmarshal([]byte(s), &data); err != nil {
		return nil, err
	}
	return data, nil
}

func parseUint(s string) (uint64, error) {
	if s == "" {
		return 0, nil
	}

	result, err := strconv.ParseUint(s, 10, 64)
	if err != nil {
		return 0, err
	}
	return result, nil
}

func timeNowFunc() string {
	return time.Now().Format("2006-01-02T15:04:05Z07:00")
}

func timeNowUTCFunc() string {
	return time.Now().UTC().Format("2006-01-02T15:04:05Z07:00")
}

func timeNowTimezoneFunc() func(string) (string, error) {
	return func(t string) (string, error) {

		if t == "" {
			return "", nil
		}

		loc, err := time.LoadLocation(t)
		if err != nil {
			return "", err
		}

		return time.Now().In(loc).Format("2006-01-02T15:04:05Z07:00"), nil
	}
}

func envFunc() func(string) (string, error) {
	return func(s string) (string, error) {
		if s == "" {
			return "", nil
		}
		return os.Getenv(s), nil
	}
}
<commit_msg>Add toUpper and toLower template funcs.<commit_after>package template

import (
	"encoding/json"
	"errors"
	"fmt"
	"os"
	"strconv"
	"strings"
	"text/template"
	"time"

	consul "github.com/hashicorp/consul/api"
	"github.com/rs/zerolog/log"
)

// funcMap builds the template functions and passes the consulClient where this
// is required.
func funcMap(consulClient *consul.Client) template.FuncMap {
	return template.FuncMap{
		"consulKey":          consulKeyFunc(consulClient),
		"consulKeyExists":    consulKeyExistsFunc(consulClient),
		"consulKeyOrDefault": consulKeyOrDefaultFunc(consulClient),
		"env":                envFunc(),
		"loop":               loop,
		"parseBool":          parseBool,
		"parseFloat":         parseFloat,
		"parseInt":           parseInt,
		"parseJSON":          parseJSON,
		"parseUint":          parseUint,
		"timeNow":            timeNowFunc,
		"timeNowUTC":         timeNowUTCFunc,
		"timeNowTimezone":    timeNowTimezoneFunc(),
		"toLower":            toLower,
		"toUpper":            toUpper,
	}
}

func consulKeyFunc(consulClient *consul.Client) func(string) (string, error) {
	return func(s string) (string, error) {

		if len(s) == 0 {
			return "", nil
		}

		kv, _, err := consulClient.KV().Get(s, nil)
		if err != nil {
			return "", err
		}

		if kv == nil {
			return "", errors.New("Consul KV not found")
		}

		v := string(kv.Value[:])
		log.Info().Msgf("template/funcs: using Consul KV variable with key %s and value %s",
			s, v)

		return v, nil
	}
}

func consulKeyExistsFunc(consulClient *consul.Client) func(string) (bool, error) {
	return func(s string) (bool, error) {

		if len(s) == 0 {
			return false, nil
		}

		kv, _, err := consulClient.KV().Get(s, nil)
		if err != nil {
			return false, err
		}

		if kv == nil {
			return false, nil
		}

		log.Info().Msgf("template/funcs: found Consul KV variable with key %s", s)

		return true, nil
	}
}

func consulKeyOrDefaultFunc(consulClient *consul.Client) func(string, string) (string, error) {
	return func(s, d string) (string, error) {

		if len(s) == 0 {
			log.Info().Msgf("template/funcs: using default Consul KV variable with value %s", d)
			return d, nil
		}

		kv, _, err := consulClient.KV().Get(s, nil)
		if err != nil {
			return "", err
		}

		if kv == nil {
			log.Info().Msgf("template/funcs: using default Consul KV variable with value %s", d)
			return d, nil
		}

		v := string(kv.Value[:])
		log.Info().Msgf("template/funcs: using Consul KV variable with key %s and value %s",
			s, v)

		return v, nil
	}
}

func loop(ints ...int64) (<-chan int64, error) {
	var start, stop int64
	switch len(ints) {
	case 1:
		start, stop = 0, ints[0]
	case 2:
		start, stop = ints[0], ints[1]
	default:
		return nil, fmt.Errorf("loop: wrong number of arguments, expected 1 or 2"+
			", but got %d", len(ints))
	}

	ch := make(chan int64)

	go func() {
		for i := start; i < stop; i++ {
			ch <- i
		}
		close(ch)
	}()

	return ch, nil
}

func parseBool(s string) (bool, error) {
	if s == "" {
		return false, nil
	}

	result, err := strconv.ParseBool(s)
	if err != nil {
		return false, err
	}
	return result, nil
}

func parseFloat(s string) (float64, error) {
	if s == "" {
		return 0.0, nil
	}

	result, err := strconv.ParseFloat(s, 10)
	if err != nil {
		return 0, err
	}
	return result, nil
}

func parseInt(s string) (int64, error) {
	if s == "" {
		return 0, nil
	}

	result, err := strconv.ParseInt(s, 10, 64)
	if err != nil {
		return 0, err
	}
	return result, nil
}

func parseJSON(s string) (interface{}, error) {
	if s == "" {
		return map[string]interface{}{}, nil
	}

	var data interface{}
	if err := json.Unmarshal([]byte(s), &data); err != nil {
		return nil, err
	}
	return data, nil
}

func parseUint(s string) (uint64, error) {
	if s == "" {
		return 0, nil
	}

	result, err := strconv.ParseUint(s, 10, 64)
	if err != nil {
		return 0, err
	}
	return result, nil
}

func timeNowFunc() string {
	return time.Now().Format("2006-01-02T15:04:05Z07:00")
}

func timeNowUTCFunc() string {
	return time.Now().UTC().Format("2006-01-02T15:04:05Z07:00")
}

func timeNowTimezoneFunc() func(string) (string, error) {
	return func(t string) (string, error) {

		if t == "" {
			return "", nil
		}

		loc, err := time.LoadLocation(t)
		if err != nil {
			return "", err
		}

		return time.Now().In(loc).Format("2006-01-02T15:04:05Z07:00"), nil
	}
}

func toLower(s string) (string, error) {
	return strings.ToLower(s), nil
}

func toUpper(s string) (string, error) {
	return strings.ToUpper(s), nil
}

func envFunc() func(string) (string, error) {
	return func(s string) (string, error) {
		if s == "" {
			return "", nil
		}
		return os.Getenv(s), nil
	}
}
<|endoftext|>


<commit_before>package template

// Functions available to gondola templates

import (
	"encoding/json"
	"fmt"
	"gondola/assets"
	"html/template"
	"reflect"
	"strconv"
	"strings"
)

func eq(args ...interface{}) bool {
	if len(args) == 0 {
		return false
	}
	x := args[0]
	switch x := x.(type) {
	case string, int, int64, byte, float32, float64:
		for _, y := range args[1:] {
			if x == y {
				return true
			}
		}
		return false
	}

	for _, y := range args[1:] {
		if reflect.DeepEqual(x, y) {
			return true
		}
	}
	return false
}

func neq(args ...interface{}) bool {
	return !eq(args...)
}

func _json(arg interface{}) string {
	if arg == nil {
		return ""
	}
	b, err := json.Marshal(arg)
	if err == nil {
		return string(b)
	}
	return ""
}

func nz(x interface{}) bool {
	switch x := x.(type) {
	case int, uint, int64, uint64, byte, float32, float64:
		return x != 0
	case string:
		return len(x) > 0
	}
	return false
}

func lower(x string) string {
	return strings.ToLower(x)
}

func join(x []string, sep string) string {
	s := ""
	for _, v := range x {
		s += fmt.Sprintf("%v%s", v, sep)
	}
	if len(s) > 0 {
		return s[:len(s)-len(sep)]
	}
	return ""
}

func _map(args ...interface{}) (map[string]interface{}, error) {
	var key string
	m := make(map[string]interface{})
	for ii, v := range args {
		if ii%2 == 0 {
			if s, ok := v.(string); ok {
				key = s
			} else {
				return nil, fmt.Errorf("Invalid argument to map at index %d, %t instead of string", ii, v)
			}
		} else {
			m[key] = v
		}
	}
	return m, nil
}

func mult(args ...interface{}) (float64, error) {
	val := 1.0
	for ii, v := range args {
		value := reflect.ValueOf(v)
		switch value.Kind() {
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
			val *= float64(value.Int())
		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
			val *= float64(value.Uint())
		case reflect.Float32, reflect.Float64:
			val *= value.Float()
		case reflect.String:
			v, err := strconv.ParseFloat(value.String(), 64)
			if err != nil {
				return 0, fmt.Errorf("Error parsing string passed to mult at index %d: %s", ii, err)
			}
			val *= v
		default:
			return 0, fmt.Errorf("Invalid argument of type %T passed to mult at index %d", v, ii)
		}
	}
	return val, nil

}

func concat(args ...interface{}) string {
	var s []string
	for _, v := range args {
		s = append(s, fmt.Sprintf("%v", v))
	}
	return strings.Join(s, "")
}

func and(args ...interface{}) bool {
	for _, v := range args {
		val := reflect.ValueOf(v)
		t, _ := isTrue(val)
		if !t {
			return false
		}
	}
	return true
}

func or(args ...interface{}) bool {
	for _, v := range args {
		val := reflect.ValueOf(v)
		t, _ := isTrue(val)
		if t {
			return true
		}
	}
	return false
}

func not(arg interface{}) bool {
	val := reflect.ValueOf(arg)
	t, _ := isTrue(val)
	return !t
}

// isTrue returns whether the value is 'true', in the sense of not the zero of its type,
// and whether the value has a meaningful truth value. This function is a copy of the
// one found in text/template
func isTrue(val reflect.Value) (truth, ok bool) {
	if !val.IsValid() {
		// Something like var x interface{}, never set. It's a form of nil.
		return false, true
	}
	switch val.Kind() {
	case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
		truth = val.Len() > 0
	case reflect.Bool:
		truth = val.Bool()
	case reflect.Complex64, reflect.Complex128:
		truth = val.Complex() != 0
	case reflect.Chan, reflect.Func, reflect.Ptr, reflect.Interface:
		truth = !val.IsNil()
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		truth = val.Int() != 0
	case reflect.Float32, reflect.Float64:
		truth = val.Float() != 0
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		truth = val.Uint() != 0
	case reflect.Struct:
		truth = true // Struct values are always true.
	default:
		return
	}
	return truth, true
}

var templateFuncs template.FuncMap = template.FuncMap{
	"eq":     eq,
	"neq":    neq,
	"json":   _json,
	"nz":     nz,
	"lower":  lower,
	"join":   join,
	"map":    _map,
	"mult":   mult,
	"render": assets.Render,
	"concat": concat,
	"and":    and,
	"or":     or,
	"not":    not,
}
<commit_msg>Add now function in template<commit_after>package template

// Functions available to gondola templates

import (
	"encoding/json"
	"fmt"
	"gondola/assets"
	"html/template"
	"reflect"
	"strconv"
	"strings"
	"time"
)

func eq(args ...interface{}) bool {
	if len(args) == 0 {
		return false
	}
	x := args[0]
	switch x := x.(type) {
	case string, int, int64, byte, float32, float64:
		for _, y := range args[1:] {
			if x == y {
				return true
			}
		}
		return false
	}

	for _, y := range args[1:] {
		if reflect.DeepEqual(x, y) {
			return true
		}
	}
	return false
}

func neq(args ...interface{}) bool {
	return !eq(args...)
}

func _json(arg interface{}) string {
	if arg == nil {
		return ""
	}
	b, err := json.Marshal(arg)
	if err == nil {
		return string(b)
	}
	return ""
}

func nz(x interface{}) bool {
	switch x := x.(type) {
	case int, uint, int64, uint64, byte, float32, float64:
		return x != 0
	case string:
		return len(x) > 0
	}
	return false
}

func lower(x string) string {
	return strings.ToLower(x)
}

func join(x []string, sep string) string {
	s := ""
	for _, v := range x {
		s += fmt.Sprintf("%v%s", v, sep)
	}
	if len(s) > 0 {
		return s[:len(s)-len(sep)]
	}
	return ""
}

func _map(args ...interface{}) (map[string]interface{}, error) {
	var key string
	m := make(map[string]interface{})
	for ii, v := range args {
		if ii%2 == 0 {
			if s, ok := v.(string); ok {
				key = s
			} else {
				return nil, fmt.Errorf("Invalid argument to map at index %d, %t instead of string", ii, v)
			}
		} else {
			m[key] = v
		}
	}
	return m, nil
}

func mult(args ...interface{}) (float64, error) {
	val := 1.0
	for ii, v := range args {
		value := reflect.ValueOf(v)
		switch value.Kind() {
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
			val *= float64(value.Int())
		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
			val *= float64(value.Uint())
		case reflect.Float32, reflect.Float64:
			val *= value.Float()
		case reflect.String:
			v, err := strconv.ParseFloat(value.String(), 64)
			if err != nil {
				return 0, fmt.Errorf("Error parsing string passed to mult at index %d: %s", ii, err)
			}
			val *= v
		default:
			return 0, fmt.Errorf("Invalid argument of type %T passed to mult at index %d", v, ii)
		}
	}
	return val, nil

}

func concat(args ...interface{}) string {
	var s []string
	for _, v := range args {
		s = append(s, fmt.Sprintf("%v", v))
	}
	return strings.Join(s, "")
}

func and(args ...interface{}) bool {
	for _, v := range args {
		val := reflect.ValueOf(v)
		t, _ := isTrue(val)
		if !t {
			return false
		}
	}
	return true
}

func or(args ...interface{}) bool {
	for _, v := range args {
		val := reflect.ValueOf(v)
		t, _ := isTrue(val)
		if t {
			return true
		}
	}
	return false
}

func not(arg interface{}) bool {
	val := reflect.ValueOf(arg)
	t, _ := isTrue(val)
	return !t
}

func now() time.Time {
	return time.Now()
}

// isTrue returns whether the value is 'true', in the sense of not the zero of its type,
// and whether the value has a meaningful truth value. This function is a copy of the
// one found in text/template
func isTrue(val reflect.Value) (truth, ok bool) {
	if !val.IsValid() {
		// Something like var x interface{}, never set. It's a form of nil.
		return false, true
	}
	switch val.Kind() {
	case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
		truth = val.Len() > 0
	case reflect.Bool:
		truth = val.Bool()
	case reflect.Complex64, reflect.Complex128:
		truth = val.Complex() != 0
	case reflect.Chan, reflect.Func, reflect.Ptr, reflect.Interface:
		truth = !val.IsNil()
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		truth = val.Int() != 0
	case reflect.Float32, reflect.Float64:
		truth = val.Float() != 0
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		truth = val.Uint() != 0
	case reflect.Struct:
		truth = true // Struct values are always true.
	default:
		return
	}
	return truth, true
}

var templateFuncs template.FuncMap = template.FuncMap{
	"eq":     eq,
	"neq":    neq,
	"json":   _json,
	"nz":     nz,
	"lower":  lower,
	"join":   join,
	"map":    _map,
	"mult":   mult,
	"render": assets.Render,
	"concat": concat,
	"and":    and,
	"or":     or,
	"not":    not,
	"now":    now,
}
<|endoftext|>


<commit_before>package benchdb

import (
	"math/rand"
	"sort"
	"testing"
)

func mySort(data sort.Interface, a, b int) {
	// Insertion sort borrowed from the std library.
	for i := a + 1; i < b; i++ {
		for j := i; j > a && data.Less(j, j-1); j-- {
			data.Swap(j, j-1)
		}
	}
}

func BenchmarkMySort1K(b *testing.B) {
	b.StopTimer()
	for i := 0; i < b.N; i++ {
		data := make([]int, 1000)
		for i := 0; i < len(data); i++ {
			data[i] = rand.Int()
		}
		b.StartTimer()
		mySort(sort.IntSlice(data), 0, len(data))
		b.StopTimer()
	}
}
<commit_msg>using sort from the std lib<commit_after>package benchdb

import (
	"math/rand"
	"sort"
	"testing"
)

func mySort(data sort.Interface, a, b int) {
	sort.Sort(data)
}

func BenchmarkMySort1K(b *testing.B) {
	b.StopTimer()
	for i := 0; i < b.N; i++ {
		data := make([]int, 1000)
		for i := 0; i < len(data); i++ {
			data[i] = rand.Int()
		}
		b.StartTimer()
		mySort(sort.IntSlice(data), 0, len(data))
		b.StopTimer()
	}
}
<|endoftext|>


<commit_before>package apps

import (
	"encoding/json"
	"io"
	"net/url"
	"path"
	"regexp"

	"github.com/cozy/cozy-stack/pkg/couchdb"
	"github.com/cozy/cozy-stack/pkg/permissions"
	"github.com/cozy/cozy-stack/pkg/vfs"
)

var slugReg = regexp.MustCompile(`^[A-Za-z0-9\-]+$`)

// Installer is used to install or update applications.
type Installer struct {
	fetcher Fetcher
	ctx     vfs.Context

	man  *Manifest
	src  *url.URL
	slug string

	err  error
	errc chan error
	manc chan *Manifest
}

// InstallerOptions provides the slug name of the application along with the
// source URL.
type InstallerOptions struct {
	Slug      string
	SourceURL string
}

// Fetcher interface should be implemented by the underlying transport
// used to fetch the application data.
type Fetcher interface {
	// FetchManifest should returns an io.ReadCloser to read the
	// manifest data
	FetchManifest(src *url.URL) (io.ReadCloser, error)
	// Fetch should download the application and install it in the given
	// directory.
	Fetch(src *url.URL, appDir string) error
}

// NewInstaller creates a new Installer
func NewInstaller(ctx vfs.Context, opts *InstallerOptions) (*Installer, error) {
	slug := opts.Slug
	if slug == "" || !slugReg.MatchString(slug) {
		return nil, ErrInvalidSlugName
	}

	man, err := GetBySlug(ctx, slug)
	if err != nil && !couchdb.IsNotFoundError(err) {
		return nil, err
	}

	var src *url.URL
	if man != nil {
		src, err = url.Parse(man.Source)
	} else if opts.SourceURL != "" {
		src, err = url.Parse(opts.SourceURL)
	} else {
		err = nil
	}
	if err != nil {
		return nil, err
	}

	var fetcher Fetcher
	if src != nil {
		switch src.Scheme {
		case "git":
			fetcher = newGitFetcher(ctx)
		default:
			return nil, ErrNotSupportedSource
		}
	}

	inst := &Installer{
		fetcher: fetcher,
		ctx:     ctx,
		src:     src,
		slug:    slug,
		man:     man,
		errc:    make(chan error),
		manc:    make(chan *Manifest, 1),
	}

	return inst, nil
}

// Install will install the application linked to the installer. It will
// report its progress or error (see Poll method).
func (i *Installer) Install() {
	defer i.endOfProc()
	if i.man != nil {
		i.man, i.err = nil, ErrAlreadyExists
	} else {
		i.man, i.err = i.install()
	}
	return
}

// Update will update the application linked to the installer. It will
// report its progress or error (see Poll method).
func (i *Installer) Update() {
	defer i.endOfProc()
	if i.man == nil {
		i.err = ErrNotFound
		return
	}
	if state := i.man.State; state != Ready && state != Errored {
		i.man, i.err = nil, ErrBadState
	} else {
		i.man, i.err = i.update()
	}
	return
}

func (i *Installer) endOfProc() {
	man, err := i.man, i.err
	if man == nil || err == ErrBadState {
		i.errc <- err
		return
	}
	if err != nil {
		man.State = Errored
		man.Error = err.Error()
		updateManifest(i.ctx, man)
		i.errc <- err
		return
	}
	man.State = Ready
	updateManifest(i.ctx, man)
	i.manc <- i.man
}

// install will perform the installation of an application. It returns the
// freshly fetched manifest from the source along with a possible error in case
// the installation went wrong.
//
// Note that the fetched manifest is returned even if an error occurred while
// upgrading.
func (i *Installer) install() (*Manifest, error) {
	man := &Manifest{}
	if err := i.ReadManifest(Installing, man); err != nil {
		return nil, err
	}

	if err := createManifest(i.ctx, man); err != nil {
		return man, err
	}

	i.manc <- man

	appdir := i.appDir()
	if _, err := vfs.MkdirAll(i.ctx, appdir, nil); err != nil {
		return man, err
	}

	err := i.fetcher.Fetch(i.src, appdir)
	return man, err
}

// update will perform the update of an already installed application. It
// returns the freshly fetched manifest from the source along with a possible
// error in case the update went wrong.
//
// Note that the fetched manifest is returned even if an error occurred while
// upgrading.
func (i *Installer) update() (*Manifest, error) {
	man := i.man
	version := man.Version

	if err := i.ReadManifest(Upgrading, man); err != nil {
		return man, err
	}

	if man.Version == version {
		return man, nil
	}

	if err := updateManifest(i.ctx, man); err != nil {
		return man, err
	}

	i.manc <- man

	err := i.fetcher.Fetch(i.src, i.appDir())
	return man, err
}

// ReadManifest will fetch the manifest and read its JSON content into the
// passed manifest pointer.
//
// The State field of the manifest will be set to the specified state.
func (i *Installer) ReadManifest(state State, man *Manifest) error {
	r, err := i.fetcher.FetchManifest(i.src)
	if err != nil {
		return err
	}
	defer r.Close()

	err = json.NewDecoder(io.LimitReader(r, ManifestMaxSize)).Decode(man)
	if err != nil {
		return ErrBadManifest
	}

	man.Slug = i.slug
	man.Source = i.src.String()
	man.State = state
	man.CreateDefaultRoute()

	return nil
}

func (i *Installer) appDir() string {
	return path.Join(vfs.AppsDirName, i.slug)
}

// Poll should be used to monitor the progress of the Installer.
func (i *Installer) Poll() (*Manifest, bool, error) {
	select {
	case man := <-i.manc:
		done := man.State == Ready
		return man, done, nil
	case err := <-i.errc:
		return nil, false, err
	}
}

func updateManifest(db couchdb.Database, man *Manifest) error {

	err := permissions.DestroyApp(db, man.Slug)
	if err != nil && !couchdb.IsNotFoundError(err) {
		return err
	}

	err = couchdb.UpdateDoc(db, man)
	if err != nil {
		return err
	}

	_, err = permissions.CreateAppSet(db, man.Slug, *man.Permissions)
	return err
}

func createManifest(db couchdb.Database, man *Manifest) error {

	if err := couchdb.CreateNamedDoc(db, man); err != nil {
		return err
	}

	_, err := permissions.CreateAppSet(db, man.Slug, *man.Permissions)
	return err

}
<commit_msg>Always update apps from git, even for the same version number<commit_after>package apps

import (
	"encoding/json"
	"io"
	"net/url"
	"path"
	"regexp"

	"github.com/cozy/cozy-stack/pkg/couchdb"
	"github.com/cozy/cozy-stack/pkg/permissions"
	"github.com/cozy/cozy-stack/pkg/vfs"
)

var slugReg = regexp.MustCompile(`^[A-Za-z0-9\-]+$`)

// Installer is used to install or update applications.
type Installer struct {
	fetcher Fetcher
	ctx     vfs.Context

	man  *Manifest
	src  *url.URL
	slug string

	err  error
	errc chan error
	manc chan *Manifest
}

// InstallerOptions provides the slug name of the application along with the
// source URL.
type InstallerOptions struct {
	Slug      string
	SourceURL string
}

// Fetcher interface should be implemented by the underlying transport
// used to fetch the application data.
type Fetcher interface {
	// FetchManifest should returns an io.ReadCloser to read the
	// manifest data
	FetchManifest(src *url.URL) (io.ReadCloser, error)
	// Fetch should download the application and install it in the given
	// directory.
	Fetch(src *url.URL, appDir string) error
}

// NewInstaller creates a new Installer
func NewInstaller(ctx vfs.Context, opts *InstallerOptions) (*Installer, error) {
	slug := opts.Slug
	if slug == "" || !slugReg.MatchString(slug) {
		return nil, ErrInvalidSlugName
	}

	man, err := GetBySlug(ctx, slug)
	if err != nil && !couchdb.IsNotFoundError(err) {
		return nil, err
	}

	var src *url.URL
	if man != nil {
		src, err = url.Parse(man.Source)
	} else if opts.SourceURL != "" {
		src, err = url.Parse(opts.SourceURL)
	} else {
		err = nil
	}
	if err != nil {
		return nil, err
	}

	var fetcher Fetcher
	if src != nil {
		switch src.Scheme {
		case "git":
			fetcher = newGitFetcher(ctx)
		default:
			return nil, ErrNotSupportedSource
		}
	}

	inst := &Installer{
		fetcher: fetcher,
		ctx:     ctx,
		src:     src,
		slug:    slug,
		man:     man,
		errc:    make(chan error),
		manc:    make(chan *Manifest, 1),
	}

	return inst, nil
}

// Install will install the application linked to the installer. It will
// report its progress or error (see Poll method).
func (i *Installer) Install() {
	defer i.endOfProc()
	if i.man != nil {
		i.man, i.err = nil, ErrAlreadyExists
	} else {
		i.man, i.err = i.install()
	}
	return
}

// Update will update the application linked to the installer. It will
// report its progress or error (see Poll method).
func (i *Installer) Update() {
	defer i.endOfProc()
	if i.man == nil {
		i.err = ErrNotFound
		return
	}
	if state := i.man.State; state != Ready && state != Errored {
		i.man, i.err = nil, ErrBadState
	} else {
		i.man, i.err = i.update()
	}
	return
}

func (i *Installer) endOfProc() {
	man, err := i.man, i.err
	if man == nil || err == ErrBadState {
		i.errc <- err
		return
	}
	if err != nil {
		man.State = Errored
		man.Error = err.Error()
		updateManifest(i.ctx, man)
		i.errc <- err
		return
	}
	man.State = Ready
	updateManifest(i.ctx, man)
	i.manc <- i.man
}

// install will perform the installation of an application. It returns the
// freshly fetched manifest from the source along with a possible error in case
// the installation went wrong.
//
// Note that the fetched manifest is returned even if an error occurred while
// upgrading.
func (i *Installer) install() (*Manifest, error) {
	man := &Manifest{}
	if err := i.ReadManifest(Installing, man); err != nil {
		return nil, err
	}

	if err := createManifest(i.ctx, man); err != nil {
		return man, err
	}

	i.manc <- man

	appdir := i.appDir()
	if _, err := vfs.MkdirAll(i.ctx, appdir, nil); err != nil {
		return man, err
	}

	err := i.fetcher.Fetch(i.src, appdir)
	return man, err
}

// update will perform the update of an already installed application. It
// returns the freshly fetched manifest from the source along with a possible
// error in case the update went wrong.
//
// Note that the fetched manifest is returned even if an error occurred while
// upgrading.
func (i *Installer) update() (*Manifest, error) {
	man := i.man

	if err := i.ReadManifest(Upgrading, man); err != nil {
		return man, err
	}

	if err := updateManifest(i.ctx, man); err != nil {
		return man, err
	}

	i.manc <- man

	err := i.fetcher.Fetch(i.src, i.appDir())
	return man, err
}

// ReadManifest will fetch the manifest and read its JSON content into the
// passed manifest pointer.
//
// The State field of the manifest will be set to the specified state.
func (i *Installer) ReadManifest(state State, man *Manifest) error {
	r, err := i.fetcher.FetchManifest(i.src)
	if err != nil {
		return err
	}
	defer r.Close()

	err = json.NewDecoder(io.LimitReader(r, ManifestMaxSize)).Decode(man)
	if err != nil {
		return ErrBadManifest
	}

	man.Slug = i.slug
	man.Source = i.src.String()
	man.State = state
	man.CreateDefaultRoute()

	return nil
}

func (i *Installer) appDir() string {
	return path.Join(vfs.AppsDirName, i.slug)
}

// Poll should be used to monitor the progress of the Installer.
func (i *Installer) Poll() (*Manifest, bool, error) {
	select {
	case man := <-i.manc:
		done := man.State == Ready
		return man, done, nil
	case err := <-i.errc:
		return nil, false, err
	}
}

func updateManifest(db couchdb.Database, man *Manifest) error {

	err := permissions.DestroyApp(db, man.Slug)
	if err != nil && !couchdb.IsNotFoundError(err) {
		return err
	}

	err = couchdb.UpdateDoc(db, man)
	if err != nil {
		return err
	}

	_, err = permissions.CreateAppSet(db, man.Slug, *man.Permissions)
	return err
}

func createManifest(db couchdb.Database, man *Manifest) error {

	if err := couchdb.CreateNamedDoc(db, man); err != nil {
		return err
	}

	_, err := permissions.CreateAppSet(db, man.Slug, *man.Permissions)
	return err

}
<|endoftext|>


<commit_before>package httpd

import (
	"bufio"
	"fmt"
	"github.com/Symantec/Dominator/lib/html"
	"net/http"
)

func statusHandler(w http.ResponseWriter, req *http.Request) {
	writer := bufio.NewWriter(w)
	defer writer.Flush()
	fmt.Fprintln(writer, "<title>System Health Agent status page</title>")
	fmt.Fprintln(writer, "")
	fmt.Fprintln(writer, "")
	fmt.Fprintln(writer, "
System Health Agent status page
")
	fmt.Fprintln(writer, "")
	html.WriteHeader(writer)
	fmt.Fprintln(writer, "
")
	for _, htmlWriter := range htmlWriters {
		if requestWriter, ok := htmlWriter.(RequestHtmlWriter); ok {
			requestWriter.RequestWriteHtml(writer, req)
		} else {
			htmlWriter.WriteHtml(writer)
		}
	}
	fmt.Fprintln(writer, "
")
	fmt.Fprintln(writer, "
")
	html.WriteFooter(writer)
	fmt.Fprintln(writer, "")
}
<commit_msg>Reject everything but root path in httpd.statusHandler().<commit_after>package httpd

import (
	"bufio"
	"fmt"
	"github.com/Symantec/Dominator/lib/html"
	"net/http"
)

func statusHandler(w http.ResponseWriter, req *http.Request) {
	if req.URL.Path != "/" {
		http.NotFound(w, req)
		return
	}
	writer := bufio.NewWriter(w)
	defer writer.Flush()
	fmt.Fprintln(writer, "<title>System Health Agent status page</title>")
	fmt.Fprintln(writer, "")
	fmt.Fprintln(writer, "")
	fmt.Fprintln(writer, "
System Health Agent status page
")
	fmt.Fprintln(writer, "")
	html.WriteHeader(writer)
	fmt.Fprintln(writer, "
")
	for _, htmlWriter := range htmlWriters {
		if requestWriter, ok := htmlWriter.(RequestHtmlWriter); ok {
			requestWriter.RequestWriteHtml(writer, req)
		} else {
			htmlWriter.WriteHtml(writer)
		}
	}
	fmt.Fprintln(writer, "
")
	fmt.Fprintln(writer, "
")
	html.WriteFooter(writer)
	fmt.Fprintln(writer, "")
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors All rights reserved.

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

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

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

package helm

import (
	rls "k8s.io/helm/pkg/proto/hapi/services"
)

// Interface for helm client for mocking in tests
type Interface interface {
	ListReleases(opts ...ReleaseListOption) (*rls.ListReleasesResponse, error)
	InstallRelease(chStr string, opts ...InstallOption) (*rls.InstallReleaseResponse, error)
	DeleteRelease(rlsName string, opts ...DeleteOption) (*rls.UninstallReleaseResponse, error)
	ReleaseStatus(rlsName string, opts ...StatusOption) (*rls.GetReleaseStatusResponse, error)
	UpdateRelease(rlsName string, opts ...UpdateOption) (*rls.UpdateReleaseResponse, error)
}
<commit_msg>fix(helm): add ReleaseContent to interface<commit_after>/*
Copyright 2016 The Kubernetes Authors All rights reserved.

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

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

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

package helm

import (
	rls "k8s.io/helm/pkg/proto/hapi/services"
)

// Interface for helm client for mocking in tests
type Interface interface {
	ListReleases(opts ...ReleaseListOption) (*rls.ListReleasesResponse, error)
	InstallRelease(chStr string, opts ...InstallOption) (*rls.InstallReleaseResponse, error)
	DeleteRelease(rlsName string, opts ...DeleteOption) (*rls.UninstallReleaseResponse, error)
	ReleaseStatus(rlsName string, opts ...StatusOption) (*rls.GetReleaseStatusResponse, error)
	UpdateRelease(rlsName string, opts ...UpdateOption) (*rls.UpdateReleaseResponse, error)
	ReleaseContent(rlsName string, opts ...ContentOption) (*rls.GetReleaseContentResponse, error)
}
<|endoftext|>


<commit_before>// Package license implements a HTTP client for accessing the GitHub
// Licenses API. See:
//   https://developer.github.com/v3/licenses/
package license

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"
)

const (
	// BaseURL is the base URL of the Github Licenses API.
	BaseURL = "https://api.github.com/licenses"
)

var (
	// Header is headers included in each request.
	Header = map[string][]string{
		"Accept": []string{
			"application/vnd.github.drax-preview+json",
			"application/vnd.github.v3+json",
		},
	}
)

// StatusError is returned when the HTTP roundtrip succeeds, but the
// the response status does not equal http.StatusOK.
type StatusError struct {
	Status     string
	StatusCode int
	Details    struct {
		Message string `json:"message"`
		Errors  []struct {
			Resource string `json:"resource"`
			Field    string `json:"field"`
			Code     string `json:"code"`
		} `json:"errors"`
	}
}

func (e StatusError) Error() string {
	s := fmt.Sprintf("license: HTTP response error: %s", e.Status)
	if e.Details.Message != "" {
		s += ": " + e.Details.Message
	}
	return s
}

// Client represents a HTTP client for making requests to the
// GitHub Licenses API. Use NewClient to create a Client
// ready for use.
type Client struct {
	HTTPClient *http.Client
	Config
}

// NewClient returns a ready-to-use client to make calls to the
// GitHub Licenses API.
func NewClient() *Client {
	return &Client{
		HTTPClient: http.DefaultClient,
		Config: Config{
			BaseURL: BaseURL,
		},
	}
}

// Config is configuration for Client.
type Config struct {
	// ClientID is the GitHub client ID for the API.
	// See https://developer.github.com/v3/oauth/.
	// If either ClientID or ClientSecret is empty,
	// then ClientID and ClientSecret are not included in the request.
	ClientID string

	// ClientSecret is the GitHub client Secret for the API.
	// See https://developer.github.com/v3/oauth/.
	ClientSecret string

	// BaseURL is the base URL for the API.
	// Useful in tests.
	BaseURL string

	// Header is a map of custom headers to add to outgoing request.
	// If nil or empty, no custom headers will be added.
	Header map[string][]string
}

func (c *Client) makeQuery(vals url.Values) string {
	v := vals.Encode()
	auth := url.Values{
		"client_id":     []string{c.ClientID},
		"client_secret": []string{c.ClientSecret},
	}
	av := auth.Encode()

	query := v
	if query != "" {
		if av != "" {
			query += "&" + av
		}
	} else {
		query = av
	}

	return query
}

func (c *Client) addHeaders(req *http.Request) {
	for k, v := range Header {
		for _, s := range v {
			req.Header.Add(k, s)
		}
	}
	for k, v := range c.Header {
		for _, s := range v {
			req.Header.Add(k, s)
		}
	}
}

func (c *Client) doReq(method, path string, body io.Reader, vals url.Values) (io.ReadCloser, error) {
	q := c.makeQuery(vals)
	u := c.BaseURL + path
	if q != "" {
		u += "?" + q
	}

	req, err := http.NewRequest(method, u, body)
	if err != nil {
		return nil, err
	}

	c.addHeaders(req)

	res, err := c.HTTPClient.Do(req)
	if err != nil {
		return nil, err
	}

	if res.StatusCode != http.StatusOK {
		defer res.Body.Close()
		se := StatusError{
			Status:     res.Status,
			StatusCode: res.StatusCode,
		}
		json.NewDecoder(res.Body).Decode(&se.Details) // Ignore error.
		return nil, se
	}

	return res.Body, nil
}

// List returns a list of licenses.
// Only the following fields will be set in returned licenses.
//   Key, Name, URL, Featured
func (c *Client) List() ([]License, error) {
	data, err := c.doReq("GET", "", nil, nil)
	if err != nil {
		return nil, err
	}
	defer data.Close()

	var lics []License
	if err := json.NewDecoder(data).Decode(&lics); err != nil {
		return nil, err
	}
	return lics, err
}

// Info returns the License for key.
// Example keys are "mit", "lgpl-3.0", etc.
func (c *Client) Info(key string) (License, error) {
	data, err := c.InfoJSON(key)
	if err != nil {
		return License{}, err
	}
	defer data.Close()

	var lic License
	if err := json.NewDecoder(data).Decode(&lic); err != nil {
		return License{}, err
	}
	return lic, err
}

// InfoJSON returns the raw JSON response for key.
// Example keys are "mit", "lgpl-3.0", etc.
func (c *Client) InfoJSON(key string) (io.ReadCloser, error) {
	return c.doReq("GET", "/"+key, nil, nil)
}
<commit_msg>pkg/license: use username and token as primary auth method<commit_after>// Package license implements a HTTP client for accessing the GitHub
// Licenses API. See:
//   https://developer.github.com/v3/licenses/
package license

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"
)

const (
	// BaseURL is the base URL of the Github Licenses API.
	BaseURL = "https://api.github.com/licenses"
)

var (
	// Header is headers included in each request.
	Header = map[string][]string{
		"Accept": []string{
			"application/vnd.github.drax-preview+json",
			"application/vnd.github.v3+json",
		},
	}
)

// StatusError is returned when the HTTP roundtrip succeeds, but the
// the response status does not equal http.StatusOK.
type StatusError struct {
	Status     string
	StatusCode int
	Details    struct {
		Message string `json:"message"`
		Errors  []struct {
			Resource string `json:"resource"`
			Field    string `json:"field"`
			Code     string `json:"code"`
		} `json:"errors"`
	}
}

func (e StatusError) Error() string {
	s := fmt.Sprintf("license: HTTP response error: %s", e.Status)
	if e.Details.Message != "" {
		s += ": " + e.Details.Message
	}
	return s
}

// Client represents a HTTP client for making requests to the
// GitHub Licenses API. Use NewClient to create a Client
// ready for use.
//
// If Token and Username are both set in Config, they are used for
// authentication. Otherwise, if ClientID and ClientSecret
// are both set, they are used for authentication. If none of the
// above fields are set, no authentication is used.
type Client struct {
	HTTPClient *http.Client
	Config
}

// NewClient returns a ready-to-use client to make calls to the
// GitHub Licenses API.
func NewClient() *Client {
	return &Client{
		HTTPClient: http.DefaultClient,
		Config: Config{
			BaseURL: BaseURL,
		},
	}
}

// Config is configuration for Client.
type Config struct {
	// Token is GitHub personal API token for authentication.
	Token string

	// Username is GitHub username for authentication.
	Username string

	// ClientID is the GitHub client ID for the API.
	// See https://developer.github.com/v3/oauth/.
	// If either ClientID or ClientSecret is empty,
	// then ClientID and ClientSecret are not included in the request.
	ClientID string

	// ClientSecret is the GitHub client secret for the API.
	// See https://developer.github.com/v3/oauth/.
	ClientSecret string

	// BaseURL is the base URL for the API.
	// Useful in tests.
	BaseURL string

	// Header is a map of custom headers to add to outgoing request.
	// If nil or empty, no custom headers will be added.
	Header map[string][]string
}

func (c *Client) makeQuery(vals url.Values) string {
	// Shallow copy, but OK.
	query := url.Values{}
	for k, v := range vals {
		query[k] = v
	}

	if (c.Token == "" && c.Username == "") &&
		(c.ClientID != "" && c.ClientSecret != "") {
		query["client_id"] = []string{c.ClientID}
		query["client_secret"] = []string{c.ClientSecret}
	}

	return query.Encode()
}

func (c *Client) addHeaders(req *http.Request) {
	for k, v := range Header {
		for _, s := range v {
			req.Header.Add(k, s)
		}
	}
	for k, v := range c.Header {
		for _, s := range v {
			req.Header.Add(k, s)
		}
	}
}

func (c *Client) doReq(method, path string, body io.Reader, vals url.Values) (io.ReadCloser, error) {
	u := c.BaseURL + path
	q := c.makeQuery(vals)
	if q != "" {
		u += "?" + q
	}

	req, err := http.NewRequest(method, u, body)
	if err != nil {
		return nil, err
	}

	if c.Username != "" && c.Token != "" {
		req.SetBasicAuth(c.Username, c.Token)
	}

	c.addHeaders(req)

	res, err := c.HTTPClient.Do(req)
	if err != nil {
		return nil, err
	}

	if res.StatusCode != http.StatusOK {
		defer res.Body.Close()
		se := StatusError{
			Status:     res.Status,
			StatusCode: res.StatusCode,
		}
		json.NewDecoder(res.Body).Decode(&se.Details) // Ignore error.
		return nil, se
	}

	return res.Body, nil
}

// List returns the list of licenses.
// Only the following fields will be set in returned licenses.
//   Key, Name, URL, Featured
func (c *Client) List() ([]License, error) {
	data, err := c.doReq("GET", "", nil, nil)
	if err != nil {
		return nil, err
	}
	defer data.Close()

	var lics []License
	if err := json.NewDecoder(data).Decode(&lics); err != nil {
		return nil, err
	}
	return lics, err
}

// Info returns the license for key.
// Example keys are "mit", "lgpl-3.0", etc.
func (c *Client) Info(key string) (License, error) {
	data, err := c.InfoJSON(key)
	if err != nil {
		return License{}, err
	}
	defer data.Close()

	var lic License
	if err := json.NewDecoder(data).Decode(&lic); err != nil {
		return License{}, err
	}
	return lic, err
}

// InfoJSON returns the license as raw JSON for key.
// Example keys are "mit", "lgpl-3.0", etc.
// If the error is non-nil, the caller is reponsible
// for closing the returned io.ReadCloser.
func (c *Client) InfoJSON(key string) (io.ReadCloser, error) {
	return c.doReq("GET", "/"+key, nil, nil)
}
<|endoftext|>


<commit_before>package oauth

import (
	"net/http"

	"github.com/hellofresh/janus/pkg/errors"
	"github.com/hellofresh/janus/pkg/notifier"
	"github.com/hellofresh/janus/pkg/opentracing"
	"github.com/hellofresh/janus/pkg/request"
	"github.com/hellofresh/janus/pkg/response"
	"github.com/hellofresh/janus/pkg/router"
)

// Controller is the api rest controller
type Controller struct {
	repo     Repository
	notifier notifier.Notifier
}

// NewController creates a new instance of Controller
func NewController(repo Repository, notifier notifier.Notifier) *Controller {
	return &Controller{repo, notifier}
}

// Get is the find all handler
func (c *Controller) Get() http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		span := opentracing.FromContext(r.Context(), "datastore.FindAll")
		data, err := c.repo.FindAll()
		span.Finish()

		if err != nil {
			panic(err.Error())
		}

		response.JSON(w, http.StatusOK, data)
	}
}

// GetBy is the find by handler
func (c *Controller) GetBy() http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		name := router.URLParam(r, "name")
		span := opentracing.FromContext(r.Context(), "datastore.FindByName")
		data, err := c.repo.FindByName(name)
		span.Finish()

		if data.Name == "" {
			panic(ErrOauthServerNotFound)
		}

		if err != nil {
			panic(errors.New(http.StatusInternalServerError, err.Error()))
		}

		response.JSON(w, http.StatusOK, data)
	}
}

// PutBy is the update handler
func (c *Controller) PutBy() http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		var err error
		name := router.URLParam(r, "name")

		span := opentracing.FromContext(r.Context(), "datastore.FindByName")
		oauth, err := c.repo.FindByName(name)
		span.Finish()

		if oauth.Name == "" {
			panic(ErrOauthServerNotFound)
		}

		if err != nil {
			panic(errors.New(http.StatusInternalServerError, err.Error()))
		}

		err = request.BindJSON(r, oauth)
		if nil != err {
			panic(errors.New(http.StatusInternalServerError, err.Error()))
		}

		span = opentracing.FromContext(r.Context(), "datastore.Add")
		err = c.repo.Add(oauth)
		c.dispatch(notifier.NoticeOAuthServerUpdated)
		span.Finish()

		if nil != err {
			panic(errors.New(http.StatusBadRequest, err.Error()))
		}

		response.JSON(w, http.StatusOK, nil)
	}
}

// Post is the create handler
func (c *Controller) Post() http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		var oauth OAuth

		err := request.BindJSON(r, &oauth)
		if nil != err {
			panic(errors.New(http.StatusInternalServerError, err.Error()))
		}

		span := opentracing.FromContext(r.Context(), "datastore.Add")
		err = c.repo.Add(&oauth)
		c.dispatch(notifier.NoticeOAuthServerAdded)
		span.Finish()

		if nil != err {
			panic(errors.New(http.StatusBadRequest, err.Error()))
		}

		response.JSON(w, http.StatusCreated, nil)
	}
}

// DeleteBy is the delete handler
func (c *Controller) DeleteBy() http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		name := router.URLParam(r, "name")

		span := opentracing.FromContext(r.Context(), "datastore.Remove")
		err := c.repo.Remove(name)
		span.Finish()

		if err != nil {
			panic(errors.New(http.StatusInternalServerError, err.Error()))
		}

		c.dispatch(notifier.NoticeOAuthServerRemoved)
		response.JSON(w, http.StatusNoContent, nil)
	}
}

func (c *Controller) dispatch(cmd notifier.NotificationCommand) {
	if c.notifier != nil {
		c.notifier.Notify(notifier.Notification{Command: cmd})
	}
}
<commit_msg>Fixed bug<commit_after>package oauth

import (
	"net/http"

	"github.com/hellofresh/janus/pkg/errors"
	"github.com/hellofresh/janus/pkg/notifier"
	"github.com/hellofresh/janus/pkg/opentracing"
	"github.com/hellofresh/janus/pkg/request"
	"github.com/hellofresh/janus/pkg/response"
	"github.com/hellofresh/janus/pkg/router"
)

// Controller is the api rest controller
type Controller struct {
	repo     Repository
	notifier notifier.Notifier
}

// NewController creates a new instance of Controller
func NewController(repo Repository, notifier notifier.Notifier) *Controller {
	return &Controller{repo, notifier}
}

// Get is the find all handler
func (c *Controller) Get() http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		span := opentracing.FromContext(r.Context(), "datastore.FindAll")
		data, err := c.repo.FindAll()
		span.Finish()

		if err != nil {
			panic(err.Error())
		}

		response.JSON(w, http.StatusOK, data)
	}
}

// GetBy is the find by handler
func (c *Controller) GetBy() http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		name := router.URLParam(r, "name")
		span := opentracing.FromContext(r.Context(), "datastore.FindByName")
		data, err := c.repo.FindByName(name)
		span.Finish()

		if err != nil {
			if err == ErrOauthServerNotFound {
				panic(err)
			}

			panic(errors.New(http.StatusInternalServerError, err.Error()))
		}

		response.JSON(w, http.StatusOK, data)
	}
}

// PutBy is the update handler
func (c *Controller) PutBy() http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		var err error
		name := router.URLParam(r, "name")

		span := opentracing.FromContext(r.Context(), "datastore.FindByName")
		oauth, err := c.repo.FindByName(name)
		span.Finish()

		if oauth.Name == "" {
			panic(ErrOauthServerNotFound)
		}

		if err != nil {
			panic(errors.New(http.StatusInternalServerError, err.Error()))
		}

		err = request.BindJSON(r, oauth)
		if nil != err {
			panic(errors.New(http.StatusInternalServerError, err.Error()))
		}

		span = opentracing.FromContext(r.Context(), "datastore.Add")
		err = c.repo.Add(oauth)
		c.dispatch(notifier.NoticeOAuthServerUpdated)
		span.Finish()

		if nil != err {
			panic(errors.New(http.StatusBadRequest, err.Error()))
		}

		response.JSON(w, http.StatusOK, nil)
	}
}

// Post is the create handler
func (c *Controller) Post() http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		var oauth OAuth

		err := request.BindJSON(r, &oauth)
		if nil != err {
			panic(errors.New(http.StatusInternalServerError, err.Error()))
		}

		span := opentracing.FromContext(r.Context(), "datastore.Add")
		err = c.repo.Add(&oauth)
		c.dispatch(notifier.NoticeOAuthServerAdded)
		span.Finish()

		if nil != err {
			panic(errors.New(http.StatusBadRequest, err.Error()))
		}

		response.JSON(w, http.StatusCreated, nil)
	}
}

// DeleteBy is the delete handler
func (c *Controller) DeleteBy() http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		name := router.URLParam(r, "name")

		span := opentracing.FromContext(r.Context(), "datastore.Remove")
		err := c.repo.Remove(name)
		span.Finish()

		if err != nil {
			panic(errors.New(http.StatusInternalServerError, err.Error()))
		}

		c.dispatch(notifier.NoticeOAuthServerRemoved)
		response.JSON(w, http.StatusNoContent, nil)
	}
}

func (c *Controller) dispatch(cmd notifier.NotificationCommand) {
	if c.notifier != nil {
		c.notifier.Notify(notifier.Notification{Command: cmd})
	}
}
<|endoftext|>