<commit_before>package main

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

	"golang.org/x/sys/unix"
	"gopkg.in/yaml.v2"

	lxd "github.com/lxc/lxd/client"
	"github.com/lxc/lxd/lxc/utils"
	"github.com/lxc/lxd/lxd/cluster"
	"github.com/lxc/lxd/lxd/db"
	"github.com/lxc/lxd/lxd/sys"
	"github.com/lxc/lxd/lxd/util"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/termios"
	"github.com/pkg/errors"
	"github.com/spf13/cobra"
)

type cmdCluster struct {
	global *cmdGlobal
}

func (c *cmdCluster) Command() *cobra.Command {
	cmd := &cobra.Command{}
	cmd.Use = "cluster"
	cmd.Short = "Low-level cluster administration commands"
	cmd.Long = `Description:
  Low level administration tools for inspecting and recovering LXD clusters.
`
	// List database nodes
	listDatabase := cmdClusterListDatabase{global: c.global}
	cmd.AddCommand(listDatabase.Command())

	// Recover
	recover := cmdClusterRecoverFromQuorumLoss{global: c.global}
	cmd.AddCommand(recover.Command())

	// Remove a raft node.
	removeRaftNode := cmdClusterRemoveRaftNode{global: c.global}
	cmd.AddCommand(removeRaftNode.Command())

	// Edit cluster configuration.
	clusterEdit := cmdClusterEdit{global: c.global}
	cmd.AddCommand(clusterEdit.Command())

	// Workaround for subcommand usage errors. See: https://github.com/spf13/cobra/issues/706
	cmd.Args = cobra.NoArgs
	cmd.Run = func(cmd *cobra.Command, args []string) { cmd.Usage() }
	return cmd
}

// ClusterMember is a more human-readable representation of the db.RaftNode struct.
type ClusterMember struct {
	ID      uint64 `yaml:"id"`
	Address string `yaml:"address"`
	Role    string `yaml:"role"`
}

// ClusterConfig is a representation of the current cluster configuration.
type ClusterConfig struct {
	Segment string          `yaml:"latest_segment"`
	Members []ClusterMember `yaml:"members"`
}

// ToRaftNode converts a ClusterConfig struct to a RaftNode struct.
func (c ClusterMember) ToRaftNode() (*db.RaftNode, error) {
	node := &db.RaftNode{
		ID:      c.ID,
		Address: c.Address,
	}

	var role db.RaftRole
	switch c.Role {
	case "voter":
		role = db.RaftVoter
		break
	case "stand-by":
		role = db.RaftStandBy
		break
	case "spare":
		role = db.RaftSpare
		break
	default:
		return nil, fmt.Errorf("unknown raft role: %q", c.Role)
	}

	node.Role = role

	return node, nil
}

type cmdClusterEdit struct {
	global *cmdGlobal
}

func (c *cmdClusterEdit) Command() *cobra.Command {
	cmd := &cobra.Command{}
	cmd.Use = "edit"
	cmd.Short = "Edit cluster configuration as YAML"
	cmd.Long = `Description:
	Edit cluster configuration as YAML.`
	cmd.RunE = c.Run

	return cmd
}

func (c *cmdClusterEdit) Run(cmd *cobra.Command, args []string) error {
	// Make sure that the daemon is not running.
	_, err := lxd.ConnectLXDUnix("", nil)
	if err == nil {
		return fmt.Errorf("The LXD daemon is running, please stop it first.")
	}

	database, _, err := db.OpenNode(filepath.Join(sys.DefaultOS().VarDir, "database"), nil, nil)
	if err != nil {
		return err
	}

	var nodes []db.RaftNode
	err = database.Transaction(func(tx *db.NodeTx) error {
		var err error
		nodes, err = tx.GetRaftNodes()
		return err
	})
	if err != nil {
		return err
	}

	segmentID, err := db.DqliteLatestSegment()
	if err != nil {
		return err
	}

	config := ClusterConfig{
		Segment: segmentID,
		Members: []ClusterMember{},
	}

	for _, node := range nodes {
		member := ClusterMember{ID: node.ID, Address: node.Address, Role: node.Role.String()}
		config.Members = append(config.Members, member)
	}

	data, err := yaml.Marshal(config)
	if err != nil {
		return err
	}

	var content []byte
	if !termios.IsTerminal(unix.Stdin) {
		content, err = ioutil.ReadAll(os.Stdin)
		if err != nil {
			return err
		}
	} else {
		content, err = shared.TextEditor("", data)
		if err != nil {
			return err
		}
	}

	for {
		newConfig := ClusterConfig{}
		err = yaml.Unmarshal(content, &newConfig)
		if err == nil {
			// Convert ClusterConfig back to RaftNodes.
			newNodes := []db.RaftNode{}
			var newNode *db.RaftNode
			for _, node := range newConfig.Members {
				newNode, err = node.ToRaftNode()
				if err != nil {
					break
				}

				newNodes = append(newNodes, *newNode)
			}

			// Ensure new configuration is valid.
			if err == nil {
				err = cluster.Reconfigure(database, newNodes)
			}
		}

		if err != nil {
			fmt.Fprintf(os.Stderr, "Config validation error: %s\n", err)
			fmt.Println("Press enter to open the editor again or ctrl+c to abort change")
			_, err := os.Stdin.Read(make([]byte, 1))
			if err != nil {
				return err
			}

			content, err = shared.TextEditor("", content)
			if err != nil {
				return err
			}

			continue
		}

		break
	}

	return nil
}

type cmdClusterListDatabase struct {
	global *cmdGlobal
}

func (c *cmdClusterListDatabase) Command() *cobra.Command {
	cmd := &cobra.Command{}
	cmd.Use = "list-database"
	cmd.Aliases = []string{"ls"}
	cmd.Short = "Print the addresses of the cluster members serving the database"

	cmd.RunE = c.Run

	return cmd
}

func (c *cmdClusterListDatabase) Run(cmd *cobra.Command, args []string) error {
	os := sys.DefaultOS()

	db, _, err := db.OpenNode(filepath.Join(os.VarDir, "database"), nil, nil)
	if err != nil {
		return errors.Wrapf(err, "Failed to open local database")
	}

	addresses, err := cluster.ListDatabaseNodes(db)
	if err != nil {
		return errors.Wrapf(err, "Failed to get database nodes")
	}

	columns := []string{"Address"}
	data := make([][]string, len(addresses))
	for i, address := range addresses {
		data[i] = []string{address}
	}
	utils.RenderTable(utils.TableFormatTable, columns, data, nil)

	return nil
}

type cmdClusterRecoverFromQuorumLoss struct {
	global             *cmdGlobal
	flagNonInteractive bool
}

func (c *cmdClusterRecoverFromQuorumLoss) Command() *cobra.Command {
	cmd := &cobra.Command{}
	cmd.Use = "recover-from-quorum-loss"
	cmd.Short = "Recover a LXD instance whose cluster has lost quorum"

	cmd.RunE = c.Run

	cmd.Flags().BoolVarP(&c.flagNonInteractive, "quiet", "q", false, "Don't require user confirmation")

	return cmd
}

func (c *cmdClusterRecoverFromQuorumLoss) Run(cmd *cobra.Command, args []string) error {
	// Make sure that the daemon is not running.
	_, err := lxd.ConnectLXDUnix("", nil)
	if err == nil {
		return fmt.Errorf("The LXD daemon is running, please stop it first.")
	}

	// Prompt for confirmation unless --quiet was passed.
	if !c.flagNonInteractive {
		err := c.promptConfirmation()
		if err != nil {
			return err
		}
	}

	os := sys.DefaultOS()

	db, _, err := db.OpenNode(filepath.Join(os.VarDir, "database"), nil, nil)
	if err != nil {
		return errors.Wrapf(err, "Failed to open local database")
	}

	return cluster.Recover(db)
}

func (c *cmdClusterRecoverFromQuorumLoss) promptConfirmation() error {
	reader := bufio.NewReader(os.Stdin)
	fmt.Printf(`You should run this command only if you are *absolutely* certain that this is
the only database node left in your cluster AND that other database nodes will
never come back (i.e. their LXD daemon won't ever be started again).

This will make this LXD instance the only member of the cluster, and it won't
be possible to perform operations on former cluster members anymore.

However all information about former cluster members will be preserved in the
database, so you can possibly inspect it for further recovery.

You'll be able to permanently delete from the database all information about
former cluster members by running "lxc cluster remove <member-name> --force".

See https://linuxcontainers.org/lxd/docs/master/clustering#recover-from-quorum-loss for more
info.

Do you want to proceed? (yes/no): `)
	input, _ := reader.ReadString('\n')
	input = strings.TrimSuffix(input, "\n")

	if !shared.StringInSlice(strings.ToLower(input), []string{"yes"}) {
		return fmt.Errorf("Recover operation aborted")
	}
	return nil
}

type cmdClusterRemoveRaftNode struct {
	global             *cmdGlobal
	flagNonInteractive bool
}

func (c *cmdClusterRemoveRaftNode) Command() *cobra.Command {
	cmd := &cobra.Command{}
	cmd.Use = "remove-raft-node <address>"
	cmd.Short = "Remove a raft node from the raft configuration"

	cmd.RunE = c.Run

	cmd.Flags().BoolVarP(&c.flagNonInteractive, "quiet", "q", false, "Don't require user confirmation")

	return cmd
}

func (c *cmdClusterRemoveRaftNode) Run(cmd *cobra.Command, args []string) error {
	if len(args) != 1 {
		cmd.Help()
		return fmt.Errorf("Missing required arguments")
	}

	address := util.CanonicalNetworkAddress(args[0])

	// Prompt for confirmation unless --quiet was passed.
	if !c.flagNonInteractive {
		err := c.promptConfirmation()
		if err != nil {
			return err
		}
	}

	client, err := lxd.ConnectLXDUnix("", nil)
	if err != nil {
		return errors.Wrapf(err, "Failed to connect to LXD daemon")
	}

	endpoint := fmt.Sprintf("/internal/cluster/raft-node/%s", address)
	_, _, err = client.RawQuery("DELETE", endpoint, nil, "")
	if err != nil {
		return err
	}

	return nil
}

func (c *cmdClusterRemoveRaftNode) promptConfirmation() error {
	reader := bufio.NewReader(os.Stdin)
	fmt.Printf(`You should run this command only if you ended up in an
inconsistent state where a node has been uncleanly removed (i.e. it doesn't show
up in "lxc cluster list" but it's still in the raft configuration).

Do you want to proceed? (yes/no): `)
	input, _ := reader.ReadString('\n')
	input = strings.TrimSuffix(input, "\n")

	if !shared.StringInSlice(strings.ToLower(input), []string{"yes"}) {
		return fmt.Errorf("Remove raft node operation aborted")
	}
	return nil
}
<commit_msg>lxd/main/cluster: add validateNewConfig<commit_after>package main

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

	"golang.org/x/sys/unix"
	"gopkg.in/yaml.v2"

	lxd "github.com/lxc/lxd/client"
	"github.com/lxc/lxd/lxc/utils"
	"github.com/lxc/lxd/lxd/cluster"
	"github.com/lxc/lxd/lxd/db"
	"github.com/lxc/lxd/lxd/sys"
	"github.com/lxc/lxd/lxd/util"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/termios"
	"github.com/pkg/errors"
	"github.com/spf13/cobra"
)

type cmdCluster struct {
	global *cmdGlobal
}

func (c *cmdCluster) Command() *cobra.Command {
	cmd := &cobra.Command{}
	cmd.Use = "cluster"
	cmd.Short = "Low-level cluster administration commands"
	cmd.Long = `Description:
  Low level administration tools for inspecting and recovering LXD clusters.
`
	// List database nodes
	listDatabase := cmdClusterListDatabase{global: c.global}
	cmd.AddCommand(listDatabase.Command())

	// Recover
	recover := cmdClusterRecoverFromQuorumLoss{global: c.global}
	cmd.AddCommand(recover.Command())

	// Remove a raft node.
	removeRaftNode := cmdClusterRemoveRaftNode{global: c.global}
	cmd.AddCommand(removeRaftNode.Command())

	// Edit cluster configuration.
	clusterEdit := cmdClusterEdit{global: c.global}
	cmd.AddCommand(clusterEdit.Command())

	// Workaround for subcommand usage errors. See: https://github.com/spf13/cobra/issues/706
	cmd.Args = cobra.NoArgs
	cmd.Run = func(cmd *cobra.Command, args []string) { cmd.Usage() }
	return cmd
}

