<commit_before>package domains

import (
	"fmt"
	"io"
	"net/http"
	"strconv"
	"strings"

	"getmelange.com/backend/framework"
	"getmelange.com/backend/info"

	adErrors "airdispat.ch/errors"
)

// TODO: Refactor file so that it doesn't handle the fetching of
// AirDispatch Data messages. This should be included somewhere in the
// regular API so that clients can access it directly.

// HandleData will resolve URLs that occur on the Data domain.
//
// This involves more work than the other non-API domains since it
// must fetch the AirDispatch data message and return it to the
// client.
func HandleData(
	res http.ResponseWriter,
	req *http.Request,
	env *info.Environment,
) {
	path := req.URL.Path
	components := strings.Split(path, "/")[1:]

	// Really need at least two
	if len(components) < 2 {
		return
	}

	user := components[0]
	name := strings.Join(components[1:], "/")

	dataMessage, conn, err := env.Manager.Client.GetDataMessage(name, user)
	if aerr, ok := err.(*adErrors.Error); ok {
		if aerr.Code == 5 {
			framework.WriteView(framework.Error404, res)
			return
		}
	}

	defer conn.Close()

	if err != nil {
		fmt.Println("[DATA] Received error getting data message", name, user)
		fmt.Println("[DATA]", err)
		framework.WriteView(framework.Error500, res)
		return
	}

	if dataMessage.Filename != "" {
		cd := fmt.Sprintf(`inline; filename="%s"`, dataMessage.Filename)
		res.Header().Add("Content-Disposition", cd)
	}

	res.Header().Add("Content-Length", strconv.Itoa(int(dataMessage.TrueLength())))

	decrypted, err := dataMessage.DecryptReader(conn)
	if err != nil {
		fmt.Println("Error decrypting data", err)
		framework.WriteView(framework.Error500, res)
		return
	}

	_, err = io.Copy(res, decrypted)
	if err != nil {
		fmt.Println("Error writing data", err)
		framework.WriteView(framework.Error500, res)
		return
	}

	// Well, now we're screwed
	if !dataMessage.VerifyPayload() {
		fmt.Println("Wait! That was totally not real!")
	}
}
<commit_msg>backend/domains: fixed error with closing unopened connection<commit_after>package domains

import (
	"fmt"
	"io"
	"net/http"
	"strconv"
	"strings"

	"getmelange.com/backend/framework"
	"getmelange.com/backend/info"

	adErrors "airdispat.ch/errors"
)

// TODO: Refactor file so that it doesn't handle the fetching of
// AirDispatch Data messages. This should be included somewhere in the
// regular API so that clients can access it directly.

// HandleData will resolve URLs that occur on the Data domain.
//
// This involves more work than the other non-API domains since it
// must fetch the AirDispatch data message and return it to the
// client.
func HandleData(
	res http.ResponseWriter,
	req *http.Request,
	env *info.Environment,
) {
	path := req.URL.Path
	components := strings.Split(path, "/")[1:]

	// Really need at least two
	if len(components) < 2 {
		return
	}

	user := components[0]
	name := strings.Join(components[1:], "/")

	dataMessage, conn, err := env.Manager.Client.GetDataMessage(name, user)
	if aerr, ok := err.(*adErrors.Error); ok {
		if aerr.Code == 5 {
			framework.WriteView(framework.Error404, res)
			return
		}
	}

	if err != nil {
		fmt.Println("[DATA] Received error getting data message", name, user)
		fmt.Println("[DATA]", err)
		framework.WriteView(framework.Error500, res)
		return
	}

	defer conn.Close()

	if dataMessage.Filename != "" {
		cd := fmt.Sprintf(`inline; filename="%s"`, dataMessage.Filename)
		res.Header().Add("Content-Disposition", cd)
	}

	res.Header().Add("Content-Length", strconv.Itoa(int(dataMessage.TrueLength())))

	decrypted, err := dataMessage.DecryptReader(conn)
	if err != nil {
		fmt.Println("Error decrypting data", err)
		framework.WriteView(framework.Error500, res)
		return
	}

	_, err = io.Copy(res, decrypted)
	if err != nil {
		fmt.Println("Error writing data", err)
		framework.WriteView(framework.Error500, res)
		return
	}

	// Well, now we're screwed
	if !dataMessage.VerifyPayload() {
		fmt.Println("Wait! That was totally not real!")
	}
}
<|endoftext|>


<commit_before>// Copyright © 2016 NAME HERE <EMAIL ADDRESS>
//
// 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 generate

import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	"github.com/aymerick/raymond"
	"github.com/bep/inflect"
	"github.com/markbates/gentronics"
	"github.com/spf13/cobra"
)

//ActionCmd is the cmd that generates actions.
var ActionCmd = &cobra.Command{
	Use:     "action [name] [actionName...]",
	Aliases: []string{"a"},
	Short:   "Generates new action(s)",
	RunE: func(cmd *cobra.Command, args []string) error {
		if len(args) < 2 {
			return errors.New("you should provide action name and handler name at least")
		}

		if _, err := os.Stat("actions"); err != nil {
			return errors.New("actions directory not found, ensure you're inside your buffalo folder")
		}

		name := args[0]
		actions := args[1:]

		data := gentronics.Data{"under": inflect.Underscore(name)}
		_, err := os.Stat(filepath.Join("actions", fmt.Sprintf("%v.go", data["under"])))
		fileExists := err == nil

		if !fileExists {
			g := gentronics.New()
			g.Add(gentronics.NewFile(filepath.Join("actions", fmt.Sprintf("%s.go", data["under"])), rActionFileT))
			g.Add(gentronics.NewFile(filepath.Join("actions", fmt.Sprintf("%s_test.go", data["under"])), rActionTest))
			g.Add(Fmt)

			err = g.Run(".", data)

			if err != nil {
				return err
			}
		}

		return generateActionComponents(name, actions)
	},
}

func generateActionComponents(name string, actions []string) error {

	actionData := gentronics.Data{
		"name":  name,
		"under": inflect.Underscore(name),
	}

	path := filepath.Join("actions", fmt.Sprintf("%v.go", actionData["under"]))
	_, err := os.Stat(path)
	fileExists := err == nil
	fileContents, _ := ioutil.ReadFile(path)

	for _, action := range actions {
		actionData["namespace"] = inflect.Camelize(name)
		actionData["action"] = inflect.Camelize(action)
		actionData["action_under"] = inflect.Underscore(action)

		if fileExists {
			funcSignature := fmt.Sprintf("func %s%s(c buffalo.Context) error", actionData["namespace"], actionData["currentAction"])
			if strings.Contains(string(fileContents), funcSignature) {
				fmt.Printf("--> [warning] skipping %v%v since it already exists\n", actionData["namespace"], actionData["currentAction"])
				continue
			}
		}

		if err = appendActionToFile(path, actionData); err != nil {
			return err
		}

		if err = generateTemplate(actionData); err != nil {
			return err
		}
	}

	return nil
}

func appendActionToFile(path string, actionData gentronics.Data) error {
	fileContents, _ := ioutil.ReadFile(path)
	t, _ := raymond.Parse(rActionFuncT)
	fn, _ := t.Exec(actionData)

	fileContents = []byte(string(fileContents) + fn)
	return ioutil.WriteFile(path, fileContents, 0755)
}

func generateTemplate(actionData gentronics.Data) error {
	fg := gentronics.New()
	templatePath := filepath.Join("templates", fmt.Sprintf("%s", actionData["under"]), fmt.Sprintf("%s.html", actionData["action_under"]))
	fg.Add(gentronics.NewFile(templatePath, rViewT))
	return fg.Run(".", actionData)
}

const (
	rActionFileT = `package actions

import "github.com/gobuffalo/buffalo"

`
	rViewT       = `<h1>{{namespace}}#{{action}}</h1>`
	rActionFuncT = `

    // {{namespace}}{{action}} default implementation.
    func {{namespace}}{{action}}(c buffalo.Context) error {
	    return c.Render(200, r.String("{{camel}}#{{.}}"))
    }
    `

	rActionTestT = `
func Test_{{namespace}}{{action}}(t *testing.T) {
	r := require.New(t)
	r.Fail("Not Implemented!")
}
    `
)
<commit_msg>disabling Fmt to check its the cause of the broken build<commit_after>// Copyright © 2016 NAME HERE <EMAIL ADDRESS>
//
// 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 generate

import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	"github.com/aymerick/raymond"
	"github.com/bep/inflect"
	"github.com/markbates/gentronics"
	"github.com/spf13/cobra"
)

//ActionCmd is the cmd that generates actions.
var ActionCmd = &cobra.Command{
	Use:     "action [name] [actionName...]",
	Aliases: []string{"a"},
	Short:   "Generates new action(s)",
	RunE: func(cmd *cobra.Command, args []string) error {
		if len(args) < 2 {
			return errors.New("you should provide action name and handler name at least")
		}

		if _, err := os.Stat("actions"); err != nil {
			return errors.New("actions directory not found, ensure you're inside your buffalo folder")
		}

		name := args[0]
		actions := args[1:]

		data := gentronics.Data{"under": inflect.Underscore(name)}
		_, err := os.Stat(filepath.Join("actions", fmt.Sprintf("%v.go", data["under"])))
		fileExists := err == nil

		if !fileExists {
			g := gentronics.New()
			g.Add(gentronics.NewFile(filepath.Join("actions", fmt.Sprintf("%s.go", data["under"])), rActionFileT))
			g.Add(gentronics.NewFile(filepath.Join("actions", fmt.Sprintf("%s_test.go", data["under"])), rActionTest))
			//g.Add(Fmt)

			err = g.Run(".", data)

			if err != nil {
				return err
			}
		}

		return generateActionComponents(name, actions)
	},
}

func generateActionComponents(name string, actions []string) error {

	actionData := gentronics.Data{
		"name":  name,
		"under": inflect.Underscore(name),
	}

	path := filepath.Join("actions", fmt.Sprintf("%v.go", actionData["under"]))
	_, err := os.Stat(path)
	fileExists := err == nil
	fileContents, _ := ioutil.ReadFile(path)

	for _, action := range actions {
		actionData["namespace"] = inflect.Camelize(name)
		actionData["action"] = inflect.Camelize(action)
		actionData["action_under"] = inflect.Underscore(action)

		if fileExists {
			funcSignature := fmt.Sprintf("func %s%s(c buffalo.Context) error", actionData["namespace"], actionData["currentAction"])
			if strings.Contains(string(fileContents), funcSignature) {
				fmt.Printf("--> [warning] skipping %v%v since it already exists\n", actionData["namespace"], actionData["currentAction"])
				continue
			}
		}

		if err = appendActionToFile(path, actionData); err != nil {
			return err
		}

		if err = generateTemplate(actionData); err != nil {
			return err
		}
	}

	return nil
}

func appendActionToFile(path string, actionData gentronics.Data) error {
	fileContents, _ := ioutil.ReadFile(path)
	t, _ := raymond.Parse(rActionFuncT)
	fn, _ := t.Exec(actionData)

	fileContents = []byte(string(fileContents) + fn)
	return ioutil.WriteFile(path, fileContents, 0755)
}

func generateTemplate(actionData gentronics.Data) error {
	fg := gentronics.New()
	templatePath := filepath.Join("templates", fmt.Sprintf("%s", actionData["under"]), fmt.Sprintf("%s.html", actionData["action_under"]))
	fg.Add(gentronics.NewFile(templatePath, rViewT))
	return fg.Run(".", actionData)
}

const (
	rActionFileT = `package actions

import "github.com/gobuffalo/buffalo"

`
	rViewT       = `<h1>{{namespace}}#{{action}}</h1>`
	rActionFuncT = `

    // {{namespace}}{{action}} default implementation.
    func {{namespace}}{{action}}(c buffalo.Context) error {
	    return c.Render(200, r.String("{{camel}}#{{.}}"))
    }
    `

	rActionTestT = `
func Test_{{namespace}}{{action}}(t *testing.T) {
	r := require.New(t)
	r.Fail("Not Implemented!")
}
    `
)
<|endoftext|>