// ClusterMember is a more human-readable representation of the db.RaftNode struct.
type ClusterMember struct {
	ID      uint64 `yaml:"id"`
	Address string `yaml:"address"`
	Role    string `yaml:"role"`
}

// ClusterConfig is a representation of the current cluster configuration.
type ClusterConfig struct {
	Segment string          `yaml:"latest_segment"`
	Members []ClusterMember `yaml:"members"`
}

// ToRaftNode converts a ClusterConfig struct to a RaftNode struct.
func (c ClusterMember) ToRaftNode() (*db.RaftNode, error) {
	node := &db.RaftNode{
		ID:      c.ID,
		Address: c.Address,
	}

	var role db.RaftRole
	switch c.Role {
	case "voter":
		role = db.RaftVoter
		break
	case "stand-by":
		role = db.RaftStandBy
		break
	case "spare":
		role = db.RaftSpare
		break
	default:
		return nil, fmt.Errorf("unknown raft role: %q", c.Role)
	}

	node.Role = role

	return node, nil
}

type cmdClusterEdit struct {
	global *cmdGlobal
}

func (c *cmdClusterEdit) Command() *cobra.Command {
	cmd := &cobra.Command{}
	cmd.Use = "edit"
	cmd.Short = "Edit cluster configuration as YAML"
	cmd.Long = `Description:
	Edit cluster configuration as YAML.`
	cmd.RunE = c.Run

	return cmd
}

func (c *cmdClusterEdit) Run(cmd *cobra.Command, args []string) error {
	// Make sure that the daemon is not running.
	_, err := lxd.ConnectLXDUnix("", nil)
	if err == nil {
		return fmt.Errorf("The LXD daemon is running, please stop it first.")
	}

	database, _, err := db.OpenNode(filepath.Join(sys.DefaultOS().VarDir, "database"), nil, nil)
	if err != nil {
		return err
	}

	var nodes []db.RaftNode
	err = database.Transaction(func(tx *db.NodeTx) error {
		var err error
		nodes, err = tx.GetRaftNodes()
		return err
	})
	if err != nil {
		return err
	}

	segmentID, err := db.DqliteLatestSegment()
	if err != nil {
		return err
	}

	config := ClusterConfig{
		Segment: segmentID,
		Members: []ClusterMember{},
	}

	for _, node := range nodes {
		member := ClusterMember{ID: node.ID, Address: node.Address, Role: node.Role.String()}
		config.Members = append(config.Members, member)
	}

	data, err := yaml.Marshal(config)
	if err != nil {
		return err
	}

	var content []byte
	if !termios.IsTerminal(unix.Stdin) {
		content, err = ioutil.ReadAll(os.Stdin)
		if err != nil {
			return err
		}
	} else {
		content, err = shared.TextEditor("", data)
		if err != nil {
			return err
		}
	}

	for {
		newConfig := ClusterConfig{}
		err = yaml.Unmarshal(content, &newConfig)
		if err == nil {
			// Convert ClusterConfig back to RaftNodes.
			newNodes := []db.RaftNode{}
			var newNode *db.RaftNode
			for _, node := range newConfig.Members {
				newNode, err = node.ToRaftNode()
				if err != nil {
					break
				}

				newNodes = append(newNodes, *newNode)
			}

			// Ensure new configuration is valid.
			if err == nil {
				err = validateNewConfig(nodes, newNodes)
				if err == nil {
					err = cluster.Reconfigure(database, newNodes)
				}
			}
		}

		if err != nil {
			fmt.Fprintf(os.Stderr, "Config validation error: %s\n", err)
			fmt.Println("Press enter to open the editor again or ctrl+c to abort change")
			_, err := os.Stdin.Read(make([]byte, 1))
			if err != nil {
				return err
			}

			content, err = shared.TextEditor("", content)
			if err != nil {
				return err
			}

			continue
		}

		break
	}

	return nil
}

func validateNewConfig(oldNodes []db.RaftNode, newNodes []db.RaftNode) error {
	if len(oldNodes) > len(newNodes) {
		return fmt.Errorf("Removing cluster members is not supported")
	}

	if len(oldNodes) < len(newNodes) {
		return fmt.Errorf("Adding cluster members is not supported")
	}

	numNewVoters := 0
	for i, newNode := range newNodes {
		oldNode := oldNodes[i]

		// IDs should not be reordered among cluster members.
		if oldNode.ID != newNode.ID {
			return fmt.Errorf("Changing cluster member ID is not supported")
		}

		if oldNode.Role == db.RaftSpare && newNode.Role == db.RaftVoter {
			return fmt.Errorf("A %q cluster member cannot become a %q", db.RaftSpare.String(), db.RaftVoter.String())
		}

		if newNode.Role == db.RaftVoter {
			numNewVoters++
		}
	}

	if numNewVoters < 2 && len(newNodes) > 2 {
		return fmt.Errorf("Number of %q must be 2 or more", db.RaftVoter.String())
	} else if numNewVoters < 1 {
		return fmt.Errorf("At least one member must be a %q", db.RaftVoter.String())
	}

	return nil
}

type cmdClusterListDatabase struct {
	global *cmdGlobal
}

func (c *cmdClusterListDatabase) Command() *cobra.Command {
	cmd := &cobra.Command{}
	cmd.Use = "list-database"
	cmd.Aliases = []string{"ls"}
	cmd.Short = "Print the addresses of the cluster members serving the database"

	cmd.RunE = c.Run

	return cmd
}

func (c *cmdClusterListDatabase) Run(cmd *cobra.Command, args []string) error {
	os := sys.DefaultOS()

	db, _, err := db.OpenNode(filepath.Join(os.VarDir, "database"), nil, nil)
	if err != nil {
		return errors.Wrapf(err, "Failed to open local database")
	}

	addresses, err := cluster.ListDatabaseNodes(db)
	if err != nil {
		return errors.Wrapf(err, "Failed to get database nodes")
	}

	columns := []string{"Address"}
	data := make([][]string, len(addresses))
	for i, address := range addresses {
		data[i] = []string{address}
	}
	utils.RenderTable(utils.TableFormatTable, columns, data, nil)

	return nil
}

type cmdClusterRecoverFromQuorumLoss struct {
	global             *cmdGlobal
	flagNonInteractive bool
}

func (c *cmdClusterRecoverFromQuorumLoss) Command() *cobra.Command {
	cmd := &cobra.Command{}
	cmd.Use = "recover-from-quorum-loss"
	cmd.Short = "Recover a LXD instance whose cluster has lost quorum"

	cmd.RunE = c.Run

	cmd.Flags().BoolVarP(&c.flagNonInteractive, "quiet", "q", false, "Don't require user confirmation")

	return cmd
}

func (c *cmdClusterRecoverFromQuorumLoss) Run(cmd *cobra.Command, args []string) error {
	// Make sure that the daemon is not running.
	_, err := lxd.ConnectLXDUnix("", nil)
	if err == nil {
		return fmt.Errorf("The LXD daemon is running, please stop it first.")
	}

	// Prompt for confirmation unless --quiet was passed.
	if !c.flagNonInteractive {
		err := c.promptConfirmation()
		if err != nil {
			return err
		}
	}

	os := sys.DefaultOS()

	db, _, err := db.OpenNode(filepath.Join(os.VarDir, "database"), nil, nil)
	if err != nil {
		return errors.Wrapf(err, "Failed to open local database")
	}

	return cluster.Recover(db)
}

func (c *cmdClusterRecoverFromQuorumLoss) promptConfirmation() error {
	reader := bufio.NewReader(os.Stdin)
	fmt.Printf(`You should run this command only if you are *absolutely* certain that this is
the only database node left in your cluster AND that other database nodes will
never come back (i.e. their LXD daemon won't ever be started again).

This will make this LXD instance the only member of the cluster, and it won't
be possible to perform operations on former cluster members anymore.

However all information about former cluster members will be preserved in the
database, so you can possibly inspect it for further recovery.

You'll be able to permanently delete from the database all information about
former cluster members by running "lxc cluster remove <member-name> --force".

See https://linuxcontainers.org/lxd/docs/master/clustering#recover-from-quorum-loss for more
info.

Do you want to proceed? (yes/no): `)
	input, _ := reader.ReadString('\n')
	input = strings.TrimSuffix(input, "\n")

	if !shared.StringInSlice(strings.ToLower(input), []string{"yes"}) {
		return fmt.Errorf("Recover operation aborted")
	}
	return nil
}

type cmdClusterRemoveRaftNode struct {
	global             *cmdGlobal
	flagNonInteractive bool
}

func (c *cmdClusterRemoveRaftNode) Command() *cobra.Command {
	cmd := &cobra.Command{}
	cmd.Use = "remove-raft-node <address>"
	cmd.Short = "Remove a raft node from the raft configuration"

	cmd.RunE = c.Run

	cmd.Flags().BoolVarP(&c.flagNonInteractive, "quiet", "q", false, "Don't require user confirmation")

	return cmd
}

func (c *cmdClusterRemoveRaftNode) Run(cmd *cobra.Command, args []string) error {
	if len(args) != 1 {
		cmd.Help()
		return fmt.Errorf("Missing required arguments")
	}

	address := util.CanonicalNetworkAddress(args[0])

	// Prompt for confirmation unless --quiet was passed.
	if !c.flagNonInteractive {
		err := c.promptConfirmation()
		if err != nil {
			return err
		}
	}

	client, err := lxd.ConnectLXDUnix("", nil)
	if err != nil {
		return errors.Wrapf(err, "Failed to connect to LXD daemon")
	}

	endpoint := fmt.Sprintf("/internal/cluster/raft-node/%s", address)
	_, _, err = client.RawQuery("DELETE", endpoint, nil, "")
	if err != nil {
		return err
	}

	return nil
}

func (c *cmdClusterRemoveRaftNode) promptConfirmation() error {
	reader := bufio.NewReader(os.Stdin)
	fmt.Printf(`You should run this command only if you ended up in an
inconsistent state where a node has been uncleanly removed (i.e. it doesn't show
up in "lxc cluster list" but it's still in the raft configuration).

Do you want to proceed? (yes/no): `)
	input, _ := reader.ReadString('\n')
	input = strings.TrimSuffix(input, "\n")

	if !shared.StringInSlice(strings.ToLower(input), []string{"yes"}) {
		return fmt.Errorf("Remove raft node operation aborted")
	}
	return nil
}
<|endoftext|>


<commit_before>package handlers

import (
	"fmt"
	"github.com/APTrust/easy-store/db/models"
	"github.com/gorilla/mux"
	_ "github.com/jinzhu/gorm/dialects/sqlite"
	"github.com/kirves/go-form-it"
	"github.com/kirves/go-form-it/fields"
	_ "github.com/mattn/go-sqlite3"
	"log"
	"net/http"
	"strconv"
)

func ProfileNewGet(w http.ResponseWriter, r *http.Request) {
	profile := models.BagItProfile{}
	form, err := ProfileForm(profile)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	data := make(map[string]interface{})
	data["form"] = form
	err = templates.ExecuteTemplate(w, "bagit-profile-form", data)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

func ProfileNewPost(w http.ResponseWriter, r *http.Request) {
	data := make(map[string]interface{})
	err := r.ParseForm()
	if err != nil {
		log.Println("Error:", err.Error())
	}
	profile := models.BagItProfile{}
	err = decoder.Decode(&profile, r.PostForm)
	if err != nil {
		log.Println("Error:", err.Error())
	}
	err = db.Save(&profile).Error
	if err != nil {
		log.Println("Error:", err.Error())
		data["errors"] = err.Error()
	} else {
		defaultTagValues := profile.DecodeDefaultTagValues(r.PostForm)
		log.Println(defaultTagValues)
		for _, val := range defaultTagValues {
			var valErr error
			if db.NewRecord(val) {
				log.Println("Creating", val.TagName, "=", val.TagValue)
				valErr = db.Create(&val).Error
			} else {
				log.Println("Updting", val.TagName, "=", val.TagValue)
				valErr = db.Save(&val).Error
			}
			if valErr != nil {
				log.Println("Error on", val.TagName, ":", valErr.Error())
				err = valErr
			}
		}
	}

	if err != nil {
		log.Println("Error:", err.Error())
		data["errors"] = err.Error()
	} else {
		http.Redirect(w, r, "/profiles?success=Profile+has+been+saved.", 303)
		return
	}

	form, err := ProfileForm(profile)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	data["form"] = form
	err = templates.ExecuteTemplate(w, "bagit-profile-form", data)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

func ProfilesList(w http.ResponseWriter, r *http.Request) {
	data := make(map[string]interface{})
	profiles := make([]models.BagItProfile, 0)
	db.Find(&profiles).Order("name")
	data["items"] = profiles
	successMessage, ok := r.URL.Query()["success"]
	if ok {
		data["success"] = successMessage[0]
	}
	err := templates.ExecuteTemplate(w, "bagit-profile-list", data)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

func ProfileEditGet(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	id, _ := strconv.Atoi(vars["id"])
	log.Println("GET profile", id)
	profile := models.BagItProfile{}
	db.Preload("DefaultTagValues").First(&profile, id)
	data := make(map[string]interface{})
	form, err := ProfileForm(profile)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	data["form"] = form
	err = templates.ExecuteTemplate(w, "bagit-profile-form", data)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

func ProfileEditPost(w http.ResponseWriter, r *http.Request) {
	data := make(map[string]interface{})
	vars := mux.Vars(r)
	id, _ := strconv.Atoi(vars["id"])
	log.Println("POST profile", id)
	err := r.ParseForm()
	if err != nil {
		log.Println("Error:", err.Error())
	}
	profile := models.BagItProfile{}
	err = decoder.Decode(&profile, r.PostForm)
	if err != nil {
		log.Println("Error:", err.Error())
	}
	profile.ID = uint(id)
	err = db.Save(&profile).Error
	if err != nil {
		data["errors"] = err.Error()
	} else {
		defaultTagValues := profile.DecodeDefaultTagValues(r.PostForm)
		for _, val := range defaultTagValues {
			var valErr error
			if db.NewRecord(val) {
				log.Println("Creating", val.TagName, "=", val.TagValue)
				valErr = db.Create(&val).Error
			} else {
				log.Println("Updting", val.TagName, "=", val.TagValue)
				valErr = db.Save(&val).Error
			}
			if valErr != nil {
				log.Println("Error on", val.TagName, ":", valErr.Error())
				err = valErr
			}
		}
	}

	if err != nil {
		data["errors"] = err.Error()
	} else {
		http.Redirect(w, r, "/profiles?success=Profile+has+been+saved.", 303)
		return
	}

	form, err := ProfileForm(profile)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	data["form"] = form
	err = templates.ExecuteTemplate(w, "bagit-profile-form", data)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

// Returns a BagItProfile form.
func ProfileForm(profile models.BagItProfile) (*forms.Form, error) {
	postUrl := fmt.Sprintf("/profile/new")
	if profile.ID > uint(0) {
		postUrl = fmt.Sprintf("/profile/%d/edit", profile.ID)
	}
	form := forms.BootstrapFormFromModel(profile, forms.POST, postUrl)
	form.Field("JSON").AddCss("height", "300px")
	if profile.JSON == "" {
		return form, nil
	}
	profileDef, err := profile.Profile()
	if err != nil {
		return nil, err
	}

	// Remove the submit button from the end of the form,
	// add our new elements, and then replace the submit button
	// at the end.
	submitButton := form.Field("submit")
	form.RemoveElement("submit")

	fieldSetNote := fields.StaticField("",
		"Set common tag values for this profile below. "+
			"Common tag defaults such as your organization name "+
			"apply across all bags created with this profile. "+
			"Leave fields such as bag title, description, etc. "+
			"blank if they should be set individually for each bag.")
	fieldSetNote.AddClass("well")
	form.Elements(fieldSetNote)

	for _, relFilePath := range profileDef.SortedTagFilesRequired() {
		fieldsInSet := make([]fields.FieldInterface, 0)
		mapOfRequiredTags := profileDef.TagFilesRequired[relFilePath]
		for _, tagname := range profileDef.SortedTagNames(relFilePath) {
			// This tag will always be set by the system, not the user.
			if tagname == "Payload-Oxum" {
				continue
			}
			tagdef := mapOfRequiredTags[tagname]
			defaultTags := profile.GetDefaultTagValues(relFilePath, tagname)
			defaultValue := ""
			defaultTagId := uint(0)
			if len(defaultTags) > 0 {
				defaultValue = defaultTags[0].TagValue
				defaultTagId = defaultTags[0].ID
			}
			fieldName := fmt.Sprintf("%s|%s|%d", relFilePath, tagname, defaultTagId)
			fieldLabel := tagname

			formField := fields.TextField(fieldName)
			if len(tagdef.Values) > 0 {
				options := make(map[string][]fields.InputChoice)
				options[""] = make([]fields.InputChoice, len(tagdef.Values)+1)
				options[""][0] = fields.InputChoice{Id: "", Val: ""}
				for i, val := range tagdef.Values {
					options[""][i+1] = fields.InputChoice{Id: val, Val: val}
				}
				formField = fields.SelectField(fieldName, options)
			}
			formField.SetLabel(fieldLabel)
			formField.SetValue(defaultValue)
			fieldsInSet = append(fieldsInSet, formField)
		}
		// Unfortunately, go-form-it does not support fieldset legends
		fieldSetLabel := fields.StaticField("", fmt.Sprintf("Default values for %s", relFilePath))
		fieldSetLabel.AddClass("fieldset-header")
		form.Elements(fieldSetLabel)
		fieldSet := forms.FieldSet(relFilePath, fieldsInSet...)
		form.Elements(fieldSet)
	}
	form.Elements(submitButton)

	return form, nil
}
<commit_msg>Added TODO<commit_after>package handlers

import (
	"fmt"
	"github.com/APTrust/easy-store/db/models"
	"github.com/gorilla/mux"
	_ "github.com/jinzhu/gorm/dialects/sqlite"
	"github.com/kirves/go-form-it"
	"github.com/kirves/go-form-it/fields"
	_ "github.com/mattn/go-sqlite3"
	"log"
	"net/http"
	"strconv"
)

func ProfileNewGet(w http.ResponseWriter, r *http.Request) {
	profile := models.BagItProfile{}
	form, err := ProfileForm(profile)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	data := make(map[string]interface{})
	data["form"] = form
	err = templates.ExecuteTemplate(w, "bagit-profile-form", data)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

func ProfileNewPost(w http.ResponseWriter, r *http.Request) {
	data := make(map[string]interface{})
	err := r.ParseForm()
	if err != nil {
		log.Println("Error:", err.Error())
	}
	profile := models.BagItProfile{}
	err = decoder.Decode(&profile, r.PostForm)
	if err != nil {
		log.Println("Error:", err.Error())
	}
	err = db.Save(&profile).Error
	if err != nil {
		log.Println("Error:", err.Error())
		data["errors"] = err.Error()
	} else {
		defaultTagValues := profile.DecodeDefaultTagValues(r.PostForm)
		log.Println(defaultTagValues)
		for _, val := range defaultTagValues {
			var valErr error
			if db.NewRecord(val) {
				log.Println("Creating", val.TagName, "=", val.TagValue)
				valErr = db.Create(&val).Error
			} else {
				log.Println("Updting", val.TagName, "=", val.TagValue)
				valErr = db.Save(&val).Error
			}
			if valErr != nil {
				log.Println("Error on", val.TagName, ":", valErr.Error())
				err = valErr
			}
		}
	}

	if err != nil {
		log.Println("Error:", err.Error())
		data["errors"] = err.Error()
	} else {
		http.Redirect(w, r, "/profiles?success=Profile+has+been+saved.", 303)
		return
	}

	form, err := ProfileForm(profile)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	data["form"] = form
	err = templates.ExecuteTemplate(w, "bagit-profile-form", data)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

func ProfilesList(w http.ResponseWriter, r *http.Request) {
	data := make(map[string]interface{})
	profiles := make([]models.BagItProfile, 0)
	db.Find(&profiles).Order("name")
	data["items"] = profiles
	successMessage, ok := r.URL.Query()["success"]
	if ok {
		data["success"] = successMessage[0]
	}
	err := templates.ExecuteTemplate(w, "bagit-profile-list", data)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

func ProfileEditGet(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	id, _ := strconv.Atoi(vars["id"])
	log.Println("GET profile", id)
	profile := models.BagItProfile{}
	db.Preload("DefaultTagValues").First(&profile, id)
	data := make(map[string]interface{})
	form, err := ProfileForm(profile)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	data["form"] = form
	err = templates.ExecuteTemplate(w, "bagit-profile-form", data)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

func ProfileEditPost(w http.ResponseWriter, r *http.Request) {
	data := make(map[string]interface{})
	vars := mux.Vars(r)
	id, _ := strconv.Atoi(vars["id"])
	log.Println("POST profile", id)
	err := r.ParseForm()
	if err != nil {
		log.Println("Error:", err.Error())
	}
	profile := models.BagItProfile{}
	err = decoder.Decode(&profile, r.PostForm)
	if err != nil {
		log.Println("Error:", err.Error())
	}
	profile.ID = uint(id)
	err = db.Save(&profile).Error
	if err != nil {
		data["errors"] = err.Error()
	} else {
		defaultTagValues := profile.DecodeDefaultTagValues(r.PostForm)
		for _, val := range defaultTagValues {
			var valErr error
			if db.NewRecord(val) {
				log.Println("Creating", val.TagName, "=", val.TagValue)
				valErr = db.Create(&val).Error
			} else {
				log.Println("Updting", val.TagName, "=", val.TagValue)
				valErr = db.Save(&val).Error
			}
			if valErr != nil {
				log.Println("Error on", val.TagName, ":", valErr.Error())
				err = valErr
			}
		}
	}

	if err != nil {
		data["errors"] = err.Error()
	} else {
		http.Redirect(w, r, "/profiles?success=Profile+has+been+saved.", 303)
		return
	}

	form, err := ProfileForm(profile)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	data["form"] = form
	err = templates.ExecuteTemplate(w, "bagit-profile-form", data)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

// Returns a BagItProfile form.
func ProfileForm(profile models.BagItProfile) (*forms.Form, error) {
	postUrl := fmt.Sprintf("/profile/new")
	if profile.ID > uint(0) {
		postUrl = fmt.Sprintf("/profile/%d/edit", profile.ID)
	}
	form := forms.BootstrapFormFromModel(profile, forms.POST, postUrl)
	form.Field("JSON").AddCss("height", "300px")
	if profile.JSON == "" {
		return form, nil
	}
	profileDef, err := profile.Profile()
	if err != nil {
		return nil, err
	}

	// Remove the submit button from the end of the form,
	// add our new elements, and then replace the submit button
	// at the end.
	submitButton := form.Field("submit")
	form.RemoveElement("submit")

	// TODO: i18n
	fieldSetNote := fields.StaticField("",
		"Set common tag values for this profile below. "+
			"Common tag defaults such as your organization name "+
			"apply across all bags created with this profile. "+
			"Leave fields such as bag title, description, etc. "+
			"blank if they should be set individually for each bag.")
	fieldSetNote.AddClass("well")
	form.Elements(fieldSetNote)

	for _, relFilePath := range profileDef.SortedTagFilesRequired() {
		fieldsInSet := make([]fields.FieldInterface, 0)
		mapOfRequiredTags := profileDef.TagFilesRequired[relFilePath]
		for _, tagname := range profileDef.SortedTagNames(relFilePath) {
			// This tag will always be set by the system, not the user.
			if tagname == "Payload-Oxum" {
				continue
			}
			tagdef := mapOfRequiredTags[tagname]
			defaultTags := profile.GetDefaultTagValues(relFilePath, tagname)
			defaultValue := ""
			defaultTagId := uint(0)
			if len(defaultTags) > 0 {
				defaultValue = defaultTags[0].TagValue
				defaultTagId = defaultTags[0].ID
			}
			fieldName := fmt.Sprintf("%s|%s|%d", relFilePath, tagname, defaultTagId)
			fieldLabel := tagname

			formField := fields.TextField(fieldName)
			if len(tagdef.Values) > 0 {
				options := make(map[string][]fields.InputChoice)
				options[""] = make([]fields.InputChoice, len(tagdef.Values)+1)
				options[""][0] = fields.InputChoice{Id: "", Val: ""}
				for i, val := range tagdef.Values {
					options[""][i+1] = fields.InputChoice{Id: val, Val: val}
				}
				formField = fields.SelectField(fieldName, options)
			}
			formField.SetLabel(fieldLabel)
			formField.SetValue(defaultValue)
			fieldsInSet = append(fieldsInSet, formField)
		}
		// Unfortunately, go-form-it does not support fieldset legends
		fieldSetLabel := fields.StaticField("", fmt.Sprintf("Default values for %s", relFilePath))
		fieldSetLabel.AddClass("fieldset-header")
		form.Elements(fieldSetLabel)
		fieldSet := forms.FieldSet(relFilePath, fieldsInSet...)
		form.Elements(fieldSet)
	}
	form.Elements(submitButton)

	return form, nil
}
<|endoftext|>


<commit_before>package sysfs

import (
	"fmt"
	"io/ioutil"
	"os"
	"reflect"
	"strconv"
	"strings"

	"github.com/prometheus/procfs/internal/util"
)

type PowerSupply struct {
	Name                     string // Power Supply Name
	Type                     string `fileName:"type"`                        // /sys/class/power_supply/<Name>/type
	Status                   string `fileName:"status"`                      // /sys/class/power_supply/<Name>/status
	VoltageNow               *int64 `fileName:"voltage_now"`                 // /sys/class/power_supply/<Name>/voltage_now
	EnergyNow                *int64 `fileName:"energy_now"`                  // /sys/class/power_supply/<Name>/energy_now
	ChargeType               string `fileName:"charge_type"`                 // /sys/class/power_supply/<Name>/charge_type
	Authentic                *int64 `fileName:"authentic"`                   // /sys/class/power_suppy/<Name>/authentic
	Health                   string `fileName:"health"`                      // /sys/class/power_suppy/<Name>/health
	VoltageOCV               *int64 `fileName:"voltage_ocv"`                 // /sys/class/power_suppy/<Name>/voltage_ocv
	VoltageMinDesign         *int64 `fileName:"voltage_min_design"`          // /sys/class/power_suppy/<Name>/voltage_min_design
	VoltageMaxDesign         *int64 `fileName:"voltage_max_design"`          // /sys/class/power_suppy/<Name>/voltage_max_design
	VoltageMin               *int64 `fileName:"voltage_min"`                 // /sys/class/power_suppy/<Name>/voltage_min
	VoltageMax               *int64 `fileName:"voltage_max"`                 // /sys/class/power_suppy/<Name>/voltage_max
	VoltageBoot              *int64 `fileName:"voltage_boot"`                // /sys/class/power_suppy/<Name>/voltage_boot
	CurrentBoot              *int64 `fileName:"current_boot"`                // /sys/class/power_suppy/<Name>/current_boot
	ChargeEmptyDesign        *int64 `fileName:"charge_empty_design"`         // /sys/class/power_suppy/<Name>/charge_empty_design
	ChargeFullDesign         *int64 `fileName:"charge_full_design"`          // /sys/class/power_suppy/<Name>/charge_full_design
	EnergyEmptyDesign        *int64 `fileName:"energy_empty_design"`         // /sys/class/power_suppy/<Name>/energy_empty_design
	EnergyFullDesign         *int64 `fileName:"energy_full_design"`          // /sys/class/power_suppy/<Name>/energy_full_design
	ChargeCounter            *int64 `fileName:"charge_counter"`              // /sys/class/power_suppy/<Name>/charge_counter
	PrechargeCurrent         *int64 `fileName:"precharge_current"`           // /sys/class/power_suppy/<Name>/precharge_current
	ChargeTermCurrent        *int64 `fileName:"charge_term_current"`         // /sys/class/power_suppy/<Name>/charge_term_current
	ConstantChargeCurrent    *int64 `fileName:"constant_charge_current"`     // /sys/class/power_suppy/<Name>/constant_charge_current
	ConstantChargeCurrentMax *int64 `fileName:"constant_charge_current_max"` // /sys/class/power_suppy/<Name>/constant_charge_current_max
	ConstantChargeVoltage    *int64 `fileName:"constant_charge_voltage"`     // /sys/class/power_suppy/<Name>/constant_charge_voltage
	ConstantChargeVoltageMax *int64 `fileName:"constant_charge_voltage_max"` // /sys/class/power_suppy/<Name>/constant_charge_voltage_max
	InputCurrentLimit        *int64 `fileName:"input_current_limit"`         // /sys/class/power_suppy/<Name>/input_current_limit
	ChargeControlLimit       *int64 `fileName:"charge_control_limit"`        // /sys/class/power_suppy/<Name>/charge_control_limit
	ChargeControlLimitMax    *int64 `fileName:"charge_control_limit_max"`    // /sys/class/power_suppy/<Name>/charge_control_limit_max
	Capacity                 *int64 `fileName:"capacity"`                    // /sys/class/power_suppy/<Name>/capacity
	CapacityAlertMin         *int64 `fileName:"capacity_alert_min"`          // /sys/class/power_suppy/<Name>/capacity_alert_min
	CapacityAlertMax         *int64 `fileName:"capacity_alert_max"`          // /sys/class/power_suppy/<Name>/capacity_alert_max
	CapacityLevel            string `fileName:"capacity_level"`              // /sys/class/power_suppy/<Name>/capacity_level
	Temp                     *int64 `fileName:"temp"`                        // /sys/class/power_suppy/<Name>/temp
	TempAlertMin             *int64 `fileName:"temp_alert_min"`              // /sys/class/power_suppy/<Name>/temp_alert_min
	TempAlertMax             *int64 `fileName:"temp_alert_max"`              // /sys/class/power_suppy/<Name>/temp_alert_max
	TempAmbient              *int64 `fileName:"temp_ambient"`                // /sys/class/power_suppy/<Name>/temp_ambient
	TempAmbientMin           *int64 `fileName:"temp_ambient_min"`            // /sys/class/power_suppy/<Name>/temp_ambient_min
	TempAmbientMax           *int64 `fileName:"temp_ambient_max"`            // /sys/class/power_suppy/<Name>/temp_ambient_max
	TempMin                  *int64 `fileName:"temp_min"`                    // /sys/class/power_suppy/<Name>/temp_min
	TempMax                  *int64 `fileName:"temp_max"`                    // /sys/class/power_suppy/<Name>/temp_max
	TimeToEmpty              *int64 `fileName:"time_to_empty"`               // /sys/class/power_suppy/<Name>/time_to_empty
	TimeToFull               *int64 `fileName:"time_to_full"`                // /sys/class/power_suppy/<Name>/time_to_full
}

type PowerSupplyClass map[string]PowerSupply

func NewPowerSupplyClass() (PowerSupplyClass, error) {
	fs, err := NewFS(DefaultMountPoint)
	if err != nil {
		return nil, err
	}

	return fs.NewPowerSupplyClass()
}

func (fs FS) NewPowerSupplyClass() (PowerSupplyClass, error) {
	path := fs.Path("class/power_supply")

	powerSupplyDirs, err := ioutil.ReadDir(path)
	if err != nil {
		return PowerSupplyClass{}, fmt.Errorf("cannot access %s dir %s", path, err)
	}

	powerSupplyClass := PowerSupplyClass{}
	for _, powerSupplyDir := range powerSupplyDirs {
		powerSupply, err := powerSupplyClass.parsePowerSupply(path + "/" + powerSupplyDir.Name())
		if err != nil {
			return nil, err
		}
		powerSupply.Name = powerSupplyDir.Name()
		powerSupplyClass[powerSupplyDir.Name()] = *powerSupply
	}
	return powerSupplyClass, nil
}

func (psc PowerSupplyClass) parsePowerSupply(powerSupplyPath string) (*PowerSupply, error) {
	powerSupply := PowerSupply{}
	powerSupplyElem := reflect.ValueOf(&powerSupply).Elem()
	powerSupplyType := reflect.TypeOf(powerSupply)

	//start from 1 - skip the Name field
	for i := 1; i < powerSupplyElem.NumField(); i++ {
		fieldType := powerSupplyType.Field(i)
		fieldValue := powerSupplyElem.Field(i)

		if fieldType.Tag.Get("fileName") == "" {
			panic(fmt.Errorf("field %s does not have a filename tag", fieldType.Name))
		}

		value, err := util.SysReadFile(powerSupplyPath + "/" + fieldType.Tag.Get("fileName"))

		if err != nil {
			if os.IsNotExist(err) || err.Error() == "operation not supported" || err.Error() == "invalid argument" {
				continue
			}
			return nil, fmt.Errorf("could not access file %s: %s", fieldType.Tag.Get("fileName"), err)
		}

		switch fieldValue.Kind() {
		case reflect.String:
			fieldValue.SetString(value)
		case reflect.Ptr:
			var int64ptr *int64
			switch fieldValue.Type() {
			case reflect.TypeOf(int64ptr):
				var intValue int64
				if strings.HasPrefix(value, "0x") {
					intValue, err = strconv.ParseInt(value[2:], 16, 64)
					if err != nil {
						return nil, fmt.Errorf("expected hex value for %s, got: %s", fieldType.Name, value)
					}
				} else {
					intValue, err = strconv.ParseInt(value, 10, 64)
					if err != nil {
						return nil, fmt.Errorf("expected Uint64 value for %s, got: %s", fieldType.Name, value)
					}
				}
				fieldValue.Set(reflect.ValueOf(&intValue))
			default:
				return nil, fmt.Errorf("unhandled pointer type %q", fieldValue.Type())
			}
		default:
			return nil, fmt.Errorf("unhandled type %q", fieldValue.Kind())
		}
	}

	return &powerSupply, nil
}
<commit_msg>Add more power supply attributes<commit_after>package sysfs

import (
	"fmt"
	"io/ioutil"
	"os"
	"reflect"
	"strconv"
	"strings"

	"github.com/prometheus/procfs/internal/util"
)

type PowerSupply struct {
	Name                     string // Power Supply Name
	Authentic                *int64 `fileName:"authentic"`                   // /sys/class/power_suppy/<Name>/authentic
	Calibrate                *int64 `fileName:"calibrate"`                   // /sys/class/power_suppy/<Name>/calibrate
	Capacity                 *int64 `fileName:"capacity"`                    // /sys/class/power_suppy/<Name>/capacity
	CapacityAlertMax         *int64 `fileName:"capacity_alert_max"`          // /sys/class/power_suppy/<Name>/capacity_alert_max
	CapacityAlertMin         *int64 `fileName:"capacity_alert_min"`          // /sys/class/power_suppy/<Name>/capacity_alert_min
	CapacityLevel            string `fileName:"capacity_level"`              // /sys/class/power_suppy/<Name>/capacity_level
	ChargeAvg                *int64 `fileName:"charge_avg"`                  // /sys/class/power_suppy/<Name>/charge_avg
	ChargeEmpty              *int64 `fileName:"charge_empty"`                // /sys/class/power_suppy/<Name>/charge_empty
	ChargeFull               *int64 `fileName:"charge_full"`                 // /sys/class/power_suppy/<Name>/charge_full
	ChargeNow                *int64 `fileName:"charge_now"`                  // /sys/class/power_suppy/<Name>/charge_now
	ChargeControlLimit       *int64 `fileName:"charge_control_limit"`        // /sys/class/power_suppy/<Name>/charge_control_limit
	ChargeControlLimitMax    *int64 `fileName:"charge_control_limit_max"`    // /sys/class/power_suppy/<Name>/charge_control_limit_max
	ChargeCounter            *int64 `fileName:"charge_counter"`              // /sys/class/power_suppy/<Name>/charge_counter
	ChargeEmptyDesign        *int64 `fileName:"charge_empty_design"`         // /sys/class/power_suppy/<Name>/charge_empty_design
	ChargeFullDesign         *int64 `fileName:"charge_full_design"`          // /sys/class/power_suppy/<Name>/charge_full_design
	ChargeTermCurrent        *int64 `fileName:"charge_term_current"`         // /sys/class/power_suppy/<Name>/charge_term_current
	ChargeType               string `fileName:"charge_type"`                 // /sys/class/power_supply/<Name>/charge_type
	ConstantChargeCurrent    *int64 `fileName:"constant_charge_current"`     // /sys/class/power_suppy/<Name>/constant_charge_current
	ConstantChargeCurrentMax *int64 `fileName:"constant_charge_current_max"` // /sys/class/power_suppy/<Name>/constant_charge_current_max
	ConstantChargeVoltage    *int64 `fileName:"constant_charge_voltage"`     // /sys/class/power_suppy/<Name>/constant_charge_voltage
	ConstantChargeVoltageMax *int64 `fileName:"constant_charge_voltage_max"` // /sys/class/power_suppy/<Name>/constant_charge_voltage_max
	CurrentBoot              *int64 `fileName:"current_boot"`                // /sys/class/power_suppy/<Name>/current_boot
	CurrentAvg               *int64 `fileName:"current_avg"`                 // /sys/class/power_suppy/<Name>/current_avg
	CurrentMax               *int64 `fileName:"current_max"`                 // /sys/class/power_suppy/<Name>/current_max
	CurrentNow               *int64 `fileName:"current_now"`                 // /sys/class/power_suppy/<Name>/current_now
	CycleCount               *int64 `fileName:"cycle_count"`                 // /sys/class/power_suppy/<Name>/cycle_count
	EnergyEmptyDesign        *int64 `fileName:"energy_empty_design"`         // /sys/class/power_suppy/<Name>/energy_empty_design
	EnergyFullDesign         *int64 `fileName:"energy_full_design"`          // /sys/class/power_suppy/<Name>/energy_full_design
	EnergyNow                *int64 `fileName:"energy_now"`                  // /sys/class/power_supply/<Name>/energy_now
	EnergyEmpty              *int64 `fileName:"energy_empty"`                // /sys/class/power_suppy/<Name>/energy_empty
	EnergyFull               *int64 `fileName:"energy_full"`                 // /sys/class/power_suppy/<Name>/energy_full
	EnergyAvg                *int64 `fileName:"energy_avg"`                  // /sys/class/power_supply/<Name>/energy_avg
	Health                   string `fileName:"health"`                      // /sys/class/power_suppy/<Name>/health
	InputCurrentLimit        *int64 `fileName:"input_current_limit"`         // /sys/class/power_suppy/<Name>/input_current_limit
	Manufacturer             string `fileName:"manufacturer"`                // /sys/class/power_suppy/<Name>/manufacturer
	ModelName                string `fileName:"model_name"`                  // /sys/class/power_suppy/<Name>/model_name
	Online                   *int64 `fileName:"online"`                      // /sys/class/power_suppy/<Name>/online
	PowerAvg                 *int64 `fileName:"power_avg"`                   // /sys/class/power_suppy/<Name>/power_avg
	PowerNow                 *int64 `fileName:"power_now"`                   // /sys/class/power_suppy/<Name>/power_now
	PrechargeCurrent         *int64 `fileName:"precharge_current"`           // /sys/class/power_suppy/<Name>/precharge_current
	Present                  *int64 `fileName:"power_avg"`                   // /sys/class/power_suppy/<Name>/present
	Scope                    *int64 `fileName:"scope"`                       // /sys/class/power_suppy/<Name>/scope
	SerialNumber             string `fileName:"serial_number"`               // /sys/class/power_suppy/<Name>/serial_number
	Status                   string `fileName:"status"`                      // /sys/class/power_supply/<Name>/status
	Technology               string `fileName:"technology"`                  // /sys/class/power_suppy/<Name>/technology
	Temp                     *int64 `fileName:"temp"`                        // /sys/class/power_suppy/<Name>/temp
	TempAlertMax             *int64 `fileName:"temp_alert_max"`              // /sys/class/power_suppy/<Name>/temp_alert_max
	TempAlertMin             *int64 `fileName:"temp_alert_min"`              // /sys/class/power_suppy/<Name>/temp_alert_min
	TempAmbient              *int64 `fileName:"temp_ambient"`                // /sys/class/power_suppy/<Name>/temp_ambient
	TempAmbientMax           *int64 `fileName:"temp_ambient_max"`            // /sys/class/power_suppy/<Name>/temp_ambient_max
	TempAmbientMin           *int64 `fileName:"temp_ambient_min"`            // /sys/class/power_suppy/<Name>/temp_ambient_min
	TempMax                  *int64 `fileName:"temp_max"`                    // /sys/class/power_suppy/<Name>/temp_max
	TempMin                  *int64 `fileName:"temp_min"`                    // /sys/class/power_suppy/<Name>/temp_min
	TimeToEmptyAvg           *int64 `fileName:"time_to_empty_avg"`           // /sys/class/power_suppy/<Name>/time_to_empty_avg
	TimeToFullAvg            *int64 `fileName:"time_to_full_avg"`            // /sys/class/power_suppy/<Name>/time_to_full_avg
	TimeToEmptyNow           *int64 `fileName:"time_to_empty_now"`           // /sys/class/power_suppy/<Name>/time_to_empty_now
	TimeToFullNow            *int64 `fileName:"time_to_full_now"`            // /sys/class/power_suppy/<Name>/time_to_full_now
	Type                     string `fileName:"type"`                        // /sys/class/power_supply/<Name>/type
	UsbType                  string `fileName:"usb_type"`                    // /sys/class/power_supply/<Name>/usb_type
	VoltageBoot              *int64 `fileName:"voltage_boot"`                // /sys/class/power_suppy/<Name>/voltage_boot
	VoltageMax               *int64 `fileName:"voltage_max"`                 // /sys/class/power_suppy/<Name>/voltage_max
	VoltageMaxDesign         *int64 `fileName:"voltage_max_design"`          // /sys/class/power_suppy/<Name>/voltage_max_design
	VoltageMin               *int64 `fileName:"voltage_min"`                 // /sys/class/power_suppy/<Name>/voltage_min
	VoltageMinDesign         *int64 `fileName:"voltage_min_design"`          // /sys/class/power_suppy/<Name>/voltage_min_design
	VoltageNow               *int64 `fileName:"voltage_now"`                 // /sys/class/power_supply/<Name>/voltage_now
	VoltageAvg               *int64 `fileName:"voltage_avg"`                 // /sys/class/power_supply/<Name>/voltage_avg
	VoltageOCV               *int64 `fileName:"voltage_ocv"`                 // /sys/class/power_suppy/<Name>/voltage_ocv
}

type PowerSupplyClass map[string]PowerSupply

func NewPowerSupplyClass() (PowerSupplyClass, error) {
	fs, err := NewFS(DefaultMountPoint)
	if err != nil {
		return nil, err
	}

	return fs.NewPowerSupplyClass()
}

func (fs FS) NewPowerSupplyClass() (PowerSupplyClass, error) {
	path := fs.Path("class/power_supply")

	powerSupplyDirs, err := ioutil.ReadDir(path)
	if err != nil {
		return PowerSupplyClass{}, fmt.Errorf("cannot access %s dir %s", path, err)
	}

	powerSupplyClass := PowerSupplyClass{}
	for _, powerSupplyDir := range powerSupplyDirs {
		powerSupply, err := powerSupplyClass.parsePowerSupply(path + "/" + powerSupplyDir.Name())
		if err != nil {
			return nil, err
		}
		powerSupply.Name = powerSupplyDir.Name()
		powerSupplyClass[powerSupplyDir.Name()] = *powerSupply
	}
	return powerSupplyClass, nil
}

func (psc PowerSupplyClass) parsePowerSupply(powerSupplyPath string) (*PowerSupply, error) {
	powerSupply := PowerSupply{}
	powerSupplyElem := reflect.ValueOf(&powerSupply).Elem()
	powerSupplyType := reflect.TypeOf(powerSupply)

	//start from 1 - skip the Name field
	for i := 1; i < powerSupplyElem.NumField(); i++ {
		fieldType := powerSupplyType.Field(i)
		fieldValue := powerSupplyElem.Field(i)

		if fieldType.Tag.Get("fileName") == "" {
			panic(fmt.Errorf("field %s does not have a filename tag", fieldType.Name))
		}

		value, err := util.SysReadFile(powerSupplyPath + "/" + fieldType.Tag.Get("fileName"))

		if err != nil {
			if os.IsNotExist(err) || err.Error() == "operation not supported" || err.Error() == "invalid argument" {
				continue
			}
			return nil, fmt.Errorf("could not access file %s: %s", fieldType.Tag.Get("fileName"), err)
		}

		switch fieldValue.Kind() {
		case reflect.String:
			fieldValue.SetString(value)
		case reflect.Ptr:
			var int64ptr *int64
			switch fieldValue.Type() {
			case reflect.TypeOf(int64ptr):
				var intValue int64
				if strings.HasPrefix(value, "0x") {
					intValue, err = strconv.ParseInt(value[2:], 16, 64)
					if err != nil {
						return nil, fmt.Errorf("expected hex value for %s, got: %s", fieldType.Name, value)
					}
				} else {
					intValue, err = strconv.ParseInt(value, 10, 64)
					if err != nil {
						return nil, fmt.Errorf("expected Uint64 value for %s, got: %s", fieldType.Name, value)
					}
				}
				fieldValue.Set(reflect.ValueOf(&intValue))
			default:
				return nil, fmt.Errorf("unhandled pointer type %q", fieldValue.Type())
			}
		default:
			return nil, fmt.Errorf("unhandled type %q", fieldValue.Kind())
		}
	}

	return &powerSupply, nil
}
<|endoftext|>


<commit_before>// +build coprocess
// +build lua

package main

/*
#cgo pkg-config: luajit

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "coprocess/sds/sds.h"

#include "coprocess/api.h"

#include "coprocess/lua/binding.h"

#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>

static void LuaInit() {
  // TODO: Cache the middlewares.
}

static struct CoProcessMessage* LuaDispatchHook(struct CoProcessMessage* object) {

  struct CoProcessMessage* outputObject = malloc(sizeof *outputObject);

  lua_State *L = luaL_newstate();

  luaL_openlibs(L);
  luaL_dofile(L, "coprocess/lua/tyk/core.lua");

  lua_getglobal(L, "dispatch");
  lua_pushlstring(L, object->p_data, object->length);
  lua_pcall(L, 1, 1, 0);

  size_t lua_output_length = lua_tointeger(L, 0);
  const char* lua_output_data = lua_tolstring(L, 1, &lua_output_length);

  char* output = malloc(lua_output_length);
  memmove(output, lua_output_data, lua_output_length);

  lua_close(L);

  outputObject->p_data = (void*)output;
  outputObject->length = lua_output_length;

  return outputObject;
}
*/
import "C"

import(
  "unsafe"

  "github.com/TykTechnologies/tyk/coprocess"
  "github.com/Sirupsen/logrus"
)

// CoProcessName declares the driver name.
const CoProcessName string = "lua"

// MessageType sets the default message type.
var MessageType = coprocess.JsonMessage

// LuaDispatcher implements a coprocess.Dispatcher
type LuaDispatcher struct {
	coprocess.Dispatcher
}

// Dispatch takes a CoProcessMessage and sends it to the CP.
func (d *LuaDispatcher) Dispatch(objectPtr unsafe.Pointer) unsafe.Pointer {
	var object *C.struct_CoProcessMessage
	object = (*C.struct_CoProcessMessage)(objectPtr)

	var newObjectPtr *C.struct_CoProcessMessage
	newObjectPtr = C.LuaDispatchHook(object)

	return unsafe.Pointer(newObjectPtr)
}

func LuaInit() {
  C.LuaInit()
}

// NewCoProcessDispatcher wraps all the actions needed for this CP.
func NewCoProcessDispatcher() (dispatcher coprocess.Dispatcher, err error) {

  LuaInit()

  dispatcher, err = &LuaDispatcher{}, nil

	if err != nil {
		log.WithFields(logrus.Fields{
			"prefix": "coprocess",
		}).Error(err)
	}

	return dispatcher, err
}
<commit_msg>Lua CP event dispatcher.<commit_after>// +build coprocess
// +build lua

package main

/*
#cgo pkg-config: luajit

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "coprocess/sds/sds.h"

#include "coprocess/api.h"

#include "coprocess/lua/binding.h"

#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>

static void LuaInit() {
  // TODO: Cache the middlewares.
}

static void LuaReload() {
}

static struct CoProcessMessage* LuaDispatchHook(struct CoProcessMessage* object) {

  struct CoProcessMessage* outputObject = malloc(sizeof *outputObject);

  lua_State *L = luaL_newstate();

  luaL_openlibs(L);
  luaL_dofile(L, "coprocess/lua/tyk/core.lua");

  lua_getglobal(L, "dispatch");
  lua_pushlstring(L, object->p_data, object->length);
  lua_pcall(L, 1, 1, 0);

  size_t lua_output_length = lua_tointeger(L, 0);
  const char* lua_output_data = lua_tolstring(L, 1, &lua_output_length);

  char* output = malloc(lua_output_length);
  memmove(output, lua_output_data, lua_output_length);

  lua_close(L);

  outputObject->p_data = (void*)output;
  outputObject->length = lua_output_length;

  return outputObject;
}

static void LuaDispatchEvent(char* event_json) {
}
*/
import "C"

import(
  "unsafe"

  "github.com/TykTechnologies/tyk/coprocess"
  "github.com/Sirupsen/logrus"
)

// CoProcessName declares the driver name.
const CoProcessName string = "lua"

// MessageType sets the default message type.
var MessageType = coprocess.JsonMessage

// LuaDispatcher implements a coprocess.Dispatcher
type LuaDispatcher struct {
	coprocess.Dispatcher
}

// Dispatch takes a CoProcessMessage and sends it to the CP.
func (d *LuaDispatcher) Dispatch(objectPtr unsafe.Pointer) unsafe.Pointer {
	var object *C.struct_CoProcessMessage
	object = (*C.struct_CoProcessMessage)(objectPtr)

	var newObjectPtr *C.struct_CoProcessMessage
	newObjectPtr = C.LuaDispatchHook(object)

	return unsafe.Pointer(newObjectPtr)
}

func (d *LuaDispatcher) Reload() {
  C.LuaReload()
}

func (d *LuaDispatcher) DispatchEvent(eventJSON []byte) {
  var CEventJSON *C.char
  CEventJSON = C.CString(string(eventJSON))
  C.LuaDispatchEvent(CEventJSON)
  C.free(unsafe.Pointer(CEventJSON))
  return
}

func LuaInit() {
  C.LuaInit()
}

// NewCoProcessDispatcher wraps all the actions needed for this CP.
func NewCoProcessDispatcher() (dispatcher coprocess.Dispatcher, err error) {

  LuaInit()

  dispatcher, err = &LuaDispatcher{}, nil

	if err != nil {
		log.WithFields(logrus.Fields{
			"prefix": "coprocess",
		}).Error(err)
	}

	return dispatcher, err
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"testing"
	"time"

	pb "github.com/brotherlogic/gobuildmaster/proto"
	pbs "github.com/brotherlogic/gobuildslave/proto"
)

func InitTestServer() *Server {
	s := Init(&pb.Config{})
	s.PrepServer()
	s.SkipLog = true
	return s
}

func TestBuildWorld(t *testing.T) {
	s := InitTestServer()
	g := &testGetter{running: make(map[string][]*pbs.JobAssignment)}
	g.running["testserver"] = []*pbs.JobAssignment{&pbs.JobAssignment{Job: &pbs.Job{Name: "testjob"}}}
	s.getter = g

	s.buildWorld(context.Background())
	if _, ok := s.world["testjob"]["testserver"]; !ok {
		t.Fatalf("World has not been built correctly: %v", s.world)
	}
}

func TestBuildEmptyWorld(t *testing.T) {
	s := InitTestServer()
	g := &testGetter{running: make(map[string][]*pbs.JobAssignment)}
	s.getter = g

	err := s.buildWorld(context.Background())
	if err == nil {
		t.Errorf("Should have been empty")
	}
}

func TestBuildWorldFailSlaves(t *testing.T) {
	s := InitTestServer()
	g := &testGetter{failGetSlaves: true, running: make(map[string][]*pbs.JobAssignment)}
	g.running["testserver"] = []*pbs.JobAssignment{&pbs.JobAssignment{Job: &pbs.Job{Name: "testjob"}}}
	s.getter = g

	s.buildWorld(context.Background())
	if len(s.world) != 0 {
		t.Errorf("World has been built: %v", s.world)
	}
}

func TestBuildWorldFailJobs(t *testing.T) {
	s := InitTestServer()
	g := &testGetter{failGetJobs: true, running: make(map[string][]*pbs.JobAssignment)}
	g.running["testserver"] = []*pbs.JobAssignment{&pbs.JobAssignment{Job: &pbs.Job{Name: "testjob"}}}
	s.getter = g

	s.buildWorld(context.Background())
	if len(s.world) != 0 {
		t.Errorf("World has been built: %v", s.world)
	}
}

func TestAlertOnMissingServer(t *testing.T) {
	s := InitTestServer()
	s.Register = s
	g := &testGetter{running: make(map[string][]*pbs.JobAssignment)}
	g.running["server1"] = []*pbs.JobAssignment{&pbs.JobAssignment{Server: "server1", Job: &pbs.Job{Name: "testjob"}}, &pbs.JobAssignment{Server: "server2", Job: &pbs.Job{Name: "testjob2"}}}
	g.running["server2"] = []*pbs.JobAssignment{&pbs.JobAssignment{Server: "server1", Job: &pbs.Job{Name: "testjob"}}, &pbs.JobAssignment{Server: "server2", Job: &pbs.Job{Name: "testjob2"}}}

	s.getter = g
	s.buildWorld(context.Background())
	time.Sleep(time.Second)

	g = &testGetter{running: make(map[string][]*pbs.JobAssignment)}
	g.running["server1"] = []*pbs.JobAssignment{&pbs.JobAssignment{Server: "server1", Job: &pbs.Job{Name: "testjob"}}}
	s.getter = g
	s.timeChange = time.Second
	s.buildWorld(context.Background())

	if s.AlertsFired != 1 {
		t.Errorf("No alert on missing server: %v", s.AlertsFired)
	}
}

func TestBuildWorldWithCountAlert(t *testing.T) {
	s := InitTestServer()
	s.config.Nintents = append(s.config.Nintents, &pb.NIntent{
		Count: 1,
		Job:   &pbs.Job{Name: "testjob"},
	})
	g := &testGetter{running: make(map[string][]*pbs.JobAssignment)}
	g.running["testserver1"] = []*pbs.JobAssignment{&pbs.JobAssignment{Job: &pbs.Job{Name: "testjob"}}}
	g.running["testserver2"] = []*pbs.JobAssignment{&pbs.JobAssignment{Job: &pbs.Job{Name: "testjob"}}}
	g.running["testserver3"] = []*pbs.JobAssignment{&pbs.JobAssignment{Job: &pbs.Job{Name: "testjob"}}}
	s.getter = g

	s.buildWorld(context.Background())
	if _, ok := s.world["testjob"]["testserver1"]; !ok {
		t.Fatalf("World has not been built correctly: %v", s.world)
	}
}
<commit_msg>Fixer<commit_after>package main

import (
	"context"
	"testing"
	"time"

	pb "github.com/brotherlogic/gobuildmaster/proto"
	pbs "github.com/brotherlogic/gobuildslave/proto"
)

func InitTestServer() *Server {
	s := Init(&pb.Config{})
	s.PrepServer()
	s.SkipLog = true
	s.SkipIssue = true
	return s
}

func TestBuildWorld(t *testing.T) {
	s := InitTestServer()
	g := &testGetter{running: make(map[string][]*pbs.JobAssignment)}
	g.running["testserver"] = []*pbs.JobAssignment{&pbs.JobAssignment{Job: &pbs.Job{Name: "testjob"}}}
	s.getter = g

	s.buildWorld(context.Background())
	if _, ok := s.world["testjob"]["testserver"]; !ok {
		t.Fatalf("World has not been built correctly: %v", s.world)
	}
}

func TestBuildEmptyWorld(t *testing.T) {
	s := InitTestServer()
	g := &testGetter{running: make(map[string][]*pbs.JobAssignment)}
	s.getter = g

	err := s.buildWorld(context.Background())
	if err == nil {
		t.Errorf("Should have been empty")
	}
}

func TestBuildWorldFailSlaves(t *testing.T) {
	s := InitTestServer()
	g := &testGetter{failGetSlaves: true, running: make(map[string][]*pbs.JobAssignment)}
	g.running["testserver"] = []*pbs.JobAssignment{&pbs.JobAssignment{Job: &pbs.Job{Name: "testjob"}}}
	s.getter = g

	s.buildWorld(context.Background())
	if len(s.world) != 0 {
		t.Errorf("World has been built: %v", s.world)
	}
}

func TestBuildWorldFailJobs(t *testing.T) {
	s := InitTestServer()
	g := &testGetter{failGetJobs: true, running: make(map[string][]*pbs.JobAssignment)}
	g.running["testserver"] = []*pbs.JobAssignment{&pbs.JobAssignment{Job: &pbs.Job{Name: "testjob"}}}
	s.getter = g

	s.buildWorld(context.Background())
	if len(s.world) != 0 {
		t.Errorf("World has been built: %v", s.world)
	}
}

func TestAlertOnMissingServer(t *testing.T) {
	s := InitTestServer()
	s.Register = s
	g := &testGetter{running: make(map[string][]*pbs.JobAssignment)}
	g.running["server1"] = []*pbs.JobAssignment{&pbs.JobAssignment{Server: "server1", Job: &pbs.Job{Name: "testjob"}}, &pbs.JobAssignment{Server: "server2", Job: &pbs.Job{Name: "testjob2"}}}
	g.running["server2"] = []*pbs.JobAssignment{&pbs.JobAssignment{Server: "server1", Job: &pbs.Job{Name: "testjob"}}, &pbs.JobAssignment{Server: "server2", Job: &pbs.Job{Name: "testjob2"}}}

	s.getter = g
	s.buildWorld(context.Background())
	time.Sleep(time.Second)

	g = &testGetter{running: make(map[string][]*pbs.JobAssignment)}
	g.running["server1"] = []*pbs.JobAssignment{&pbs.JobAssignment{Server: "server1", Job: &pbs.Job{Name: "testjob"}}}
	s.getter = g
	s.timeChange = time.Second
	s.buildWorld(context.Background())

	if s.AlertsFired != 1 {
		t.Errorf("No alert on missing server: %v", s.AlertsFired)
	}
}

func TestBuildWorldWithCountAlert(t *testing.T) {
	s := InitTestServer()
	s.config.Nintents = append(s.config.Nintents, &pb.NIntent{
		Count: 1,
		Job:   &pbs.Job{Name: "testjob"},
	})
	g := &testGetter{running: make(map[string][]*pbs.JobAssignment)}
	g.running["testserver1"] = []*pbs.JobAssignment{&pbs.JobAssignment{Job: &pbs.Job{Name: "testjob"}}}
	g.running["testserver2"] = []*pbs.JobAssignment{&pbs.JobAssignment{Job: &pbs.Job{Name: "testjob"}}}
	g.running["testserver3"] = []*pbs.JobAssignment{&pbs.JobAssignment{Job: &pbs.Job{Name: "testjob"}}}
	s.getter = g

	s.buildWorld(context.Background())
	if _, ok := s.world["testjob"]["testserver1"]; !ok {
		t.Fatalf("World has not been built correctly: %v", s.world)
	}
}
<|endoftext|>


<commit_before>package xmlutil

import (
	"encoding/base64"
	"encoding/xml"
	"fmt"
	"io"
	"reflect"
	"strconv"
	"strings"
	"time"

	"github.com/aws/aws-sdk-go/aws"
)

// UnmarshalXML deserializes an xml.Decoder into the container v. V
// needs to match the shape of the XML expected to be decoded.
// If the shape doesn't match unmarshaling will fail.
func UnmarshalXML(v interface{}, d *xml.Decoder, wrapper string) error {
	n, err := XMLToStruct(d, nil)
	if err != nil {
		return err
	}
	if n.Children != nil {
		for _, root := range n.Children {
			for _, c := range root {
				if wrappedChild, ok := c.Children[wrapper]; ok {
					c = wrappedChild[0] // pull out wrapped element
				}

				err = parse(reflect.ValueOf(v), c, "")
				if err != nil {
					if err == io.EOF {
						return nil
					}
					return err
				}
			}
		}
		return nil
	}
	return nil
}

// parse deserializes any value from the XMLNode. The type tag is used to infer the type, or reflect
// will be used to determine the type from r.
func parse(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
	rtype := r.Type()
	if rtype.Kind() == reflect.Ptr {
		rtype = rtype.Elem() // check kind of actual element type
	}

	t := tag.Get("type")
	if t == "" {
		switch rtype.Kind() {
		case reflect.Struct:
			// also it can't be a time object
			if _, ok := r.Interface().(*time.Time); !ok {
				t = "structure"
			}
		case reflect.Slice:
			// also it can't be a byte slice
			if _, ok := r.Interface().([]byte); !ok {
				t = "list"
			}
		case reflect.Map:
			// cannot be a JSONValue map
			if _, ok := r.Interface().(aws.JSONValue); !ok {
				t = "map"
			}
		}
	}

	switch t {
	case "structure":
		if field, ok := rtype.FieldByName("_"); ok {
			tag = field.Tag
		}
		return parseStruct(r, node, tag)
	case "list":
		return parseList(r, node, tag)
	case "map":
		return parseMap(r, node, tag)
	default:
		return parseScalar(r, node, tag)
	}
}

// parseStruct deserializes a structure and its fields from an XMLNode. Any nested
// types in the structure will also be deserialized.
func parseStruct(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
	t := r.Type()
	if r.Kind() == reflect.Ptr {
		if r.IsNil() { // create the structure if it's nil
			s := reflect.New(r.Type().Elem())
			r.Set(s)
			r = s
		}

		r = r.Elem()
		t = t.Elem()
	}

	// unwrap any payloads
	if payload := tag.Get("payload"); payload != "" {
		field, _ := t.FieldByName(payload)
		return parseStruct(r.FieldByName(payload), node, field.Tag)
	}

	for i := 0; i < t.NumField(); i++ {
		field := t.Field(i)
		if c := field.Name[0:1]; strings.ToLower(c) == c {
			continue // ignore unexported fields
		}

		// figure out what this field is called
		name := field.Name
		if field.Tag.Get("flattened") != "" && field.Tag.Get("locationNameList") != "" {
			name = field.Tag.Get("locationNameList")
		} else if locName := field.Tag.Get("locationName"); locName != "" {
			name = locName
		}

		// try to find the field by name in elements
		elems := node.Children[name]

		if elems == nil { // try to find the field in attributes
			if val, ok := node.findElem(name); ok {
				elems = []*XMLNode{{Text: val}}
			}
		}

		member := r.FieldByName(field.Name)
		for _, elem := range elems {
			err := parse(member, elem, field.Tag)
			if err != nil {
				return err
			}
		}
	}
	return nil
}

// parseList deserializes a list of values from an XML node. Each list entry
// will also be deserialized.
func parseList(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
	t := r.Type()

	if tag.Get("flattened") == "" { // look at all item entries
		mname := "member"
		if name := tag.Get("locationNameList"); name != "" {
			mname = name
		}

		if Children, ok := node.Children[mname]; ok {
			if r.IsNil() {
				r.Set(reflect.MakeSlice(t, len(Children), len(Children)))
			}

			for i, c := range Children {
				err := parse(r.Index(i), c, "")
				if err != nil {
					return err
				}
			}
		}
	} else { // flattened list means this is a single element
		if r.IsNil() {
			r.Set(reflect.MakeSlice(t, 0, 0))
		}

		childR := reflect.Zero(t.Elem())
		r.Set(reflect.Append(r, childR))
		err := parse(r.Index(r.Len()-1), node, "")
		if err != nil {
			return err
		}
	}

	return nil
}

// parseMap deserializes a map from an XMLNode. The direct children of the XMLNode
// will also be deserialized as map entries.
func parseMap(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
	if r.IsNil() {
		r.Set(reflect.MakeMap(r.Type()))
	}

	if tag.Get("flattened") == "" { // look at all child entries
		for _, entry := range node.Children["entry"] {
			parseMapEntry(r, entry, tag)
		}
	} else { // this element is itself an entry
		parseMapEntry(r, node, tag)
	}

	return nil
}

// parseMapEntry deserializes a map entry from a XML node.
func parseMapEntry(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
	kname, vname := "key", "value"
	if n := tag.Get("locationNameKey"); n != "" {
		kname = n
	}
	if n := tag.Get("locationNameValue"); n != "" {
		vname = n
	}

	keys, ok := node.Children[kname]
	values := node.Children[vname]
	if ok {
		for i, key := range keys {
			keyR := reflect.ValueOf(key.Text)
			value := values[i]
			valueR := reflect.New(r.Type().Elem()).Elem()

			parse(valueR, value, "")
			r.SetMapIndex(keyR, valueR)
		}
	}
	return nil
}

// parseScaller deserializes an XMLNode value into a concrete type based on the
// interface type of r.
//
// Error is returned if the deserialization fails due to invalid type conversion,
// or unsupported interface type.
func parseScalar(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
	switch r.Interface().(type) {
	case *string:
		r.Set(reflect.ValueOf(&node.Text))
		return nil
	case []byte:
		b, err := base64.StdEncoding.DecodeString(node.Text)
		if err != nil {
			return err
		}
		r.Set(reflect.ValueOf(b))
	case *bool:
		v, err := strconv.ParseBool(node.Text)
		if err != nil {
			return err
		}
		r.Set(reflect.ValueOf(&v))
	case *int64:
		v, err := strconv.ParseInt(node.Text, 10, 64)
		if err != nil {
			return err
		}
		r.Set(reflect.ValueOf(&v))
	case *float64:
		v, err := strconv.ParseFloat(node.Text, 64)
		if err != nil {
			return err
		}
		r.Set(reflect.ValueOf(&v))
	case *time.Time:
		const ISO8601UTC = "2006-01-02T15:04:05Z"
		t, err := time.Parse(ISO8601UTC, node.Text)
		if err != nil {
			return err
		}
		r.Set(reflect.ValueOf(&t))
	default:
		return fmt.Errorf("unsupported value: %v (%s)", r.Interface(), r.Type())
	}
	return nil
}
<commit_msg>private/protocol/xml/xmlutil: Remove processing of JSONValue from unmarhsaler (#1911)<commit_after>package xmlutil

import (
	"encoding/base64"
	"encoding/xml"
	"fmt"
	"io"
	"reflect"
	"strconv"
	"strings"
	"time"
)

// UnmarshalXML deserializes an xml.Decoder into the container v. V
// needs to match the shape of the XML expected to be decoded.
// If the shape doesn't match unmarshaling will fail.
func UnmarshalXML(v interface{}, d *xml.Decoder, wrapper string) error {
	n, err := XMLToStruct(d, nil)
	if err != nil {
		return err
	}
	if n.Children != nil {
		for _, root := range n.Children {
			for _, c := range root {
				if wrappedChild, ok := c.Children[wrapper]; ok {
					c = wrappedChild[0] // pull out wrapped element
				}

				err = parse(reflect.ValueOf(v), c, "")
				if err != nil {
					if err == io.EOF {
						return nil
					}
					return err
				}
			}
		}
		return nil
	}
	return nil
}

// parse deserializes any value from the XMLNode. The type tag is used to infer the type, or reflect
// will be used to determine the type from r.
func parse(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
	rtype := r.Type()
	if rtype.Kind() == reflect.Ptr {
		rtype = rtype.Elem() // check kind of actual element type
	}

	t := tag.Get("type")
	if t == "" {
		switch rtype.Kind() {
		case reflect.Struct:
			// also it can't be a time object
			if _, ok := r.Interface().(*time.Time); !ok {
				t = "structure"
			}
		case reflect.Slice:
			// also it can't be a byte slice
			if _, ok := r.Interface().([]byte); !ok {
				t = "list"
			}
		case reflect.Map:
			t = "map"
		}
	}

	switch t {
	case "structure":
		if field, ok := rtype.FieldByName("_"); ok {
			tag = field.Tag
		}
		return parseStruct(r, node, tag)
	case "list":
		return parseList(r, node, tag)
	case "map":
		return parseMap(r, node, tag)
	default:
		return parseScalar(r, node, tag)
	}
}

// parseStruct deserializes a structure and its fields from an XMLNode. Any nested
// types in the structure will also be deserialized.
func parseStruct(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
	t := r.Type()
	if r.Kind() == reflect.Ptr {
		if r.IsNil() { // create the structure if it's nil
			s := reflect.New(r.Type().Elem())
			r.Set(s)
			r = s
		}

		r = r.Elem()
		t = t.Elem()
	}

	// unwrap any payloads
	if payload := tag.Get("payload"); payload != "" {
		field, _ := t.FieldByName(payload)
		return parseStruct(r.FieldByName(payload), node, field.Tag)
	}

	for i := 0; i < t.NumField(); i++ {
		field := t.Field(i)
		if c := field.Name[0:1]; strings.ToLower(c) == c {
			continue // ignore unexported fields
		}

		// figure out what this field is called
		name := field.Name
		if field.Tag.Get("flattened") != "" && field.Tag.Get("locationNameList") != "" {
			name = field.Tag.Get("locationNameList")
		} else if locName := field.Tag.Get("locationName"); locName != "" {
			name = locName
		}

		// try to find the field by name in elements
		elems := node.Children[name]

		if elems == nil { // try to find the field in attributes
			if val, ok := node.findElem(name); ok {
				elems = []*XMLNode{{Text: val}}
			}
		}

		member := r.FieldByName(field.Name)
		for _, elem := range elems {
			err := parse(member, elem, field.Tag)
			if err != nil {
				return err
			}
		}
	}
	return nil
}

// parseList deserializes a list of values from an XML node. Each list entry
// will also be deserialized.
func parseList(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
	t := r.Type()

	if tag.Get("flattened") == "" { // look at all item entries
		mname := "member"
		if name := tag.Get("locationNameList"); name != "" {
			mname = name
		}

		if Children, ok := node.Children[mname]; ok {
			if r.IsNil() {
				r.Set(reflect.MakeSlice(t, len(Children), len(Children)))
			}

			for i, c := range Children {
				err := parse(r.Index(i), c, "")
				if err != nil {
					return err
				}
			}
		}
	} else { // flattened list means this is a single element
		if r.IsNil() {
			r.Set(reflect.MakeSlice(t, 0, 0))
		}

		childR := reflect.Zero(t.Elem())
		r.Set(reflect.Append(r, childR))
		err := parse(r.Index(r.Len()-1), node, "")
		if err != nil {
			return err
		}
	}

	return nil
}

// parseMap deserializes a map from an XMLNode. The direct children of the XMLNode
// will also be deserialized as map entries.
func parseMap(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
	if r.IsNil() {
		r.Set(reflect.MakeMap(r.Type()))
	}

	if tag.Get("flattened") == "" { // look at all child entries
		for _, entry := range node.Children["entry"] {
			parseMapEntry(r, entry, tag)
		}
	} else { // this element is itself an entry
		parseMapEntry(r, node, tag)
	}

	return nil
}

// parseMapEntry deserializes a map entry from a XML node.
func parseMapEntry(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
	kname, vname := "key", "value"
	if n := tag.Get("locationNameKey"); n != "" {
		kname = n
	}
	if n := tag.Get("locationNameValue"); n != "" {
		vname = n
	}

	keys, ok := node.Children[kname]
	values := node.Children[vname]
	if ok {
		for i, key := range keys {
			keyR := reflect.ValueOf(key.Text)
			value := values[i]
			valueR := reflect.New(r.Type().Elem()).Elem()

			parse(valueR, value, "")
			r.SetMapIndex(keyR, valueR)
		}
	}
	return nil
}

// parseScaller deserializes an XMLNode value into a concrete type based on the
// interface type of r.
//
// Error is returned if the deserialization fails due to invalid type conversion,
// or unsupported interface type.
func parseScalar(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
	switch r.Interface().(type) {
	case *string:
		r.Set(reflect.ValueOf(&node.Text))
		return nil
	case []byte:
		b, err := base64.StdEncoding.DecodeString(node.Text)
		if err != nil {
			return err
		}
		r.Set(reflect.ValueOf(b))
	case *bool:
		v, err := strconv.ParseBool(node.Text)
		if err != nil {
			return err
		}
		r.Set(reflect.ValueOf(&v))
	case *int64:
		v, err := strconv.ParseInt(node.Text, 10, 64)
		if err != nil {
			return err
		}
		r.Set(reflect.ValueOf(&v))
	case *float64:
		v, err := strconv.ParseFloat(node.Text, 64)
		if err != nil {
			return err
		}
		r.Set(reflect.ValueOf(&v))
	case *time.Time:
		const ISO8601UTC = "2006-01-02T15:04:05Z"
		t, err := time.Parse(ISO8601UTC, node.Text)
		if err != nil {
			return err
		}
		r.Set(reflect.ValueOf(&t))
	default:
		return fmt.Errorf("unsupported value: %v (%s)", r.Interface(), r.Type())
	}
	return nil
}
<|endoftext|>


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

package lxdclient

import (
	"github.com/juju/errors"
)

const (
	remoteLocalName   = "local"
	remoteDefaultName = remoteLocalName

	// TODO(ericsnow) This may be changing to "local"
	remoteIDForLocal = ""
)

// Local is LXD's default "remote". Essentially it is an unencrypted,
// unauthenticated connection to localhost over a unix socket.
var Local = Remote{
	RemoteInfo: RemoteInfo{
		Name: remoteLocalName,
	},
}

// TODO(ericsnow) Fold RemoteInfo into Remote.

// RemoteInfo describes a LXD "remote" server for a client. In
// particular it holds the information needed for the client
// to connect to the remote.
type RemoteInfo struct {
	// Name is a label for this remote.
	Name string

	// Host identifies the host to which the client should connect.
	// An empty string is interpreted as:
	//   "localhost over a unix socket (unencrypted)".
	Host string

	// Cert holds the TLS certificate data for the client to use.
	Cert *Cert
}

// SetDefaults updates a copy of the remote with default values
// where needed.
func (ri RemoteInfo) SetDefaults() (RemoteInfo, error) {
	if ri.Host == "" {
		return ri.setLocalDefaults(), nil
	}

	if ri.Cert == nil {
		certPEM, keyPEM, err := genCertAndKey()
		if err != nil {
			return ri, errors.Trace(err)
		}
		ri.Cert = NewCert(certPEM, keyPEM)
	}

	return ri, nil
}

func (ri RemoteInfo) setLocalDefaults() RemoteInfo {
	if ri.Name == "" {
		ri.Name = remoteLocalName
	}

	// TODO(ericsnow) Set ri.Cert to nil?

	return ri
}

// Validate checks the RemoteInfo fields for invalid values.
func (ri RemoteInfo) Validate() error {
	if ri.Name == "" {
		return errors.NotValidf("remote missing name,")
	}

	if ri.Host == "" {
		if err := ri.validateLocal(); err != nil {
			return errors.Trace(err)
		}
		return nil
	}

	// TODO(ericsnow) Ensure the host is a valid hostname or address?

	if ri.Cert == nil {
		return errors.NotValidf("remote without cert")
	} else if err := ri.Cert.Validate(); err != nil {
		return errors.Trace(err)
	}

	return nil
}

func (ri RemoteInfo) validateLocal() error {
	if ri.Cert != nil {
		return errors.NotValidf("hostless remote with cert")
	}

	return nil
}

// Remote represents a single LXD remote server.
type Remote struct {
	RemoteInfo
}

// NewRemote builds a new Remote from the provided info.
func NewRemote(info RemoteInfo) Remote {
	return Remote{
		RemoteInfo: info,
	}
}

// setDefaults updates a copy of the remote with default values
// where needed.
func (r Remote) setDefaults() (Remote, error) {
	info, err := r.RemoteInfo.SetDefaults()
	if err != nil {
		return r, errors.Trace(err)
	}
	r.RemoteInfo = info

	return r, nil
}

// ID identifies the remote to the raw LXD client code.
func (r Remote) ID() string {
	if r.RemoteInfo.Host == "" {
		return remoteIDForLocal
	}
	return r.RemoteInfo.Name
}

// Cert returns the certificate the client should use.
func (r Remote) Cert() Cert {
	if r.RemoteInfo.Cert == nil {
		return Cert{}
	}
	return *r.RemoteInfo.Cert
}

// TODO(ericsnow) Add a "Connect(Config)" method that connects
// to the remote and returns the corresponding Client.

// TODO(ericsnow) Add a "Register" method to Client that adds the remote
// to the client's remote?
<commit_msg>Compare against Local.Host for the implicit local unix socket.<commit_after>// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package lxdclient

import (
	"github.com/juju/errors"
)

const (
	remoteLocalName   = "local"
	remoteDefaultName = remoteLocalName

	// TODO(ericsnow) This may be changing to "local"
	remoteIDForLocal = ""
)

// Local is LXD's default "remote". Essentially it is an unencrypted,
// unauthenticated connection to localhost over a unix socket.
var Local = Remote{
	RemoteInfo: RemoteInfo{
		Name: remoteLocalName,
		Host: "", // The LXD API turns this into the local unix socket.
	},
}

// TODO(ericsnow) Fold RemoteInfo into Remote.

// RemoteInfo describes a LXD "remote" server for a client. In
// particular it holds the information needed for the client
// to connect to the remote.
type RemoteInfo struct {
	// Name is a label for this remote.
	Name string

	// Host identifies the host to which the client should connect.
	// An empty string is interpreted as:
	//   "localhost over a unix socket (unencrypted)".
	Host string

	// Cert holds the TLS certificate data for the client to use.
	Cert *Cert
}

// SetDefaults updates a copy of the remote with default values
// where needed.
func (ri RemoteInfo) SetDefaults() (RemoteInfo, error) {
	if ri.Host == Local.Host {
		return ri.setLocalDefaults(), nil
	}

	if ri.Cert == nil {
		certPEM, keyPEM, err := genCertAndKey()
		if err != nil {
			return ri, errors.Trace(err)
		}
		ri.Cert = NewCert(certPEM, keyPEM)
	}

	return ri, nil
}

func (ri RemoteInfo) setLocalDefaults() RemoteInfo {
	if ri.Name == "" {
		ri.Name = remoteLocalName
	}

	// TODO(ericsnow) Set ri.Cert to nil?

	return ri
}

// Validate checks the RemoteInfo fields for invalid values.
func (ri RemoteInfo) Validate() error {
	if ri.Name == "" {
		return errors.NotValidf("remote missing name,")
	}

	if ri.Host == Local.Host {
		if err := ri.validateLocal(); err != nil {
			return errors.Trace(err)
		}
		return nil
	}

	// TODO(ericsnow) Ensure the host is a valid hostname or address?

	if ri.Cert == nil {
		return errors.NotValidf("remote without cert")
	} else if err := ri.Cert.Validate(); err != nil {
		return errors.Trace(err)
	}

	return nil
}

func (ri RemoteInfo) validateLocal() error {
	if ri.Cert != nil {
		return errors.NotValidf("hostless remote with cert")
	}

	return nil
}

// Remote represents a single LXD remote server.
type Remote struct {
	RemoteInfo
}

// NewRemote builds a new Remote from the provided info.
func NewRemote(info RemoteInfo) Remote {
	return Remote{
		RemoteInfo: info,
	}
}

// setDefaults updates a copy of the remote with default values
// where needed.
func (r Remote) setDefaults() (Remote, error) {
	info, err := r.RemoteInfo.SetDefaults()
	if err != nil {
		return r, errors.Trace(err)
	}
	r.RemoteInfo = info

	return r, nil
}

// ID identifies the remote to the raw LXD client code.
func (r Remote) ID() string {
	if r.RemoteInfo.Host == Local.Host {
		return remoteIDForLocal
	}
	return r.RemoteInfo.Name
}

// Cert returns the certificate the client should use.
func (r Remote) Cert() Cert {
	if r.RemoteInfo.Cert == nil {
		return Cert{}
	}
	return *r.RemoteInfo.Cert
}

// TODO(ericsnow) Add a "Connect(Config)" method that connects
// to the remote and returns the corresponding Client.

// TODO(ericsnow) Add a "Register" method to Client that adds the remote
// to the client's remote?
<|endoftext|>


<commit_before>package bots

type CommandAction func(WebhookContext) (MessageFromBot, error)

type CommandMatcher func(Command, WebhookContext) bool

const DEFAULT_TITLE = ""
const SHORT_TITLE = "short_title"

//const LONG_TITLE = "long_title"

type Command struct {
	InputType  WebhookInputType // Instant match if != WebhookInputUnknown && == whc.InputType()
	Icon       string
	Replies    []Command
	Code       string
	Title      string
	Titles     map[string]string
	ExactMatch string
	Commands   []string
	Matcher    CommandMatcher
	Action     CommandAction
}

func (whcb *WebhookContextBase) CommandText(title, icon string) string {
	title = whcb.Translate(title)
	return CommandTextNoTrans(title, icon)
}

func CommandTextNoTrans(title, icon string) string {
	if title == "" && icon != "" {
		return icon
	} else if title != "" && icon == "" {
		return title
	} else if title != "" && icon != "" {
		return title + " " + icon
	} else {
		return "<NO_TITLE_OR_ICON>"
	}
}

func (c Command) DefaultTitle(whc WebhookContext) string {
	return c.TitleByKey(DEFAULT_TITLE, whc)
}

func (c Command) TitleByKey(key string, whc WebhookContext) string {
	var title string
	if key == DEFAULT_TITLE && c.Title != "" {
		title = c.Title
	} else if val, ok := c.Titles[key]; ok {
		title = val
	}

	if c.Icon == "" {
		if title == "" {
			title = c.Code
		} else {
			title = whc.Translate(title)
		}
	} else {
		if title == "" {
			title = CommandTextNoTrans("", c.Icon)
		} else {
			title = whc.CommandText(title, c.Icon)
		}
	}
	return title
}
<commit_msg>Locale switch changed<commit_after>package bots

import "fmt"

type CommandAction func(WebhookContext) (MessageFromBot, error)

type CommandMatcher func(Command, WebhookContext) bool

const DEFAULT_TITLE = ""
const SHORT_TITLE = "short_title"

//const LONG_TITLE = "long_title"

type Command struct {
	InputType  WebhookInputType // Instant match if != WebhookInputUnknown && == whc.InputType()
	Icon       string
	Replies    []Command
	Code       string
	Title      string
	Titles     map[string]string
	ExactMatch string
	Commands   []string
	Matcher    CommandMatcher
	Action     CommandAction
}

func (c Command) String() string {
	return fmt.Sprintf("Command{Code: '%v', InputType: %v, Icon: '%v', Title: '%v', ExactMatch: '%v', len(Command): %v, len(Replies): %v}", c.Code, c.InputType, c.Icon, c.Title, c.ExactMatch, len(c.Commands), len(c.Replies))
}

func (whcb *WebhookContextBase) CommandText(title, icon string) string {
	title = whcb.Translate(title)
	return CommandTextNoTrans(title, icon)
}

func CommandTextNoTrans(title, icon string) string {
	if title == "" && icon != "" {
		return icon
	} else if title != "" && icon == "" {
		return title
	} else if title != "" && icon != "" {
		return title + " " + icon
	} else {
		return "<NO_TITLE_OR_ICON>"
	}
}

func (c Command) DefaultTitle(whc WebhookContext) string {
	return c.TitleByKey(DEFAULT_TITLE, whc)
}

func (c Command) TitleByKey(key string, whc WebhookContext) string {
	var title string
	if key == DEFAULT_TITLE && c.Title != "" {
		title = c.Title
	} else if val, ok := c.Titles[key]; ok {
		title = val
	}

	if c.Icon == "" {
		if title == "" {
			title = c.Code
		} else {
			title = whc.Translate(title)
		}
	} else {
		if title == "" {
			title = CommandTextNoTrans("", c.Icon)
		} else {
			title = whc.CommandText(title, c.Icon)
		}
	}
	return title
}
<|endoftext|>


<commit_before>package server

import _ "embed" // Necessary to use go:embed

// Standard Secure Boot certificates (DER encoded)
var (
	//go:embed secure-boot/GcePk.crt
	GceDefaultPKCert []byte
	//go:embed secure-boot/MicCorKEKCA2011_2011-06-24.crt
	MicrosoftKEKCA2011Cert []byte
	//go:embed secure-boot/MicWinProPCA2011_2011-10-19.crt
	WindowsProductionPCA2011Cert []byte
	//go:embed secure-boot/MicCorUEFCA2011_2011-06-27.crt
	MicrosoftUEFICA2011Cert []byte
)

// Revoked Signing certificates (DER encoded)
var (
	//go:embed secure-boot/canonical-boothole.crt
	RevokedCanonicalBootholeCert []byte
	//go:embed secure-boot/debian-boothole.crt
	RevokedDebianBootholeCert []byte
	//go:embed secure-boot/cisco-boothole.crt
	RevokedCiscoCert []byte
)
<commit_msg>server: Add policy helper constants<commit_after>package server

import _ "embed" // Necessary to use go:embed

// Expected Firmware/PCR0 Event Types.
//
// Taken from TCG PC Client Platform Firmware Profile Specification,
// Table 14 Events.
const (
	NoAction     uint32 = 0x00000003
	Separator    uint32 = 0x00000004
	SCRTMVersion uint32 = 0x00000008
	NonhostInfo  uint32 = 0x00000011
)

var (
	// GCENonHostInfoSignature identifies the GCE Non-Host info event, which
	// indicates if memory encryption is enabled. This event is 32-bytes consisting
	// of the below signature (16 bytes), followed by a byte indicating whether
	// it is confidential, followed by 15 reserved bytes.
	GCENonHostInfoSignature = []byte("GCE NonHostInfo\x00")
)

// Standard Secure Boot certificates (DER encoded)
var (
	//go:embed secure-boot/GcePk.crt
	GceDefaultPKCert []byte
	//go:embed secure-boot/MicCorKEKCA2011_2011-06-24.crt
	MicrosoftKEKCA2011Cert []byte
	//go:embed secure-boot/MicWinProPCA2011_2011-10-19.crt
	WindowsProductionPCA2011Cert []byte
	//go:embed secure-boot/MicCorUEFCA2011_2011-06-27.crt
	MicrosoftUEFICA2011Cert []byte
)

// Revoked Signing certificates (DER encoded)
var (
	//go:embed secure-boot/canonical-boothole.crt
	RevokedCanonicalBootholeCert []byte
	//go:embed secure-boot/debian-boothole.crt
	RevokedDebianBootholeCert []byte
	//go:embed secure-boot/cisco-boothole.crt
	RevokedCiscoCert []byte
)
<|endoftext|>