<commit_before>/*
   Nging is a toolbox for webmasters
   Copyright (C) 2018-present  Wenhui Shen <swh@admpub.com>

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Affero General Public License as published
   by the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Affero General Public License for more details.

   You should have received a copy of the GNU Affero General Public License
   along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

package config

import (
	"io"
	"os"

	"github.com/admpub/log"
	"github.com/webx-top/com"
)

func (c *CLIConfig) CaddyStopHistory() (err error) {
	if DefaultConfig == nil {
		return nil
	}
	return com.CloseProcessFromPidFile(DefaultConfig.Caddy.PidFile)
}

func (c *CLIConfig) CaddyStart(writer ...io.Writer) (err error) {
	err = c.CaddyStopHistory()
	if err != nil {
		log.Error(err.Error())
	}
	params := []string{os.Args[0], `--config`, c.Conf, `--type`, `webserver`}
	c.caddyCh = com.NewCmdChanReader()
	c.cmds["caddy"] = com.RunCmdWithReaderWriter(params, c.caddyCh, writer...)
	return nil
}

func (c *CLIConfig) CaddyStop() error {
	defer func() {
		if c.caddyCh != nil {
			c.caddyCh.Close()
			c.caddyCh = nil
		}
	}()
	return c.CmdStop("caddy")
}

var eol = []byte("\n")

func (c *CLIConfig) CaddyReload() error {
	if c.caddyCh == nil {
		return c.CaddyRestart()
	}
	c.caddyCh.Send(eol)
	return nil
}

func (c *CLIConfig) CaddyRestart(writer ...io.Writer) error {
	err := c.CaddyStop()
	if err != nil {
		log.Error(err)
	}
	return c.CaddyStart(writer...)
}
<commit_msg>update<commit_after>/*
   Nging is a toolbox for webmasters
   Copyright (C) 2018-present  Wenhui Shen <swh@admpub.com>

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Affero General Public License as published
   by the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Affero General Public License for more details.

   You should have received a copy of the GNU Affero General Public License
   along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

package config

import (
	"io"
	"os"

	"github.com/admpub/log"
	"github.com/webx-top/com"
)

func (c *CLIConfig) CaddyStopHistory() (err error) {
	if DefaultConfig == nil {
		return nil
	}
	return com.CloseProcessFromPidFile(DefaultConfig.Caddy.PidFile)
}

func (c *CLIConfig) CaddyStart(writer ...io.Writer) (err error) {
	err = c.CaddyStopHistory()
	if err != nil {
		log.Error(err.Error())
	}
	params := []string{os.Args[0], `--config`, c.Conf, `--type`, `webserver`}
	c.caddyCh = com.NewCmdChanReader()
	c.cmds["caddy"] = com.RunCmdWithReaderWriter(params, c.caddyCh, writer...)
	return nil
}

func (c *CLIConfig) CaddyStop() error {
	defer func() {
		if c.caddyCh != nil {
			c.caddyCh.Close()
			c.caddyCh = nil
		}
	}()
	return c.CmdStop("caddy")
}

var eol = []byte("\n")

func (c *CLIConfig) CaddyReload() error {
	if c.caddyCh == nil || com.IsWindows { //windows不支持重载，需要重启
		return c.CaddyRestart()
	}
	c.caddyCh.Send(eol)
	return nil
}

func (c *CLIConfig) CaddyRestart(writer ...io.Writer) error {
	err := c.CaddyStop()
	if err != nil {
		log.Error(err)
	}
	return c.CaddyStart(writer...)
}
<|endoftext|>


<commit_before>/*
   Nging is a toolbox for webmasters
   Copyright (C) 2018-present  Wenhui Shen <swh@admpub.com>

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Affero General Public License as published
   by the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Affero General Public License for more details.

   You should have received a copy of the GNU Affero General Public License
   along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

package config

import (
	"reflect"
	"strings"

	"github.com/webx-top/echo"
	"github.com/webx-top/echo/subdomains"

	"github.com/admpub/log"
	"github.com/admpub/nging/v3/application/library/common"
	"github.com/admpub/nging/v3/application/library/notice"
	"github.com/admpub/nging/v3/application/registry/settings"
)

var Setting = common.Setting

func NewSettings(config *Config) *Settings {
	c := &Settings{
		config: config,
	}
	return c
}

type Settings struct {
	Email              Email  `json:"email"`
	Log                Log    `json:"log"`
	APIKey             string `json:"-"` //API密钥
	Debug              bool   `json:"debug"`
	MaxRequestBodySize int    `json:"maxRequestBodySize"`
	Base               echo.H `json:"base"`
	config             *Config
}

func (c *Settings) SetBy(r echo.H, defaults echo.H) *Settings {
	if !r.Has(`base`) && defaults != nil {
		r.Set(`base`, defaults.GetStore(`base`))
	}
	c.Base = r.GetStore(`base`)
	c.APIKey = c.Base.String(`apiKey`)
	c.Debug = c.Base.Bool(`debug`)
	c.MaxRequestBodySize = c.Base.Int(`maxRequestBodySize`)
	return c
}

func (c *Settings) SetDebug(on bool) {
	c.Log.Debug = on
	c.Debug = on

	c.config.DB.SetDebug(on)
	notice.SetDebug(on)
	if on {
		log.Info(`Currently running in debug mode`)
		log.SetLevel(`Debug`)
	} else {
		log.Info(`Currently running in normal mode`)
		log.SetLevel(`Info`)
	}
	subdomains.Default.SetDebug(on)
}

var (
	actGroups          = []string{`base`, `smtp`, `log`}
	onKeySetSettings   = map[string][]func(Diff) error{}
	onGroupSetSettings = map[string][]func(Diffs) error{}
)

func OnGroupSetSettings(groupAndKey string, fn func(Diffs) error) {
	if _, ok := onGroupSetSettings[groupAndKey]; !ok {
		onGroupSetSettings[groupAndKey] = []func(Diffs) error{}
	}
	onGroupSetSettings[groupAndKey] = append(onGroupSetSettings[groupAndKey], fn)
}

func OnKeySetSettings(groupAndKey string, fn func(Diff) error) {
	if _, ok := onKeySetSettings[groupAndKey]; !ok {
		onKeySetSettings[groupAndKey] = []func(Diff) error{}
	}
	onKeySetSettings[groupAndKey] = append(onKeySetSettings[groupAndKey], fn)
}

func FireInitSettings(configs echo.H) error {
	for group, fnList := range onGroupSetSettings {
		values := configs.GetStore(group)
		diffs := Diffs{}
		for k, v := range values {
			diffs[k] = &Diff{
				Old: v,
				New: v,
			}
		}
		for _, fn := range fnList {
			if err := fn(diffs); err != nil {
				return err
			}
		}
	}
	for groupAndKey, fnList := range onKeySetSettings {
		args := strings.SplitN(groupAndKey, `.`, 2)
		values := configs.GetStore(args[0])
		var val interface{}
		if len(args) == 2 {
			val = values.Get(args[1])
		} else {
			val = values
		}
		for _, fn := range fnList {
			if err := fn(Diff{
				Old: val,
				New: val,
			}); err != nil {
				return err
			}
		}
	}
	return nil
}

func FireSetSettings(group string, diffs Diffs) error {
	if fnList, ok := onGroupSetSettings[group]; ok {
		for _, fn := range fnList {
			if err := fn(diffs); err != nil {
				return err
			}
		}
	}
	for key, diff := range diffs {
		k := group + `.` + key
		if fnList, ok := onKeySetSettings[k]; ok {
			for _, fn := range fnList {
				if err := fn(*diff); err != nil {
					return err
				}
			}
		}
	}
	return nil
}

func (c *Settings) Init(ctx echo.Context) error {
	if ctx == nil {
		ctx = common.NewMockContext()
	}
	defaults := settings.ConfigDefaultsAsStore()
	var configs = defaults
	if IsInstalled() {
		if c.config.ConnectedDB() {
			configs = settings.ConfigAsStore(ctx)
		}
	}
	echo.Set(`NgingConfig`, configs)
	for _, group := range actGroups {
		c.SetConfig(group, configs, defaults)
	}
	return FireInitSettings(configs)
}

func (c *Settings) GetConfig() echo.H {
	r, _ := echo.Get(`NgingConfig`).(echo.H)
	return r
}

type Diff struct {
	Old    interface{}
	New    interface{}
	IsDiff bool
}

func (d Diff) String() string {
	s, _ := d.New.(string)
	return s
}

type Diffs map[string]*Diff

func (d Diffs) Get(key string) interface{} {
	return d[key]
}

func (c *Settings) SetConfigs(ctx echo.Context, groups ...string) error {
	newConfigs := settings.ConfigAsStore(ctx, groups...)
	oldConfigs := c.GetConfig()
	return c.setConfigs(newConfigs, oldConfigs)
}

func (c *Settings) setConfigs(newConfigs echo.H, oldConfigs echo.H) error {
	for group, conf := range newConfigs {
		keyCfg := conf.(echo.H)
		keyOldCfg := oldConfigs.GetStore(group)
		diffs := Diffs{}
		for k, v := range keyCfg {
			if !reflect.DeepEqual(keyOldCfg.Get(k), v) {
				diffs[k] = &Diff{
					Old:    keyOldCfg.Get(k),
					New:    v,
					IsDiff: true,
				}
			}
		}
		if len(diffs) == 0 {
			continue
		}
		oldConfigs.Set(group, keyCfg)
		if err := FireSetSettings(group, diffs); err != nil {
			return err
		}
		//log.Debug(`Change configuration:`, group, `:`, echo.Dump(conf, false))
		c.SetConfig(group, oldConfigs, nil)
	}
	return nil
}

func (c *Settings) SetConfig(group string, ngingConfig echo.H, defaults echo.H) {
	switch group {
	case `base`:
		c.SetBy(ngingConfig, defaults)
		c.SetDebug(c.Debug)
	case `smtp`:
		c.Email.SetBy(ngingConfig, defaults).Init()
	case `log`:
		c.Log.SetBy(ngingConfig, defaults).Init()
	}
}
<commit_msg>update<commit_after>/*
   Nging is a toolbox for webmasters
   Copyright (C) 2018-present  Wenhui Shen <swh@admpub.com>

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Affero General Public License as published
   by the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Affero General Public License for more details.

   You should have received a copy of the GNU Affero General Public License
   along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

package config

import (
	"reflect"
	"strings"

	"github.com/webx-top/echo"
	"github.com/webx-top/echo/subdomains"

	"github.com/admpub/log"
	"github.com/admpub/nging/v3/application/library/common"
	"github.com/admpub/nging/v3/application/library/notice"
	"github.com/admpub/nging/v3/application/registry/settings"
)

var Setting = common.Setting

func NewSettings(config *Config) *Settings {
	c := &Settings{
		config: config,
	}
	return c
}

type Settings struct {
	Email              Email  `json:"email"`
	Log                Log    `json:"log"`
	APIKey             string `json:"-"` //API密钥
	Debug              bool   `json:"debug"`
	MaxRequestBodySize int    `json:"maxRequestBodySize"`
	Base               echo.H `json:"base"`
	config             *Config
}

func (c *Settings) SetBy(r echo.H, defaults echo.H) *Settings {
	if !r.Has(`base`) && defaults != nil {
		r.Set(`base`, defaults.GetStore(`base`))
	}
	c.Base = r.GetStore(`base`)
	c.APIKey = c.Base.String(`apiKey`)
	c.Debug = c.Base.Bool(`debug`)
	c.MaxRequestBodySize = c.Base.Int(`maxRequestBodySize`)
	return c
}

func (c *Settings) SetDebug(on bool) {
	c.Log.Debug = on
	c.Debug = on

	c.config.DB.SetDebug(on)
	notice.SetDebug(on)
	if on {
		log.Info(`Currently running in debug mode`)
		log.SetLevel(`Debug`)
	} else {
		log.Info(`Currently running in normal mode`)
		log.SetLevel(`Info`)
	}
	subdomains.Default.SetDebug(on)
}

var (
	actGroups          = []string{`base`, `smtp`, `log`}
	onKeySetSettings   = map[string][]func(Diff) error{}
	onGroupSetSettings = map[string][]func(Diffs) error{}
)

func OnGroupSetSettings(groupAndKey string, fn func(Diffs) error) {
	if _, ok := onGroupSetSettings[groupAndKey]; !ok {
		onGroupSetSettings[groupAndKey] = []func(Diffs) error{}
	}
	onGroupSetSettings[groupAndKey] = append(onGroupSetSettings[groupAndKey], fn)
}

func OnKeySetSettings(groupAndKey string, fn func(Diff) error) {
	if _, ok := onKeySetSettings[groupAndKey]; !ok {
		onKeySetSettings[groupAndKey] = []func(Diff) error{}
	}
	onKeySetSettings[groupAndKey] = append(onKeySetSettings[groupAndKey], fn)
}

func FireInitSettings(configs echo.H) error {
	for group, fnList := range onGroupSetSettings {
		values := configs.GetStore(group)
		diffs := Diffs{}
		for k, v := range values {
			diffs[k] = &Diff{
				Old: v,
				New: v,
			}
		}
		for _, fn := range fnList {
			if err := fn(diffs); err != nil {
				return err
			}
		}
	}
	for groupAndKey, fnList := range onKeySetSettings {
		args := strings.SplitN(groupAndKey, `.`, 2)
		values := configs.GetStore(args[0])
		var val interface{}
		if len(args) == 2 {
			val = values.Get(args[1])
		} else {
			val = values
		}
		for _, fn := range fnList {
			if err := fn(Diff{
				Old: val,
				New: val,
			}); err != nil {
				return err
			}
		}
	}
	return nil
}

func FireSetSettings(group string, diffs Diffs) error {
	if fnList, ok := onGroupSetSettings[group]; ok {
		for _, fn := range fnList {
			if err := fn(diffs); err != nil {
				return err
			}
		}
	}
	for key, diff := range diffs {
		k := group + `.` + key
		if fnList, ok := onKeySetSettings[k]; ok {
			for _, fn := range fnList {
				if err := fn(*diff); err != nil {
					return err
				}
			}
		}
	}
	return nil
}

func (c *Settings) Init(ctx echo.Context) error {
	if ctx == nil {
		ctx = common.NewMockContext()
	}
	defaults := settings.ConfigDefaultsAsStore()
	var configs = defaults
	if IsInstalled() {
		if c.config.ConnectedDB() {
			configs = settings.ConfigAsStore(ctx)
		}
	}
	echo.Set(`NgingConfig`, configs)
	for _, group := range actGroups {
		c.SetConfig(group, configs, defaults)
	}
	return FireInitSettings(configs)
}

func (c *Settings) GetConfig() echo.H {
	r, _ := echo.Get(`NgingConfig`).(echo.H)
	return r
}

type Diff struct {
	Old    interface{}
	New    interface{}
	IsDiff bool
}

func (d Diff) String() string {
	s, _ := d.New.(string)
	return s
}

type Diffs map[string]*Diff

func (d Diffs) Get(key string) interface{} {
	return d[key]
}

func (c *Settings) SetConfigs(ctx echo.Context, groups ...string) error {
	newConfigs := settings.ConfigAsStore(ctx, groups...)
	oldConfigs := c.GetConfig()
	return c.setConfigs(newConfigs, oldConfigs)
}

func (c *Settings) setConfigs(newConfigs echo.H, oldConfigs echo.H) error {
	for group, conf := range newConfigs {
		keyCfg := conf.(echo.H)
		keyOldCfg := oldConfigs.GetStore(group)
		diffs := Diffs{}
		for k, v := range keyCfg {
			if !reflect.DeepEqual(keyOldCfg.Get(k), v) {
				diffs[k] = &Diff{
					Old:    keyOldCfg.Get(k),
					New:    v,
					IsDiff: true,
				}
			}
		}
		if len(diffs) == 0 {
			continue
		}
		oldConfigs.Set(group, keyCfg)
		if err := FireSetSettings(group, diffs); err != nil {
			return err
		}
		//log.Debug(`Change configuration:`, group, `:`, echo.Dump(conf, false))
		c.SetConfig(group, oldConfigs, nil)
	}
	for group := range oldConfigs {
		if !newConfigs.Has(group) {
			oldConfigs.Delete(group)
		}
	}
	return nil
}

func (c *Settings) SetConfig(group string, ngingConfig echo.H, defaults echo.H) {
	switch group {
	case `base`:
		c.SetBy(ngingConfig, defaults)
		c.SetDebug(c.Debug)
	case `smtp`:
		c.Email.SetBy(ngingConfig, defaults).Init()
	case `log`:
		c.Log.SetBy(ngingConfig, defaults).Init()
	}
}
<|endoftext|>


<commit_before>package pachyderm

import (
	"bytes"
	"fmt"
	"log"
	"os"
	"path"
	"strings"
	"testing"

	"golang.org/x/net/context"

	"github.com/pachyderm/pachyderm/src/pfs"
	"github.com/pachyderm/pachyderm/src/pfs/pfsutil"
	"github.com/pachyderm/pachyderm/src/pkg/require"
	"github.com/pachyderm/pachyderm/src/pkg/uuid"
	"github.com/pachyderm/pachyderm/src/pps"
	"github.com/pachyderm/pachyderm/src/pps/ppsutil"
	"google.golang.org/grpc"
)

func TestJob(t *testing.T) {
	dataRepo := uniqueString("TestJob.data")
	pfsClient := getPfsClient(t)
	require.NoError(t, pfsutil.CreateRepo(pfsClient, dataRepo))
	commit, err := pfsutil.StartCommit(pfsClient, dataRepo, "")
	require.NoError(t, err)
	_, err = pfsutil.PutFile(pfsClient, dataRepo, commit.Id, "file", 0, strings.NewReader("foo"))
	require.NoError(t, err)
	require.NoError(t, pfsutil.FinishCommit(pfsClient, dataRepo, commit.Id))
	ppsClient := getPpsClient(t)
	job, err := ppsutil.CreateJob(
		ppsClient,
		"",
		[]string{"cp", path.Join("/pfs", dataRepo, "file"), "/pfs/out/file"},
		"",
		1,
		[]*pfs.Commit{commit},
		"",
	)
	require.NoError(t, err)
	inspectJobRequest := &pps.InspectJobRequest{
		Job:         job,
		BlockOutput: true,
		BlockState:  true,
	}
	jobInfo, err := ppsClient.InspectJob(context.Background(), inspectJobRequest)
	require.NoError(t, err)
	var buffer bytes.Buffer
	require.NoError(t, pfsutil.GetFile(pfsClient, jobInfo.OutputCommit.Repo.Name, jobInfo.OutputCommit.Id, "file", 0, 0, nil, &buffer))
	require.Equal(t, "foo", buffer.String())
}

func TestGrep(t *testing.T) {
	t.Skip()
	dataRepo := uniqueString("pachyderm.TestGrep.data")
	pfsClient := getPfsClient(t)
	require.NoError(t, pfsutil.CreateRepo(pfsClient, dataRepo))
	commit, err := pfsutil.StartCommit(pfsClient, dataRepo, "")
	require.NoError(t, err)
	for i := 0; i < 100; i++ {
		_, err = pfsutil.PutFile(pfsClient, dataRepo, commit.Id, fmt.Sprintf("file%d", i), 0, strings.NewReader("foo\nbar\nfizz\nbuzz\n"))
		require.NoError(t, err)
	}
	require.NoError(t, pfsutil.FinishCommit(pfsClient, dataRepo, commit.Id))
	ppsClient := getPpsClient(t)
	_, err = ppsutil.CreateJob(
		ppsClient,
		"",
		[]string{"sh"},
		fmt.Sprintf("grep foo /pfs/%s/* >/pfs/out/foo", dataRepo),
		1,
		[]*pfs.Commit{commit},
		"",
	)
	require.NoError(t, err)
}

func TestPipeline(t *testing.T) {
	t.Skip()
	pfsClient := getPfsClient(t)
	ppsClient := getPpsClient(t)
	// create repos
	dataRepo := uniqueString("TestPipeline.data")
	require.NoError(t, pfsutil.CreateRepo(pfsClient, dataRepo))
	// create pipeline
	pipelineName := uniqueString("pipeline")
	outRepo := pps.PipelineRepo(ppsutil.NewPipeline(pipelineName))
	require.NoError(t, ppsutil.CreatePipeline(
		ppsClient,
		pipelineName,
		"",
		[]string{"cp", path.Join("/pfs", dataRepo, "file"), "/pfs/out/file"},
		"",
		1,
		[]*pfs.Repo{&pfs.Repo{Name: dataRepo}},
	))
	// Do first commit to repo
	log.Printf("Do first commit.")
	commit1, err := pfsutil.StartCommit(pfsClient, dataRepo, "")
	require.NoError(t, err)
	_, err = pfsutil.PutFile(pfsClient, dataRepo, commit1.Id, "file", 0, strings.NewReader("foo"))
	require.NoError(t, err)
	require.NoError(t, pfsutil.FinishCommit(pfsClient, dataRepo, commit1.Id))
	listCommitRequest := &pfs.ListCommitRequest{
		Repo:       []*pfs.Repo{outRepo},
		CommitType: pfs.CommitType_COMMIT_TYPE_READ,
		Block:      true,
	}
	listCommitResponse, err := pfsClient.ListCommit(
		context.Background(),
		listCommitRequest,
	)
	require.NoError(t, err)
	outCommits := listCommitResponse.CommitInfo
	require.Equal(t, 1, len(outCommits))
	var buffer bytes.Buffer
	log.Printf("First commit: %+v", outCommits[0])
	require.NoError(t, pfsutil.GetFile(pfsClient, outRepo.Name, outCommits[0].Commit.Id, "file", 0, 0, nil, &buffer))
	require.Equal(t, "foo", buffer.String())
	// Do second commit to repo
	log.Printf("Do second commit.")
	commit2, err := pfsutil.StartCommit(pfsClient, dataRepo, commit1.Id)
	require.NoError(t, err)
	_, err = pfsutil.PutFile(pfsClient, dataRepo, commit2.Id, "file", 0, strings.NewReader("bar"))
	require.NoError(t, err)
	require.NoError(t, pfsutil.FinishCommit(pfsClient, dataRepo, commit2.Id))
	listCommitRequest = &pfs.ListCommitRequest{
		Repo:       []*pfs.Repo{outRepo},
		FromCommit: []*pfs.Commit{outCommits[0].Commit},
		CommitType: pfs.CommitType_COMMIT_TYPE_READ,
		Block:      true,
	}
	listCommitResponse, err = pfsClient.ListCommit(
		context.Background(),
		listCommitRequest,
	)
	require.NoError(t, err)
	outCommits = listCommitResponse.CommitInfo
	require.Equal(t, 1, len(outCommits))
	buffer = bytes.Buffer{}
	log.Printf("Second commit: %+v", outCommits[0])
	require.NoError(t, pfsutil.GetFile(pfsClient, outRepo.Name, outCommits[0].Commit.Id, "file", 0, 0, nil, &buffer))
	require.Equal(t, "foobar", buffer.String())
}

func getPfsClient(t *testing.T) pfs.APIClient {
	pfsdAddr := os.Getenv("PFSD_PORT_650_TCP_ADDR")
	if pfsdAddr == "" {
		t.Error("PFSD_PORT_650_TCP_ADDR not set")
	}
	clientConn, err := grpc.Dial(fmt.Sprintf("%s:650", pfsdAddr), grpc.WithInsecure())
	require.NoError(t, err)
	return pfs.NewAPIClient(clientConn)
}

func getPpsClient(t *testing.T) pps.APIClient {
	ppsdAddr := os.Getenv("PPSD_PORT_651_TCP_ADDR")
	if ppsdAddr == "" {
		t.Error("PPSD_PORT_651_TCP_ADDR not set")
	}
	clientConn, err := grpc.Dial(fmt.Sprintf("%s:651", ppsdAddr), grpc.WithInsecure())
	require.NoError(t, err)
	return pps.NewAPIClient(clientConn)
}

func uniqueString(prefix string) string {
	return prefix + "." + uuid.NewWithoutDashes()[0:12]
}
<commit_msg>Make pachyderm_test.go harder.<commit_after>package pachyderm

import (
	"bytes"
	"fmt"
	"log"
	"os"
	"path"
	"strings"
	"testing"

	"golang.org/x/net/context"

	"github.com/pachyderm/pachyderm/src/pfs"
	"github.com/pachyderm/pachyderm/src/pfs/pfsutil"
	"github.com/pachyderm/pachyderm/src/pkg/require"
	"github.com/pachyderm/pachyderm/src/pkg/uuid"
	"github.com/pachyderm/pachyderm/src/pps"
	"github.com/pachyderm/pachyderm/src/pps/ppsutil"
	"google.golang.org/grpc"
)

func TestJob(t *testing.T) {
	dataRepo := uniqueString("TestJob.data")
	pfsClient := getPfsClient(t)
	require.NoError(t, pfsutil.CreateRepo(pfsClient, dataRepo))
	commit, err := pfsutil.StartCommit(pfsClient, dataRepo, "")
	require.NoError(t, err)
	_, err = pfsutil.PutFile(pfsClient, dataRepo, commit.Id, "file", 0, strings.NewReader("foo"))
	require.NoError(t, err)
	require.NoError(t, pfsutil.FinishCommit(pfsClient, dataRepo, commit.Id))
	ppsClient := getPpsClient(t)
	job, err := ppsutil.CreateJob(
		ppsClient,
		"",
		[]string{"cp", path.Join("/pfs", dataRepo, "file"), "/pfs/out/file"},
		"",
		1,
		[]*pfs.Commit{commit},
		"",
	)
	require.NoError(t, err)
	inspectJobRequest := &pps.InspectJobRequest{
		Job:         job,
		BlockOutput: true,
		BlockState:  true,
	}
	jobInfo, err := ppsClient.InspectJob(context.Background(), inspectJobRequest)
	require.NoError(t, err)
	require.Equal(t, pps.JobState_JOB_STATE_SUCCESS, jobInfo.State)
	commitInfo, err := pfsutil.InspectCommit(pfsClient, jobInfo.OutputCommit.Repo.Name, jobInfo.OutputCommit.Id)
	require.NoError(t, err)
	require.Equal(t, pfs.CommitType_COMMIT_TYPE_READ, commitInfo.CommitType)
	log.Printf("GetFile: %s/%s/%s", jobInfo.OutputCommit.Repo.Name, jobInfo.OutputCommit.Id, "file")
	var buffer bytes.Buffer
	require.NoError(t, pfsutil.GetFile(pfsClient, jobInfo.OutputCommit.Repo.Name, jobInfo.OutputCommit.Id, "file", 0, 0, nil, &buffer))
	require.Equal(t, "foo", buffer.String())
}

func TestGrep(t *testing.T) {
	t.Skip()
	dataRepo := uniqueString("pachyderm.TestGrep.data")
	pfsClient := getPfsClient(t)
	require.NoError(t, pfsutil.CreateRepo(pfsClient, dataRepo))
	commit, err := pfsutil.StartCommit(pfsClient, dataRepo, "")
	require.NoError(t, err)
	for i := 0; i < 100; i++ {
		_, err = pfsutil.PutFile(pfsClient, dataRepo, commit.Id, fmt.Sprintf("file%d", i), 0, strings.NewReader("foo\nbar\nfizz\nbuzz\n"))
		require.NoError(t, err)
	}
	require.NoError(t, pfsutil.FinishCommit(pfsClient, dataRepo, commit.Id))
	ppsClient := getPpsClient(t)
	_, err = ppsutil.CreateJob(
		ppsClient,
		"",
		[]string{"sh"},
		fmt.Sprintf("grep foo /pfs/%s/* >/pfs/out/foo", dataRepo),
		1,
		[]*pfs.Commit{commit},
		"",
	)
	require.NoError(t, err)
}

func TestPipeline(t *testing.T) {
	t.Skip()
	pfsClient := getPfsClient(t)
	ppsClient := getPpsClient(t)
	// create repos
	dataRepo := uniqueString("TestPipeline.data")
	require.NoError(t, pfsutil.CreateRepo(pfsClient, dataRepo))
	// create pipeline
	pipelineName := uniqueString("pipeline")
	outRepo := pps.PipelineRepo(ppsutil.NewPipeline(pipelineName))
	require.NoError(t, ppsutil.CreatePipeline(
		ppsClient,
		pipelineName,
		"",
		[]string{"cp", path.Join("/pfs", dataRepo, "file"), "/pfs/out/file"},
		"",
		1,
		[]*pfs.Repo{&pfs.Repo{Name: dataRepo}},
	))
	// Do first commit to repo
	log.Printf("Do first commit.")
	commit1, err := pfsutil.StartCommit(pfsClient, dataRepo, "")
	require.NoError(t, err)
	_, err = pfsutil.PutFile(pfsClient, dataRepo, commit1.Id, "file", 0, strings.NewReader("foo"))
	require.NoError(t, err)
	require.NoError(t, pfsutil.FinishCommit(pfsClient, dataRepo, commit1.Id))
	listCommitRequest := &pfs.ListCommitRequest{
		Repo:       []*pfs.Repo{outRepo},
		CommitType: pfs.CommitType_COMMIT_TYPE_READ,
		Block:      true,
	}
	listCommitResponse, err := pfsClient.ListCommit(
		context.Background(),
		listCommitRequest,
	)
	require.NoError(t, err)
	outCommits := listCommitResponse.CommitInfo
	require.Equal(t, 1, len(outCommits))
	var buffer bytes.Buffer
	log.Printf("First commit: %+v", outCommits[0])
	require.NoError(t, pfsutil.GetFile(pfsClient, outRepo.Name, outCommits[0].Commit.Id, "file", 0, 0, nil, &buffer))
	require.Equal(t, "foo", buffer.String())
	// Do second commit to repo
	log.Printf("Do second commit.")
	commit2, err := pfsutil.StartCommit(pfsClient, dataRepo, commit1.Id)
	require.NoError(t, err)
	_, err = pfsutil.PutFile(pfsClient, dataRepo, commit2.Id, "file", 0, strings.NewReader("bar"))
	require.NoError(t, err)
	require.NoError(t, pfsutil.FinishCommit(pfsClient, dataRepo, commit2.Id))
	listCommitRequest = &pfs.ListCommitRequest{
		Repo:       []*pfs.Repo{outRepo},
		FromCommit: []*pfs.Commit{outCommits[0].Commit},
		CommitType: pfs.CommitType_COMMIT_TYPE_READ,
		Block:      true,
	}
	listCommitResponse, err = pfsClient.ListCommit(
		context.Background(),
		listCommitRequest,
	)
	require.NoError(t, err)
	outCommits = listCommitResponse.CommitInfo
	require.Equal(t, 1, len(outCommits))
	buffer = bytes.Buffer{}
	log.Printf("Second commit: %+v", outCommits[0])
	require.NoError(t, pfsutil.GetFile(pfsClient, outRepo.Name, outCommits[0].Commit.Id, "file", 0, 0, nil, &buffer))
	require.Equal(t, "foobar", buffer.String())
}

func getPfsClient(t *testing.T) pfs.APIClient {
	pfsdAddr := os.Getenv("PFSD_PORT_650_TCP_ADDR")
	if pfsdAddr == "" {
		t.Error("PFSD_PORT_650_TCP_ADDR not set")
	}
	clientConn, err := grpc.Dial(fmt.Sprintf("%s:650", pfsdAddr), grpc.WithInsecure())
	require.NoError(t, err)
	return pfs.NewAPIClient(clientConn)
}

func getPpsClient(t *testing.T) pps.APIClient {
	ppsdAddr := os.Getenv("PPSD_PORT_651_TCP_ADDR")
	if ppsdAddr == "" {
		t.Error("PPSD_PORT_651_TCP_ADDR not set")
	}
	clientConn, err := grpc.Dial(fmt.Sprintf("%s:651", ppsdAddr), grpc.WithInsecure())
	require.NoError(t, err)
	return pps.NewAPIClient(clientConn)
}

func uniqueString(prefix string) string {
	return prefix + "." + uuid.NewWithoutDashes()[0:12]
}
<|endoftext|>


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

// Package main defines the CLI interface for GCR Cleaner.
package main

import (
	"context"
	"flag"
	"fmt"
	"os"
	"regexp"
	"runtime"
	"time"

	gcrauthn "github.com/google/go-containerregistry/pkg/authn"
	gcrgoogle "github.com/google/go-containerregistry/pkg/v1/google"
	"github.com/hashicorp/go-multierror"
	"github.com/sethvargo/gcr-cleaner/pkg/gcrcleaner"
)

var (
	stdout = os.Stdout
	stderr = os.Stderr

	tokenPtr       = flag.String("token", os.Getenv("GCRCLEANER_TOKEN"), "Authentication token")
	repoPtr        = flag.String("repo", "", "Repository name")
	recursivePtr   = flag.Bool("recursive", false, "Clean all sub-repositories under the -repo root")
	gracePtr       = flag.Duration("grace", 0, "Grace period")
	allowTaggedPtr = flag.Bool("allow-tagged", false, "Delete tagged images")
	keepPtr        = flag.Int("keep", 0, "Minimum to keep")
	tagFilterPtr   = flag.String("tag-filter", "", "Tags pattern to clean")
)

func main() {
	flag.Parse()

	if err := realMain(); err != nil {
		fmt.Fprintf(stderr, "%s\n", err)
		os.Exit(1)
	}
}

func realMain() error {
	if *repoPtr == "" {
		return fmt.Errorf("missing -repo")
	}

	if *allowTaggedPtr == false && *tagFilterPtr != "" {
		return fmt.Errorf("-allow-tagged must be true when -tag-filter is declared")
	}

	tagFilterRegexp, err := regexp.Compile(*tagFilterPtr)
	if err != nil {
		return fmt.Errorf("failed to parse -tag-filter: %w", err)
	}

	// Try to find the "best" authentication.
	var auther gcrauthn.Authenticator
	if *tokenPtr != "" {
		auther = &gcrauthn.Bearer{Token: *tokenPtr}
	} else {
		var err error
		auther, err = gcrgoogle.NewEnvAuthenticator()
		if err != nil {
			return fmt.Errorf("failed to setup auther: %w", err)
		}
	}

	concurrency := runtime.NumCPU()
	cleaner, err := gcrcleaner.NewCleaner(auther, concurrency)
	if err != nil {
		return fmt.Errorf("failed to create cleaner: %w", err)
	}

	// Convert duration to a negative value, since we're about to "add" it to the
	// since time.
	sub := time.Duration(*gracePtr)
	if *gracePtr > 0 {
		sub = sub * -1
	}
	since := time.Now().UTC().Add(sub)

	// Gather the repositories
	var repositories = make([]string, 0)
	repositories = append(repositories, *repoPtr)
	if *recursivePtr {
		childRepos, err := cleaner.ListChildRepositories(context.Background(), *repoPtr)
		if err != nil {
			return err
		}
		repositories = append(repositories, childRepos...)
	}

	// Do the deletion.
	var result error
	for _, repo := range repositories {
		fmt.Fprintf(stdout, "%s: deleting refs since %s\n", repo, since)
		deleted, err := cleaner.Clean(repo, since, *allowTaggedPtr, *keepPtr, tagFilterRegexp)
		if err != nil {
			result = multierror.Append(result, err)
		}
		fmt.Fprintf(stdout, "%s: successfully deleted %d refs\n", repo, len(deleted))
	}

	return result
}
<commit_msg>Code review comments re: error handling<commit_after>// Copyright 2019 The GCR Cleaner Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package main defines the CLI interface for GCR Cleaner.
package main

import (
	"context"
	"flag"
	"fmt"
	"os"
	"regexp"
	"runtime"
	"time"

	gcrauthn "github.com/google/go-containerregistry/pkg/authn"
	gcrgoogle "github.com/google/go-containerregistry/pkg/v1/google"
	"github.com/hashicorp/go-multierror"
	"github.com/sethvargo/gcr-cleaner/pkg/gcrcleaner"
)

var (
	stdout = os.Stdout
	stderr = os.Stderr

	tokenPtr       = flag.String("token", os.Getenv("GCRCLEANER_TOKEN"), "Authentication token")
	repoPtr        = flag.String("repo", "", "Repository name")
	recursivePtr   = flag.Bool("recursive", false, "Clean all sub-repositories under the -repo root")
	gracePtr       = flag.Duration("grace", 0, "Grace period")
	allowTaggedPtr = flag.Bool("allow-tagged", false, "Delete tagged images")
	keepPtr        = flag.Int("keep", 0, "Minimum to keep")
	tagFilterPtr   = flag.String("tag-filter", "", "Tags pattern to clean")
)

func main() {
	flag.Parse()

	if err := realMain(); err != nil {
		fmt.Fprintf(stderr, "%s\n", err)
		os.Exit(1)
	}
}

func realMain() error {
	if *repoPtr == "" {
		return fmt.Errorf("missing -repo")
	}

	if *allowTaggedPtr == false && *tagFilterPtr != "" {
		return fmt.Errorf("-allow-tagged must be true when -tag-filter is declared")
	}

	tagFilterRegexp, err := regexp.Compile(*tagFilterPtr)
	if err != nil {
		return fmt.Errorf("failed to parse -tag-filter: %w", err)
	}

	// Try to find the "best" authentication.
	var auther gcrauthn.Authenticator
	if *tokenPtr != "" {
		auther = &gcrauthn.Bearer{Token: *tokenPtr}
	} else {
		var err error
		auther, err = gcrgoogle.NewEnvAuthenticator()
		if err != nil {
			return fmt.Errorf("failed to setup auther: %w", err)
		}
	}

	concurrency := runtime.NumCPU()
	cleaner, err := gcrcleaner.NewCleaner(auther, concurrency)
	if err != nil {
		return fmt.Errorf("failed to create cleaner: %w", err)
	}

	// Convert duration to a negative value, since we're about to "add" it to the
	// since time.
	sub := time.Duration(*gracePtr)
	if *gracePtr > 0 {
		sub = sub * -1
	}
	since := time.Now().UTC().Add(sub)

	// Gather the repositories
	var repositories = make([]string, 0)
	repositories = append(repositories, *repoPtr)
	if *recursivePtr {
		childRepos, err := cleaner.ListChildRepositories(context.Background(), *repoPtr)
		if err != nil {
			return err
		}
		repositories = append(repositories, childRepos...)
	}

	// Do the deletion.
	var result *multierror.Error
	for _, repo := range repositories {
		fmt.Fprintf(stdout, "%s: deleting refs since %s\n", repo, since)
		deleted, err := cleaner.Clean(repo, since, *allowTaggedPtr, *keepPtr, tagFilterRegexp)
		if err != nil {
			result = multierror.Append(result, err)
		}
		fmt.Fprintf(stdout, "%s: successfully deleted %d refs\n", repo, len(deleted))
	}

	return result.ErrorOrNil()
}
<|endoftext|>


<commit_before>// A trivial redirector for google.golang.org.
package main

import (
	"fmt"
	"html/template"
	"net/http"
	"os"
	"strings"
)

var repoMap = map[string]*repoImport{
	"api": {
		VCS: "git",
		URL: "https://code.googlesource.com/google-api-go-client",
		Src: github("google/google-api-go-client"),
	},
	"appengine": {
		VCS: "git",
		URL: "https://github.com/golang/appengine",
		Src: github("golang/appengine"),
	},
	"cloud": {
		// This repo is now at "cloud.google.com/go", but still specifying the repo
		// here gives nicer errors in godoc.org and the go tool.
		VCS: "git",
		URL: "https://code.googlesource.com/gocloud",
		Src: github("GoogleCloudPlatform/gcloud-golang"),
	},
	"genproto": {
		VCS: "git",
		URL: "https://github.com/google/go-genproto",
		Src: github("google/go-genproto"),
	},
	"grpc": {
		VCS: "git",
		URL: "https://github.com/grpc/grpc-go",
		Src: github("grpc/grpc-go"),
	},
	"protobuf": {
		VCS: "git",
		URL: "https://go.googlesource.com/protobuf",
		Src: github("protocolbuffers/protobuf-go"),
	},
}

// repoImport represents an import meta-tag, as per
// https://golang.org/cmd/go/#hdr-Import_path_syntax
type repoImport struct {
	VCS string
	URL string
	Src *src
}

// src represents a godoc.org source redirect.
// https://github.com/golang/gddo/search?utf8=%E2%9C%93&q=sourceMeta
type src struct {
	URL     string
	DirTpl  string
	FileTpl string
}

// github returns the *src representing a github repo.
func github(base string) *src {
	return &src{
		URL:     fmt.Sprintf("https://github.com/%s", base),
		DirTpl:  fmt.Sprintf("https://github.com/%s/tree/master{/dir}", base),
		FileTpl: fmt.Sprintf("https://github.com/%s/tree/master{/dir}/{file}#L{line}", base),
	}
}

func googsource(repo, base string) *src {
	return &src{
		URL:     fmt.Sprintf("https://%s.googlesource.com/%s", repo, base),
		DirTpl:  fmt.Sprintf("https://%s.googlesource.com/%s/+/master{/dir}", repo, base),
		FileTpl: fmt.Sprintf("https://%s.googlesource.com/%s/+/master{/dir}/{file}#{line}", repo, base),
	}
}

func main() {
	http.HandleFunc("/", handler)

	port := os.Getenv("PORT")
	if port == "" {
		port = "8080"
		fmt.Printf("Defaulting to port %s\n", port)
	}

	fmt.Printf("Listening on port %s\n", port)
	if err := http.ListenAndServe(fmt.Sprintf(":%s", port), nil); err != nil {
		fmt.Fprintf(os.Stderr, "http.ListenAndServe: %v\n", err)
		return
	}
}

func handler(w http.ResponseWriter, r *http.Request) {
	head, tail := strings.TrimPrefix(r.URL.Path, "/"), ""
	if i := strings.Index(head, "/"); i != -1 {
		head, tail = head[:i], head[i:]
	}
	if head == "" {
		http.Redirect(w, r, "https://cloud.google.com/go/google.golang.org", http.StatusFound)
		return
	}
	repo, ok := repoMap[head]
	if !ok {
		http.NotFound(w, r)
		return
	}
	godoc := "https://godoc.org/google.golang.org/" + head + tail
	// For users visting in a browser, redirect straight to godoc.org.
	if isBrowser := r.FormValue("go-get") == ""; isBrowser {
		http.Redirect(w, r, godoc, http.StatusFound)
		return
	}
	data := struct {
		Head, GoDoc string
		Repo        *repoImport
	}{head, godoc, repo}
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	if err := tmpl.Execute(w, data); err != nil {
		fmt.Fprintf(os.Stderr, "tmpl.Execute: %v\n", err)
	}
}

var tmpl = template.Must(template.New("redir").Parse(`<!DOCTYPE html>

<meta name="go-import" content="google.golang.org/{{.Head}} {{.Repo.VCS}} {{.Repo.URL}}">
{{if .Repo.Src}}
<meta name="go-source" content="google.golang.org/{{.Head}} {{.Repo.Src.URL}} {{.Repo.Src.DirTpl}} {{.Repo.Src.FileTpl}}">
{{end}}
<meta http-equiv="refresh" content="0; url={{.GoDoc}}">

Nothing to see here. Please move along.

`))
<commit_msg>cmd/googlegolangorg: update Google API repo URLs<commit_after>// A trivial redirector for google.golang.org.
package main

import (
	"fmt"
	"html/template"
	"net/http"
	"os"
	"strings"
)

var repoMap = map[string]*repoImport{
	"api": {
		VCS: "git",
		URL: "https://github.com/googleapis/google-api-go-client",
		Src: github("googleapis/google-api-go-client"),
	},
	"appengine": {
		VCS: "git",
		URL: "https://github.com/golang/appengine",
		Src: github("golang/appengine"),
	},
	"cloud": {
		// This repo is now at "cloud.google.com/go", but still specifying the repo
		// here gives nicer errors in godoc.org and the go tool.
		VCS: "git",
		URL: "https://code.googlesource.com/gocloud",
		Src: github("googleapis/google-cloud-go"),
	},
	"genproto": {
		VCS: "git",
		URL: "https://github.com/googleapis/go-genproto",
		Src: github("googleapis/go-genproto"),
	},
	"grpc": {
		VCS: "git",
		URL: "https://github.com/grpc/grpc-go",
		Src: github("grpc/grpc-go"),
	},
	"protobuf": {
		VCS: "git",
		URL: "https://go.googlesource.com/protobuf",
		Src: github("protocolbuffers/protobuf-go"),
	},
}

// repoImport represents an import meta-tag, as per
// https://golang.org/cmd/go/#hdr-Import_path_syntax
type repoImport struct {
	VCS string
	URL string
	Src *src
}

// src represents a godoc.org source redirect.
// https://github.com/golang/gddo/search?utf8=%E2%9C%93&q=sourceMeta
type src struct {
	URL     string
	DirTpl  string
	FileTpl string
}

// github returns the *src representing a github repo.
func github(base string) *src {
	return &src{
		URL:     fmt.Sprintf("https://github.com/%s", base),
		DirTpl:  fmt.Sprintf("https://github.com/%s/tree/master{/dir}", base),
		FileTpl: fmt.Sprintf("https://github.com/%s/tree/master{/dir}/{file}#L{line}", base),
	}
}

func googsource(repo, base string) *src {
	return &src{
		URL:     fmt.Sprintf("https://%s.googlesource.com/%s", repo, base),
		DirTpl:  fmt.Sprintf("https://%s.googlesource.com/%s/+/master{/dir}", repo, base),
		FileTpl: fmt.Sprintf("https://%s.googlesource.com/%s/+/master{/dir}/{file}#{line}", repo, base),
	}
}

func main() {
	http.HandleFunc("/", handler)

	port := os.Getenv("PORT")
	if port == "" {
		port = "8080"
		fmt.Printf("Defaulting to port %s\n", port)
	}

	fmt.Printf("Listening on port %s\n", port)
	if err := http.ListenAndServe(fmt.Sprintf(":%s", port), nil); err != nil {
		fmt.Fprintf(os.Stderr, "http.ListenAndServe: %v\n", err)
		return
	}
}

func handler(w http.ResponseWriter, r *http.Request) {
	head, tail := strings.TrimPrefix(r.URL.Path, "/"), ""
	if i := strings.Index(head, "/"); i != -1 {
		head, tail = head[:i], head[i:]
	}
	if head == "" {
		http.Redirect(w, r, "https://cloud.google.com/go/google.golang.org", http.StatusFound)
		return
	}
	repo, ok := repoMap[head]
	if !ok {
		http.NotFound(w, r)
		return
	}
	godoc := "https://godoc.org/google.golang.org/" + head + tail
	// For users visting in a browser, redirect straight to godoc.org.
	if isBrowser := r.FormValue("go-get") == ""; isBrowser {
		http.Redirect(w, r, godoc, http.StatusFound)
		return
	}
	data := struct {
		Head, GoDoc string
		Repo        *repoImport
	}{head, godoc, repo}
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	if err := tmpl.Execute(w, data); err != nil {
		fmt.Fprintf(os.Stderr, "tmpl.Execute: %v\n", err)
	}
}

var tmpl = template.Must(template.New("redir").Parse(`<!DOCTYPE html>

<meta name="go-import" content="google.golang.org/{{.Head}} {{.Repo.VCS}} {{.Repo.URL}}">
{{if .Repo.Src}}
<meta name="go-source" content="google.golang.org/{{.Head}} {{.Repo.Src.URL}} {{.Repo.Src.DirTpl}} {{.Repo.Src.FileTpl}}">
{{end}}
<meta http-equiv="refresh" content="0; url={{.GoDoc}}">

Nothing to see here. Please move along.

`))
<|endoftext|>


<commit_before>package katoctl
<commit_msg>Remove katoctl_test.go<commit_after><|endoftext|>


<commit_before>// Copyright 2015 Matthew Holt and The Caddy 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 caddycmd

import (
	"os"
	"path/filepath"
	"syscall"
)

// removeCaddyBinary removes the Caddy binary at the given path.
//
// On Windows, this uses a syscall to indirectly remove the file,
// because otherwise we get an "Access is denied." error when trying
// to delete the binary while Caddy is still running and performing
// the upgrade. "cmd.exe /C" executes a command specified by the
// following arguments, i.e. "del" which will run as a separate process,
// which avoids the "Access is denied." error.
func removeCaddyBinary(path string) error {
	var sI syscall.StartupInfo
	var pI syscall.ProcessInformation
	argv := syscall.UTF16PtrFromString(filepath.Join(os.Getenv("windir"), "system32", "cmd.exe") + " /C del " + path)
	return syscall.CreateProcess(nil, argv, nil, nil, true, 0, nil, nil, &sI, &pI)
}
<commit_msg>Fix compilation on Windows<commit_after>// Copyright 2015 Matthew Holt and The Caddy 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 caddycmd

import (
	"os"
	"path/filepath"
	"syscall"
)

// removeCaddyBinary removes the Caddy binary at the given path.
//
// On Windows, this uses a syscall to indirectly remove the file,
// because otherwise we get an "Access is denied." error when trying
// to delete the binary while Caddy is still running and performing
// the upgrade. "cmd.exe /C" executes a command specified by the
// following arguments, i.e. "del" which will run as a separate process,
// which avoids the "Access is denied." error.
func removeCaddyBinary(path string) error {
	var sI syscall.StartupInfo
	var pI syscall.ProcessInformation
	argv, err := syscall.UTF16PtrFromString(filepath.Join(os.Getenv("windir"), "system32", "cmd.exe") + " /C del " + path)
	if err != nil {
		return err
	}
	return syscall.CreateProcess(nil, argv, nil, nil, true, 0, nil, nil, &sI, &pI)
}
<|endoftext|>


<commit_before>package cmd_member

import (
	"flag"
	"github.com/cihub/seelog"
	"github.com/dropbox/dropbox-sdk-go-unofficial/dropbox/async"
	"github.com/dropbox/dropbox-sdk-go-unofficial/dropbox/team"
	"github.com/watermint/toolbox/api"
	"github.com/watermint/toolbox/cmdlet"
	"github.com/watermint/toolbox/infra"
	"github.com/watermint/toolbox/infra/util"
	"io"
	"os"
	"time"
)

type CmdMemberInvite struct {
	optCsv       string
	optSilent    bool
	apiContext   *api.ApiContext
	infraContext *infra.InfraContext
}

func NewCmdMemberInvite() *CmdMemberInvite {
	c := CmdMemberInvite{
		infraContext: &infra.InfraContext{},
	}
	return &c
}

func (c *CmdMemberInvite) Name() string {
	return "invite"
}

func (c *CmdMemberInvite) Desc() string {
	return "Invite members"
}

func (c *CmdMemberInvite) UsageTmpl() string {
	return `
Usage: {{.Command}} -csv MEMBER_FILENAME
`
}

func (c *CmdMemberInvite) FlagSet() (f *flag.FlagSet) {
	f = flag.NewFlagSet(c.Name(), flag.ExitOnError)

	descCsv := "CSV file name"
	f.StringVar(&c.optCsv, "csv", "", descCsv)

	descSilent := "Silent provisioning"
	f.BoolVar(&c.optSilent, "silent", false, descSilent)

	c.infraContext.PrepareFlags(f)
	return f
}

func (c *CmdMemberInvite) Exec(cc cmdlet.CommandletContext) error {
	_, err := cmdlet.ParseFlags(cc, c)
	if err != nil {
		return err
	}
	if c.optCsv == "" {
		return &cmdlet.CommandShowUsageError{
			Context:     cc,
			Instruction: "missing `-csv` option.",
		}
	}
	c.infraContext.Startup()
	defer c.infraContext.Shutdown()
	seelog.Debugf("invite:%s", util.MarshalObjectToString(c))
	c.apiContext, err = c.infraContext.LoadOrAuthBusinessManagement()

	if c.optCsv == "" {
		return &cmdlet.CommandError{
			Context:     cc,
			ReasonTag:   "member/invite:missing_csv",
			Description: "Missing CSV file",
		}
	}
	return c.inviteByCsv(c.optCsv)
}

func (c *CmdMemberInvite) inviteByCsv(csvFile string) error {
	f, err := os.Open(csvFile)
	if err != nil {
		seelog.Warnf("Unable to open file[%s] : error[%s]", csvFile, err)
		return err
	}
	csv := util.NewBomAwareCsvReader(f)

	for {
		cols, err := csv.Read()
		if err == io.EOF {
			break
		}
		if err != nil {
			seelog.Warnf("Unable to read CSV file [%s] : error[%s]", csvFile, err)
			return err
		}
		if len(cols) < 1 {
			seelog.Warnf("Skip line: [%v]", cols)
			continue
		}
		var email, givenName, surName string
		email = cols[0]
		if len(cols) >= 2 {
			givenName = cols[1]
		}
		if len(cols) >= 3 {
			surName = cols[2]
		}

		seelog.Infof("Trying invite email[%s] givenName[%s] surName[%s]", email, givenName, surName)

		c.invite(email, givenName, surName)
	}
	return nil
}

func (c *CmdMemberInvite) invite(email, givenName, surname string) error {
	client := c.apiContext.Team()

	inv := team.NewMemberAddArg(email)
	inv.MemberGivenName = givenName
	inv.MemberSurname = surname

	if c.optSilent {
		inv.SendWelcomeEmail = false
	}

	arg := team.NewMembersAddArg([]*team.MemberAddArg{inv})

	seelog.Infof("Inviting: email[%s] givenName[%s] surName[%s] silent[%t]", email, givenName, surname, c.optSilent)
	client.MembersAdd(arg)
	return nil
}

func (c *CmdMemberInvite) waitForAsync(asyncJobId, email, givenName, surname string) ([]*team.MemberAddResult, error) {
	client := c.apiContext.Team()

	for {
		time.Sleep(5 * time.Second)
		res, err := client.MembersAddJobStatusGet(async.NewPollArg(asyncJobId))
		if err != nil {
			seelog.Warnf("Unable to check status : error[%s]", err)
			return nil, err
		}
		if res.Tag == "in_progress" {
			seelog.Debugf("Process status `in_progress`: async_job_id[%s]", asyncJobId)
			continue
		}
		if res.Failed != "" {
			seelog.Warnf("Failed to add member email[%s] givenName[%s] surName[%s] : error[%s]",
				email, givenName, surname, res.Failed)
			return nil, err
		}
		if res.Complete != nil {
			return res.Complete, nil
		}
	}
}
<commit_msg>reduce message<commit_after>package cmd_member

import (
	"flag"
	"github.com/cihub/seelog"
	"github.com/dropbox/dropbox-sdk-go-unofficial/dropbox/async"
	"github.com/dropbox/dropbox-sdk-go-unofficial/dropbox/team"
	"github.com/watermint/toolbox/api"
	"github.com/watermint/toolbox/cmdlet"
	"github.com/watermint/toolbox/infra"
	"github.com/watermint/toolbox/infra/util"
	"io"
	"os"
	"time"
)

type CmdMemberInvite struct {
	optCsv       string
	optSilent    bool
	apiContext   *api.ApiContext
	infraContext *infra.InfraContext
}

func NewCmdMemberInvite() *CmdMemberInvite {
	c := CmdMemberInvite{
		infraContext: &infra.InfraContext{},
	}
	return &c
}

func (c *CmdMemberInvite) Name() string {
	return "invite"
}

func (c *CmdMemberInvite) Desc() string {
	return "Invite members"
}

func (c *CmdMemberInvite) UsageTmpl() string {
	return `
Usage: {{.Command}} -csv MEMBER_FILENAME
`
}

func (c *CmdMemberInvite) FlagSet() (f *flag.FlagSet) {
	f = flag.NewFlagSet(c.Name(), flag.ExitOnError)

	descCsv := "CSV file name"
	f.StringVar(&c.optCsv, "csv", "", descCsv)

	descSilent := "Silent provisioning"
	f.BoolVar(&c.optSilent, "silent", false, descSilent)

	c.infraContext.PrepareFlags(f)
	return f
}

func (c *CmdMemberInvite) Exec(cc cmdlet.CommandletContext) error {
	_, err := cmdlet.ParseFlags(cc, c)
	if err != nil {
		return err
	}
	if c.optCsv == "" {
		return &cmdlet.CommandShowUsageError{
			Context:     cc,
			Instruction: "missing `-csv` option.",
		}
	}
	c.infraContext.Startup()
	defer c.infraContext.Shutdown()
	seelog.Debugf("invite:%s", util.MarshalObjectToString(c))
	c.apiContext, err = c.infraContext.LoadOrAuthBusinessManagement()

	if c.optCsv == "" {
		return &cmdlet.CommandError{
			Context:     cc,
			ReasonTag:   "member/invite:missing_csv",
			Description: "Missing CSV file",
		}
	}
	return c.inviteByCsv(c.optCsv)
}

func (c *CmdMemberInvite) inviteByCsv(csvFile string) error {
	f, err := os.Open(csvFile)
	if err != nil {
		seelog.Warnf("Unable to open file[%s] : error[%s]", csvFile, err)
		return err
	}
	csv := util.NewBomAwareCsvReader(f)

	for {
		cols, err := csv.Read()
		if err == io.EOF {
			break
		}
		if err != nil {
			seelog.Warnf("Unable to read CSV file [%s] : error[%s]", csvFile, err)
			return err
		}
		if len(cols) < 1 {
			seelog.Warnf("Skip line: [%v]", cols)
			continue
		}
		var email, givenName, surName string
		email = cols[0]
		if len(cols) >= 2 {
			givenName = cols[1]
		}
		if len(cols) >= 3 {
			surName = cols[2]
		}

		c.invite(email, givenName, surName)
	}
	return nil
}

func (c *CmdMemberInvite) invite(email, givenName, surname string) error {
	client := c.apiContext.Team()

	inv := team.NewMemberAddArg(email)
	inv.MemberGivenName = givenName
	inv.MemberSurname = surname

	if c.optSilent {
		inv.SendWelcomeEmail = false
	}

	arg := team.NewMembersAddArg([]*team.MemberAddArg{inv})

	seelog.Infof("Inviting: email[%s] givenName[%s] surName[%s] silent[%t]", email, givenName, surname, c.optSilent)
	client.MembersAdd(arg)
	return nil
}

func (c *CmdMemberInvite) waitForAsync(asyncJobId, email, givenName, surname string) ([]*team.MemberAddResult, error) {
	client := c.apiContext.Team()

	for {
		time.Sleep(5 * time.Second)
		res, err := client.MembersAddJobStatusGet(async.NewPollArg(asyncJobId))
		if err != nil {
			seelog.Warnf("Unable to check status : error[%s]", err)
			return nil, err
		}
		if res.Tag == "in_progress" {
			seelog.Debugf("Process status `in_progress`: async_job_id[%s]", asyncJobId)
			continue
		}
		if res.Failed != "" {
			seelog.Warnf("Failed to add member email[%s] givenName[%s] surName[%s] : error[%s]",
				email, givenName, surname, res.Failed)
			return nil, err
		}
		if res.Complete != nil {
			return res.Complete, nil
		}
	}
}
<|endoftext|>


<commit_before>package cpe

import (
	"bytes"
	"compress/gzip"
	"encoding/xml"
	"fmt"
	"io/ioutil"
	"net/http"

	"github.com/parnurzeal/gorequest"
)

// CpeList has cpe-item list
// https://nvd.nist.gov/cpe.cfm
type CpeList struct {
	CpeItems []CpeItem `xml:"cpe-item"`
}

// CpeItem has CPE information
type CpeItem struct {
	Name      string    `xml:"name,attr"`
	Cpe23Item Cpe23Item `xml:"cpe23-item"`
	Titles    []Title   `xml:"title"`

	// each items
	//  Part     string
	//  Vendor   string
	//  Product  string
	//  Version  string
	//  Update   string
	//  Edition  string
	//  Language string
}

func (item CpeItem) GetTitleEn() string {
	for _, t := range item.Titles {
		if t.Lang == "en-US" {
			return t.Value
		}
	}
	return ""
}

func (item CpeItem) GetTitleJa() string {
	for _, t := range item.Titles {
		if t.Lang == "ja-JP" {
			return t.Value
		}
	}
	return ""
}

type Cpe23Item struct {
	Name string `xml:"name,attr"`
}

// Title has title, lang
type Title struct {
	Lang  string `xml:"lang,attr"`
	Value string `xml:",chardata"`
}

func FetchCPE(httpProxy string) (cpeList CpeList, err error) {
	var body string
	var errs []error
	var resp *http.Response
	url := "http://static.nvd.nist.gov/feeds/xml/cpe/dictionary/official-cpe-dictionary_v2.3.xml.gz"
	resp, body, errs = gorequest.New().Proxy(httpProxy).Get(url).End()
	if len(errs) > 0 || resp.StatusCode != 200 {
		return cpeList, fmt.Errorf("HTTP error. errs: %v, url: %s", errs, url)
	}

	b := bytes.NewBufferString(body)
	reader, err := gzip.NewReader(b)
	defer reader.Close()
	if err != nil {
		return cpeList,
			fmt.Errorf("Failed to decompress NVD feedfile. url: %s, err: %s", url, err)
	}
	bytes, err := ioutil.ReadAll(reader)
	if err != nil {
		return cpeList,
			fmt.Errorf("Failed to Read NVD feedfile. url: %s, err: %s", url, err)
	}
	if err = xml.Unmarshal(bytes, &cpeList); err != nil {
		return cpeList, fmt.Errorf("Failed to unmarshal. url: %s, err: %s", url, err)
	}

	return
}
<commit_msg>change nvd url<commit_after>package cpe

import (
	"bytes"
	"compress/gzip"
	"encoding/xml"
	"fmt"
	"io/ioutil"
	"net/http"

	"github.com/parnurzeal/gorequest"
)

// CpeList has cpe-item list
// https://nvd.nist.gov/cpe.cfm
type CpeList struct {
	CpeItems []CpeItem `xml:"cpe-item"`
}

// CpeItem has CPE information
type CpeItem struct {
	Name      string    `xml:"name,attr"`
	Cpe23Item Cpe23Item `xml:"cpe23-item"`
	Titles    []Title   `xml:"title"`

	// each items
	//  Part     string
	//  Vendor   string
	//  Product  string
	//  Version  string
	//  Update   string
	//  Edition  string
	//  Language string
}

func (item CpeItem) GetTitleEn() string {
	for _, t := range item.Titles {
		if t.Lang == "en-US" {
			return t.Value
		}
	}
	return ""
}

func (item CpeItem) GetTitleJa() string {
	for _, t := range item.Titles {
		if t.Lang == "ja-JP" {
			return t.Value
		}
	}
	return ""
}

type Cpe23Item struct {
	Name string `xml:"name,attr"`
}

// Title has title, lang
type Title struct {
	Lang  string `xml:"lang,attr"`
	Value string `xml:",chardata"`
}

func FetchCPE(httpProxy string) (cpeList CpeList, err error) {
	var body string
	var errs []error
	var resp *http.Response
	url := "http://nvd.nist.gov/feeds/xml/cpe/dictionary/official-cpe-dictionary_v2.3.xml.gz"
	resp, body, errs = gorequest.New().Proxy(httpProxy).Get(url).End()
	if len(errs) > 0 || resp.StatusCode != 200 {
		return cpeList, fmt.Errorf("HTTP error. errs: %v, url: %s", errs, url)
	}

	b := bytes.NewBufferString(body)
	reader, err := gzip.NewReader(b)
	defer reader.Close()
	if err != nil {
		return cpeList,
			fmt.Errorf("Failed to decompress NVD feedfile. url: %s, err: %s", url, err)
	}
	bytes, err := ioutil.ReadAll(reader)
	if err != nil {
		return cpeList,
			fmt.Errorf("Failed to Read NVD feedfile. url: %s, err: %s", url, err)
	}
	if err = xml.Unmarshal(bytes, &cpeList); err != nil {
		return cpeList, fmt.Errorf("Failed to unmarshal. url: %s, err: %s", url, err)
	}

	return
}
<|endoftext|>


<commit_before>// Copyright 2012 The ebml-go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package ebml decodes EBML data.
//
// EBML is short for Extensible Binary Meta Language. EBML specifies a
// binary and octet (byte) aligned format inspired by the principle of
// XML. EBML itself is a generalized description of the technique of
// binary markup. Like XML, it is completely agnostic to any data that it
// might contain.
// For a specification, see http://ebml.sourceforge.net/specs/
package ebml

import (
	"errors"
	"fmt"
	"io"
	"log"
	"math"
	"reflect"
	"strconv"
)

// ReachedPayloadError is generated when a field tagged with
// ebmlstop:"1" is reached.
type ReachedPayloadError struct {
	First *Element
	Rest  *Element
}

func (r ReachedPayloadError) Error() string {
	return "Reached payload"
}

// Element represents an EBML-encoded chunk of data.
type Element struct {
	R  io.Reader
	Id uint
}

func (e *Element) String() string {
	return fmt.Sprintf("{%+v %x}", e.R, e.Id)
}

// Size returns the size of the element.
func (e *Element) Size() int64 {
	lr := e.R.(*io.LimitedReader)
	return lr.N
}

// Creates the root element corresponding to the data available in r.
func RootElement(r io.Reader) (*Element, error) {
	e := &Element{io.LimitReader(r, math.MaxInt64), 0}
	return e, nil
}

func remaining(x int8) (rem int) {
	for x > 0 {
		rem++
		x += x
	}
	return
}

func readVint(r io.Reader) (val uint64, err error, rem int) {
	v := make([]uint8, 1)
	_, err = io.ReadFull(r, v)
	if err == nil {
		val = uint64(v[0])
		rem = remaining(int8(val))
		for i := 0; err == nil && i < rem; i++ {
			_, err = io.ReadFull(r, v)
			val <<= 8
			val += uint64(v[0])
		}
	}
	return
}

func readSize(r io.Reader) (int64, error) {
	val, err, rem := readVint(r)
	return int64(val & ^(128 << uint(rem*8-rem))), err
}

// Next returns the next child element in an element.
func (e *Element) Next() (*Element, error) {
	var ne Element
	id, err, _ := readVint(e.R)
	if err != nil {
		return nil, err
	}
	var sz int64
	sz, err = readSize(e.R)
	if err != nil {
		return nil, err
	}
	ne.R = io.LimitReader(e.R, sz)
	ne.Id = uint(id)
	return &ne, err
}

func (e *Element) readUint64() (uint64, error) {
	d, err := e.ReadData()
	var i int
	sz := len(d)
	var val uint64
	for i = 0; i < sz; i++ {
		val <<= 8
		val += uint64(d[i])
	}
	return val, err
}

func (e *Element) readUint() (uint, error) {
	val, err := e.readUint64()
	return uint(val), err
}

func (e *Element) readString() (string, error) {
	s, err := e.ReadData()
	return string(s), err
}

func (e *Element) ReadData() (d []byte, err error) {
	sz := e.Size()
	d = make([]uint8, sz, sz)
	_, err = io.ReadFull(e.R, d)
	return
}

func (e *Element) readFloat() (val float64, err error) {
	var uval uint64
	uval, err = e.readUint64()
	if e.Size() == 8 {
		val = math.Float64frombits(uval)
	} else {
		val = float64(math.Float32frombits(uint32(uval)))
	}
	return
}

func (e *Element) skip() (err error) {
	_, err = e.ReadData()
	return
}

// Unmarshal reads EBML data from r into data. Data must be a pointer
// to a struct. Fields present in the struct but absent in the stream
// will just keep their zero value.
// Returns an error that can be an io.Error or a ReachedPayloadError
// containing the first element and the the parent element containing
// the rest of the elements.
func (e *Element) Unmarshal(val interface{}) error {
	return e.readStruct(reflect.Indirect(reflect.ValueOf(val)))
}

func getTag(f reflect.StructField, s string) uint {
	sid := f.Tag.Get(s)
	id, _ := strconv.ParseUint(sid, 16, 0)
	return uint(id)
}

func lookup(reqid uint, t reflect.Type) int {
	for i, l := 0, t.NumField(); i < l; i++ {
		f := t.Field(i)
		if getTag(f, "ebml") == reqid {
			return i - 1000000*int(getTag(f, "ebmlstop"))
		}
	}
	return -1
}

func setDefaults(v reflect.Value) {
	t := v.Type()
	for i, l := 0, t.NumField(); i < l; i++ {
		fv := v.Field(i)
		switch fv.Kind() {
		case reflect.Int:
			fallthrough
		case reflect.Int8:
			fallthrough
		case reflect.Int16:
			fallthrough
		case reflect.Int32:
			fallthrough
		case reflect.Int64:
			fallthrough
		case reflect.Uint:
			fallthrough
		case reflect.Uint8:
			fallthrough
		case reflect.Uint16:
			fallthrough
		case reflect.Uint32:
			fallthrough
		case reflect.Uint64:
			fallthrough
		case reflect.Float32:
			fallthrough
		case reflect.Float64:
			fallthrough
		case reflect.String:
			setFieldDefaults(fv, t.Field(i), v)
		case reflect.Array:
			fallthrough
		case reflect.Struct:
			fallthrough
		case reflect.Slice:
			break
		default:
			log.Panic("Unsupported type")
		}
	}
}

func setFieldDefaults(v reflect.Value, sf reflect.StructField, s reflect.Value) {
	if v.CanInterface() && reflect.DeepEqual(
		v.Interface(), reflect.Zero(v.Type()).Interface()) {
		tag := sf.Tag.Get("ebmldef")
		if tag != "" {
			switch v.Kind() {
			case reflect.Int:
				fallthrough
			case reflect.Int64:
				u, _ := strconv.ParseInt(tag, 10, 0)
				v.SetInt(int64(u))
			case reflect.Uint:
				fallthrough
			case reflect.Uint64:
				u, _ := strconv.ParseUint(tag, 10, 0)
				v.SetUint(u)
			case reflect.Float32:
				fallthrough
			case reflect.Float64:
				f, _ := strconv.ParseFloat(tag, 64)
				v.SetFloat(f)
			case reflect.String:
				v.SetString(tag)
			default:
				log.Panic("Unsupported default value")
			}
		}
		ltag := sf.Tag.Get("ebmldeflink")
		if ltag != "" {
			v.Set(s.FieldByName(ltag))
		}
	}
}

func (e *Element) readStruct(v reflect.Value) (err error) {
	t := v.Type()
	for err == nil {
		var ne *Element
		ne, err = e.Next()
		if err == io.EOF {
			err = nil
			break
		}
		i := lookup(ne.Id, t)
		if i >= 0 {
			err = ne.readField(v.Field(i))
		} else if i == -1 {
			err = ne.skip()
		} else {
			err = ReachedPayloadError{ne, e}
		}
	}
	setDefaults(v)
	return
}

func (e *Element) readField(v reflect.Value) (err error) {
	switch v.Kind() {
	case reflect.Struct:
		err = e.readStruct(v)
	case reflect.Slice:
		err = e.readSlice(v)
	case reflect.Array:
		for i, l := 0, v.Len(); i < l && err == nil; i++ {
			err = e.readStruct(v.Index(i))
		}
	case reflect.String:
		var s string
		s, err = e.readString()
		v.SetString(s)
	case reflect.Int:
		fallthrough
	case reflect.Int64:
		var u uint64
		u, err = e.readUint64()
		v.SetInt(int64(u))
	case reflect.Uint:
		fallthrough
	case reflect.Uint64:
		var u uint64
		u, err = e.readUint64()
		v.SetUint(u)
	case reflect.Float32:
		fallthrough
	case reflect.Float64:
		var f float64
		f, err = e.readFloat()
		v.SetFloat(f)
	default:
		err = errors.New("Unknown type: " + v.String())
	}
	return
}

func (e *Element) readSlice(v reflect.Value) (err error) {
	switch v.Type().Elem().Kind() {
	case reflect.Uint8:
		var sl []uint8
		sl, err = e.ReadData()
		if err == nil {
			v.Set(reflect.ValueOf(sl))
		}
	case reflect.Struct:
		vl := v.Len()
		ne := reflect.New(v.Type().Elem())
		nsl := reflect.Append(v, reflect.Indirect(ne))
		v.Set(nsl)
		err = e.readStruct(v.Index(vl))
	default:
		err = errors.New("Unknown slice type: " + v.String())
	}
	return
}
<commit_msg>Boring stuff<commit_after>// Copyright (c) 2012, Jorge Acereda Maciá. All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can
// be found in the LICENSE file.

// Package ebml decodes EBML data.
//
// EBML is short for Extensible Binary Meta Language. EBML specifies a
// binary and octet (byte) aligned format inspired by the principle of
// XML. EBML itself is a generalized description of the technique of
// binary markup. Like XML, it is completely agnostic to any data that it
// might contain.
// For a specification, see http://ebml.sourceforge.net/specs/
package ebml

import (
	"errors"
	"fmt"
	"io"
	"log"
	"math"
	"reflect"
	"strconv"
)

// ReachedPayloadError is generated when a field tagged with
// ebmlstop:"1" is reached.
type ReachedPayloadError struct {
	First *Element
	Rest  *Element
}

func (r ReachedPayloadError) Error() string {
	return "Reached payload"
}

// Element represents an EBML-encoded chunk of data.
type Element struct {
	R  io.Reader
	Id uint
}

func (e *Element) String() string {
	return fmt.Sprintf("{%+v %x}", e.R, e.Id)
}

// Size returns the size of the element.
func (e *Element) Size() int64 {
	lr := e.R.(*io.LimitedReader)
	return lr.N
}

// Creates the root element corresponding to the data available in r.
func RootElement(r io.Reader) (*Element, error) {
	e := &Element{io.LimitReader(r, math.MaxInt64), 0}
	return e, nil
}

func remaining(x int8) (rem int) {
	for x > 0 {
		rem++
		x += x
	}
	return
}

func readVint(r io.Reader) (val uint64, err error, rem int) {
	v := make([]uint8, 1)
	_, err = io.ReadFull(r, v)
	if err == nil {
		val = uint64(v[0])
		rem = remaining(int8(val))
		for i := 0; err == nil && i < rem; i++ {
			_, err = io.ReadFull(r, v)
			val <<= 8
			val += uint64(v[0])
		}
	}
	return
}

func readSize(r io.Reader) (int64, error) {
	val, err, rem := readVint(r)
	return int64(val & ^(128 << uint(rem*8-rem))), err
}

// Next returns the next child element in an element.
func (e *Element) Next() (*Element, error) {
	var ne Element
	id, err, _ := readVint(e.R)
	if err != nil {
		return nil, err
	}
	var sz int64
	sz, err = readSize(e.R)
	if err != nil {
		return nil, err
	}
	ne.R = io.LimitReader(e.R, sz)
	ne.Id = uint(id)
	return &ne, err
}

func (e *Element) readUint64() (uint64, error) {
	d, err := e.ReadData()
	var i int
	sz := len(d)
	var val uint64
	for i = 0; i < sz; i++ {
		val <<= 8
		val += uint64(d[i])
	}
	return val, err
}

func (e *Element) readUint() (uint, error) {
	val, err := e.readUint64()
	return uint(val), err
}

func (e *Element) readString() (string, error) {
	s, err := e.ReadData()
	return string(s), err
}

func (e *Element) ReadData() (d []byte, err error) {
	sz := e.Size()
	d = make([]uint8, sz, sz)
	_, err = io.ReadFull(e.R, d)
	return
}

func (e *Element) readFloat() (val float64, err error) {
	var uval uint64
	uval, err = e.readUint64()
	if e.Size() == 8 {
		val = math.Float64frombits(uval)
	} else {
		val = float64(math.Float32frombits(uint32(uval)))
	}
	return
}

func (e *Element) skip() (err error) {
	_, err = e.ReadData()
	return
}

// Unmarshal reads EBML data from r into data. Data must be a pointer
// to a struct. Fields present in the struct but absent in the stream
// will just keep their zero value.
// Returns an error that can be an io.Error or a ReachedPayloadError
// containing the first element and the the parent element containing
// the rest of the elements.
func (e *Element) Unmarshal(val interface{}) error {
	return e.readStruct(reflect.Indirect(reflect.ValueOf(val)))
}

func getTag(f reflect.StructField, s string) uint {
	sid := f.Tag.Get(s)
	id, _ := strconv.ParseUint(sid, 16, 0)
	return uint(id)
}

func lookup(reqid uint, t reflect.Type) int {
	for i, l := 0, t.NumField(); i < l; i++ {
		f := t.Field(i)
		if getTag(f, "ebml") == reqid {
			return i - 1000000*int(getTag(f, "ebmlstop"))
		}
	}
	return -1
}

func setDefaults(v reflect.Value) {
	t := v.Type()
	for i, l := 0, t.NumField(); i < l; i++ {
		fv := v.Field(i)
		switch fv.Kind() {
		case reflect.Int:
			fallthrough
		case reflect.Int8:
			fallthrough
		case reflect.Int16:
			fallthrough
		case reflect.Int32:
			fallthrough
		case reflect.Int64:
			fallthrough
		case reflect.Uint:
			fallthrough
		case reflect.Uint8:
			fallthrough
		case reflect.Uint16:
			fallthrough
		case reflect.Uint32:
			fallthrough
		case reflect.Uint64:
			fallthrough
		case reflect.Float32:
			fallthrough
		case reflect.Float64:
			fallthrough
		case reflect.String:
			setFieldDefaults(fv, t.Field(i), v)
		case reflect.Array:
			fallthrough
		case reflect.Struct:
			fallthrough
		case reflect.Slice:
			break
		default:
			log.Panic("Unsupported type")
		}
	}
}

func setFieldDefaults(v reflect.Value, sf reflect.StructField, s reflect.Value) {
	if v.CanInterface() && reflect.DeepEqual(
		v.Interface(), reflect.Zero(v.Type()).Interface()) {
		tag := sf.Tag.Get("ebmldef")
		if tag != "" {
			switch v.Kind() {
			case reflect.Int:
				fallthrough
			case reflect.Int64:
				u, _ := strconv.ParseInt(tag, 10, 0)
				v.SetInt(int64(u))
			case reflect.Uint:
				fallthrough
			case reflect.Uint64:
				u, _ := strconv.ParseUint(tag, 10, 0)
				v.SetUint(u)
			case reflect.Float32:
				fallthrough
			case reflect.Float64:
				f, _ := strconv.ParseFloat(tag, 64)
				v.SetFloat(f)
			case reflect.String:
				v.SetString(tag)
			default:
				log.Panic("Unsupported default value")
			}
		}
		ltag := sf.Tag.Get("ebmldeflink")
		if ltag != "" {
			v.Set(s.FieldByName(ltag))
		}
	}
}

func (e *Element) readStruct(v reflect.Value) (err error) {
	t := v.Type()
	for err == nil {
		var ne *Element
		ne, err = e.Next()
		if err == io.EOF {
			err = nil
			break
		}
		i := lookup(ne.Id, t)
		if i >= 0 {
			err = ne.readField(v.Field(i))
		} else if i == -1 {
			err = ne.skip()
		} else {
			err = ReachedPayloadError{ne, e}
		}
	}
	setDefaults(v)
	return
}

func (e *Element) readField(v reflect.Value) (err error) {
	switch v.Kind() {
	case reflect.Struct:
		err = e.readStruct(v)
	case reflect.Slice:
		err = e.readSlice(v)
	case reflect.Array:
		for i, l := 0, v.Len(); i < l && err == nil; i++ {
			err = e.readStruct(v.Index(i))
		}
	case reflect.String:
		var s string
		s, err = e.readString()
		v.SetString(s)
	case reflect.Int:
		fallthrough
	case reflect.Int64:
		var u uint64
		u, err = e.readUint64()
		v.SetInt(int64(u))
	case reflect.Uint:
		fallthrough
	case reflect.Uint64:
		var u uint64
		u, err = e.readUint64()
		v.SetUint(u)
	case reflect.Float32:
		fallthrough
	case reflect.Float64:
		var f float64
		f, err = e.readFloat()
		v.SetFloat(f)
	default:
		err = errors.New("Unknown type: " + v.String())
	}
	return
}

func (e *Element) readSlice(v reflect.Value) (err error) {
	switch v.Type().Elem().Kind() {
	case reflect.Uint8:
		var sl []uint8
		sl, err = e.ReadData()
		if err == nil {
			v.Set(reflect.ValueOf(sl))
		}
	case reflect.Struct:
		vl := v.Len()
		ne := reflect.New(v.Type().Elem())
		nsl := reflect.Append(v, reflect.Indirect(ne))
		v.Set(nsl)
		err = e.readStruct(v.Index(vl))
	default:
		err = errors.New("Unknown slice type: " + v.String())
	}
	return
}
<|endoftext|>


<commit_before>// Copyright 2011 The ebml-go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package ebml decodes EBML data.
//
// EBML is short for Extensible Binary Meta Language. EBML specifies a
// binary and octet (byte) aligned format inspired by the principle of
// XML. EBML itself is a generalized description of the technique of
// binary markup. Like XML, it is completely agnostic to any data that it
// might contain.
// For a specification, see http://ebml.sourceforge.net/specs/
package ebml

import (
	"errors"
	"io"
	"math"
	"reflect"
	"strconv"
)

// ReachedPayloadError is generated when a field tagged with
// ebmlstop:"1" is reached.
type ReachedPayloadError struct {
	First *Element
	Rest  *Element
}

func (r ReachedPayloadError) Error() string {
	return "Reached payload"
}

// Element represents an EBML-encoded chunk of data.
type Element struct {
	R  io.Reader
	Id uint
}

// Size returns the size of the element.
func (e *Element) Size() int64 {
	lr := e.R.(*io.LimitedReader)
	return lr.N
}

// Creates the root element corresponding to the data available in r.
func RootElement(r io.Reader) (*Element, error) {
	e := &Element{io.LimitReader(r, math.MaxInt64), 0}
	return e, nil
}

func remaining(x int8) (rem int) {
	for x > 0 {
		rem++
		x += x
	}
	return
}

func readVint(r io.Reader) (val uint64, err error, rem int) {
	v := make([]uint8, 1)
	_, err = io.ReadFull(r, v)
	if err == nil {
		val = uint64(v[0])
		rem = remaining(int8(val))
		for i := 0; err == nil && i < rem; i++ {
			_, err = io.ReadFull(r, v)
			val <<= 8
			val += uint64(v[0])
		}
	}
	return
}

func readSize(r io.Reader) (int64, error) {
	val, err, rem := readVint(r)
	return int64(val & ^(128 << uint(rem*8-rem))), err
}

// Next returns the next child element in an element.
func (e *Element) Next() (*Element, error) {
	var ne Element
	id, err, _ := readVint(e.R)
	if err != nil {
		return nil, err
	}
	var sz int64
	sz, err = readSize(e.R)
	if err != nil {
		return nil, err
	}
	ne.R = io.LimitReader(e.R, sz)
	ne.Id = uint(id)
	return &ne, err
}

func (e *Element) readUint64() (uint64, error) {
	d, err := e.ReadData()
	var i int
	sz := len(d)
	var val uint64
	for i = 0; i < sz; i++ {
		val <<= 8
		val += uint64(d[i])
	}
	return val, err
}

func (e *Element) readUint() (uint, error) {
	val, err := e.readUint64()
	return uint(val), err
}

func (e *Element) readString() (string, error) {
	s, err := e.ReadData()
	return string(s), err
}

func (e *Element) ReadData() (d []byte, err error) {
	sz := e.Size()
	d = make([]uint8, sz, sz)
	_, err = io.ReadFull(e.R, d)
	return
}

func (e *Element) readFloat() (val float64, err error) {
	var uval uint64
	uval, err = e.readUint64()
	if e.Size() == 8 {
		val = math.Float64frombits(uval)
	} else {
		val = float64(math.Float32frombits(uint32(uval)))
	}
	return
}

func (e *Element) skip() (err error) {
	_, err = e.ReadData()
	return
}

// Unmarshal reads EBML data from r into data. Data must be a pointer
// to a struct. Fields present in the struct but absent in the stream
// will just keep their zero value.
// Returns an error that can be an io.Error or a ReachedPayloadError
// containing the first element and the the parent element containing
// the rest of the elements.
func (e *Element) Unmarshal(val interface{}) error {
	return e.readStruct(reflect.Indirect(reflect.ValueOf(val)))
}

func getTag(f reflect.StructField, s string) uint {
	sid := f.Tag.Get(s)
	id, _ := strconv.ParseUint(sid, 16, 0)
	return uint(id)
}

func lookup(reqid uint, t reflect.Type) int {
	for i, l := 0, t.NumField(); i < l; i++ {
		f := t.Field(i)
		if getTag(f, "ebml") == reqid {
			return i - 1000000*int(getTag(f, "ebmlstop"))
		}
	}
	return -1
}

func (e *Element) readStruct(v reflect.Value) (err error) {
	for err == nil {
		var ne *Element
		ne, err = e.Next()
		if err == io.EOF {
			err = nil
			break
		}
		i := lookup(ne.Id, v.Type())
		if i >= 0 {
			err = ne.readField(v.Field(i))
		} else if i == -1 {
			err = ne.skip()
		} else {
			err = ReachedPayloadError{ne, e}
		}
	}
	return
}

func (e *Element) readField(v reflect.Value) (err error) {
	switch v.Kind() {
	case reflect.Struct:
		err = e.readStruct(v)
	case reflect.Slice:
		err = e.readSlice(v)
	case reflect.Array:
		for i, l := 0, v.Len(); i < l && err == nil; i++ {
			err = e.readStruct(v.Index(i))
		}
	case reflect.String:
		var s string
		s, err = e.readString()
		v.SetString(s)
	case reflect.Int:
		fallthrough
	case reflect.Int64:
		var u uint64
		u, err = e.readUint64()
		v.SetInt(int64(u))
	case reflect.Uint:
		fallthrough
	case reflect.Uint64:
		var u uint64
		u, err = e.readUint64()
		v.SetUint(u)
	case reflect.Float32:
		fallthrough
	case reflect.Float64:
		var f float64
		f, err = e.readFloat()
		v.SetFloat(f)
	default:
		err = errors.New("Unknown type: " + v.String())
	}
	return
}

func (e *Element) readSlice(v reflect.Value) (err error) {
	switch v.Type().Elem().Kind() {
	case reflect.Uint8:
		var sl []uint8
		sl, err = e.ReadData()
		if err == nil {
			v.Set(reflect.ValueOf(sl))
		}
	case reflect.Struct:
		vl := v.Len()
		ne := reflect.New(v.Type().Elem())
		nsl := reflect.Append(v, reflect.Indirect(ne))
		v.Set(nsl)
		err = e.readStruct(v.Index(vl))
	default:
		err = errors.New("Unknown slice type: " + v.String())
	}
	return
}
<commit_msg>Added preliminary support for default values<commit_after>// Copyright 2011 The ebml-go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package ebml decodes EBML data.
//
// EBML is short for Extensible Binary Meta Language. EBML specifies a
// binary and octet (byte) aligned format inspired by the principle of
// XML. EBML itself is a generalized description of the technique of
// binary markup. Like XML, it is completely agnostic to any data that it
// might contain.
// For a specification, see http://ebml.sourceforge.net/specs/
package ebml

import (
	"errors"
	"io"
	"log"
	"math"
	"reflect"
	"strconv"
)

// ReachedPayloadError is generated when a field tagged with
// ebmlstop:"1" is reached.
type ReachedPayloadError struct {
	First *Element
	Rest  *Element
}

func (r ReachedPayloadError) Error() string {
	return "Reached payload"
}

// Element represents an EBML-encoded chunk of data.
type Element struct {
	R  io.Reader
	Id uint
}

// Size returns the size of the element.
func (e *Element) Size() int64 {
	lr := e.R.(*io.LimitedReader)
	return lr.N
}

// Creates the root element corresponding to the data available in r.
func RootElement(r io.Reader) (*Element, error) {
	e := &Element{io.LimitReader(r, math.MaxInt64), 0}
	return e, nil
}

func remaining(x int8) (rem int) {
	for x > 0 {
		rem++
		x += x
	}
	return
}

func readVint(r io.Reader) (val uint64, err error, rem int) {
	v := make([]uint8, 1)
	_, err = io.ReadFull(r, v)
	if err == nil {
		val = uint64(v[0])
		rem = remaining(int8(val))
		for i := 0; err == nil && i < rem; i++ {
			_, err = io.ReadFull(r, v)
			val <<= 8
			val += uint64(v[0])
		}
	}
	return
}

func readSize(r io.Reader) (int64, error) {
	val, err, rem := readVint(r)
	return int64(val & ^(128 << uint(rem*8-rem))), err
}

// Next returns the next child element in an element.
func (e *Element) Next() (*Element, error) {
	var ne Element
	id, err, _ := readVint(e.R)
	if err != nil {
		return nil, err
	}
	var sz int64
	sz, err = readSize(e.R)
	if err != nil {
		return nil, err
	}
	ne.R = io.LimitReader(e.R, sz)
	ne.Id = uint(id)
	return &ne, err
}

func (e *Element) readUint64() (uint64, error) {
	d, err := e.ReadData()
	var i int
	sz := len(d)
	var val uint64
	for i = 0; i < sz; i++ {
		val <<= 8
		val += uint64(d[i])
	}
	return val, err
}

func (e *Element) readUint() (uint, error) {
	val, err := e.readUint64()
	return uint(val), err
}

func (e *Element) readString() (string, error) {
	s, err := e.ReadData()
	return string(s), err
}

func (e *Element) ReadData() (d []byte, err error) {
	sz := e.Size()
	d = make([]uint8, sz, sz)
	_, err = io.ReadFull(e.R, d)
	return
}

func (e *Element) readFloat() (val float64, err error) {
	var uval uint64
	uval, err = e.readUint64()
	if e.Size() == 8 {
		val = math.Float64frombits(uval)
	} else {
		val = float64(math.Float32frombits(uint32(uval)))
	}
	return
}

func (e *Element) skip() (err error) {
	_, err = e.ReadData()
	return
}

// Unmarshal reads EBML data from r into data. Data must be a pointer
// to a struct. Fields present in the struct but absent in the stream
// will just keep their zero value.
// Returns an error that can be an io.Error or a ReachedPayloadError
// containing the first element and the the parent element containing
// the rest of the elements.
func (e *Element) Unmarshal(val interface{}) error {
	return e.readStruct(reflect.Indirect(reflect.ValueOf(val)))
}

func getTag(f reflect.StructField, s string) uint {
	sid := f.Tag.Get(s)
	id, _ := strconv.ParseUint(sid, 16, 0)
	return uint(id)
}

func lookup(reqid uint, t reflect.Type) int {
	for i, l := 0, t.NumField(); i < l; i++ {
		f := t.Field(i)
		if getTag(f, "ebml") == reqid {
			return i - 1000000*int(getTag(f, "ebmlstop"))
		}
	}
	return -1
}

func setDefaults(v reflect.Value) {
	t := v.Type()
	for i, l := 0, t.NumField(); i < l; i++ {
		fv := v.Field(i)
		switch fv.Kind() {
		case reflect.Int:
			fallthrough
		case reflect.Int8:
			fallthrough
		case reflect.Int16:
			fallthrough
		case reflect.Int32:
			fallthrough
		case reflect.Int64:
			fallthrough
		case reflect.Uint:
			fallthrough
		case reflect.Uint8:
			fallthrough
		case reflect.Uint16:
			fallthrough
		case reflect.Uint32:
			fallthrough
		case reflect.Uint64:
			fallthrough
		case reflect.Float32:
			fallthrough
		case reflect.Float64:
			fallthrough
		case reflect.String:
			setFieldDefaults(fv, t.Field(i))
		case reflect.Array:
			fallthrough
		case reflect.Struct:
			fallthrough
		case reflect.Slice:
			break
		default:
			log.Panic("Unsupported type")
		}
	}
}

func setFieldDefaults(v reflect.Value, sf reflect.StructField) {
	if v.CanInterface() && reflect.DeepEqual(
		v.Interface(), reflect.Zero(v.Type()).Interface()) {
		tag := sf.Tag.Get("ebmldef")
		if tag != "" {
			switch v.Kind() {
			case reflect.Int:
				fallthrough
			case reflect.Int64:
				u, _ := strconv.ParseInt(tag, 10, 0)
				v.SetInt(int64(u))
			case reflect.Uint:
				fallthrough
			case reflect.Uint64:
				u, _ := strconv.ParseUint(tag, 10, 0)
				v.SetUint(u)
			case reflect.Float32:
				fallthrough
			case reflect.Float64:
				f, _ := strconv.ParseFloat(tag, 64)
				v.SetFloat(f)
			case reflect.String:
				v.SetString(tag)
			default:
				log.Panic("Unsupported default value")
			}
		}
	}
}

func (e *Element) readStruct(v reflect.Value) (err error) {
	t := v.Type()
	for err == nil {
		var ne *Element
		ne, err = e.Next()
		if err == io.EOF {
			err = nil
			break
		}
		i := lookup(ne.Id, t)
		if i >= 0 {
			err = ne.readField(v.Field(i))
		} else if i == -1 {
			err = ne.skip()
		} else {
			err = ReachedPayloadError{ne, e}
		}
	}
	setDefaults(v)
	return
}

func (e *Element) readField(v reflect.Value) (err error) {
	switch v.Kind() {
	case reflect.Struct:
		err = e.readStruct(v)
	case reflect.Slice:
		err = e.readSlice(v)
	case reflect.Array:
		for i, l := 0, v.Len(); i < l && err == nil; i++ {
			err = e.readStruct(v.Index(i))
		}
	case reflect.String:
		var s string
		s, err = e.readString()
		v.SetString(s)
	case reflect.Int:
		fallthrough
	case reflect.Int64:
		var u uint64
		u, err = e.readUint64()
		v.SetInt(int64(u))
	case reflect.Uint:
		fallthrough
	case reflect.Uint64:
		var u uint64
		u, err = e.readUint64()
		v.SetUint(u)
	case reflect.Float32:
		fallthrough
	case reflect.Float64:
		var f float64
		f, err = e.readFloat()
		v.SetFloat(f)
	default:
		err = errors.New("Unknown type: " + v.String())
	}
	return
}

func (e *Element) readSlice(v reflect.Value) (err error) {
	switch v.Type().Elem().Kind() {
	case reflect.Uint8:
		var sl []uint8
		sl, err = e.ReadData()
		if err == nil {
			v.Set(reflect.ValueOf(sl))
		}
	case reflect.Struct:
		vl := v.Len()
		ne := reflect.New(v.Type().Elem())
		nsl := reflect.Append(v, reflect.Indirect(ne))
		v.Set(nsl)
		err = e.readStruct(v.Index(vl))
	default:
		err = errors.New("Unknown slice type: " + v.String())
	}
	return
}
<|endoftext|>