<commit_before>// problem68.go
//
// What is the maximum 16-digit string for a 'magic' 5-gon ring?

package main

import (
	"euler/tools"
	"fmt"
	"strings"
)

// Ring represents a solution to the 5-gon ring problem.
type Ring []int

// This solution is much less efficient than the one found in the Python
// project dir. There, we created candidate solutions incrementally, allowing
// us to 'exit early' i.e. discount many permutations that are not worth
// considering. It's not quite as convenient to do the same in Go, so we simply
// brute-force check all the factorial(10) permutations.
func problem68() string {
	const start = 6   // Each line cannot sum to less than 6 (1+2+3)
	const end = 27    // or greater than 27 (8+9+10)
	const strlen = 16 // Specified in the problem description.
	var max string
	xs := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
	perms := tools.Permutations(xs, 10)

	for n := start; n <= end; n++ {
		for _, p := range perms {
			a, b, c, d, e := p[0], p[1], p[2], p[3], p[4]
			f, g, h, i, j := p[5], p[6], p[7], p[8], p[9]
			// Test whether this permutation conforms to the summation rules.
			if (a+b+c != n) || (d+c+e != n) || (f+e+g) != n || (h+g+i) != n || (j+i+b) != n {
				continue
			}
			// Each solution can be described uniquely starting from the group of three
			// with the numerically lowest external node and working clockwise.
			// So we specify that a < min(d, f, h, j)
			if a < tools.Min(d, f, h, j) {
				solution := (Ring{
					// As shown in the summation test above, the
					// 5-gon ring is represented as this pattern:
					// {a b c} {d c e} {f e g} {h g i} {j i b}
					// The problem asks for it flattened into one string.
					a, b, c, d, c, e, f, e, g, h, g, i, j, i, b,
				})
				s := strings.Join(tools.IntsToStrings(solution), "")
				if s > max && len(s) == strlen {
					max = s
				}
			}
		}
	}
	return max
}

func main() {
	ans := problem68()
	fmt.Println(ans)
}
<commit_msg>Remove superfluous parens<commit_after>// problem68.go
//
// What is the maximum 16-digit string for a 'magic' 5-gon ring?

package main

import (
	"euler/tools"
	"fmt"
	"strings"
)

// Ring represents a solution to the 5-gon ring problem.
type Ring []int

// This solution is much less efficient than the one found in the Python
// project dir. There, we created candidate solutions incrementally, allowing
// us to 'exit early' i.e. discount many permutations that are not worth
// considering. It's not quite as convenient to do the same in Go, so we simply
// brute-force check all the factorial(10) permutations.
func problem68() string {
	const start = 6   // Each line cannot sum to less than 6 (1+2+3)
	const end = 27    // or greater than 27 (8+9+10)
	const strlen = 16 // Specified in the problem description.
	var max string
	xs := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
	perms := tools.Permutations(xs, 10)

	for n := start; n <= end; n++ {
		for _, p := range perms {
			a, b, c, d, e := p[0], p[1], p[2], p[3], p[4]
			f, g, h, i, j := p[5], p[6], p[7], p[8], p[9]
			// Test whether this permutation conforms to the summation rules.
			if (a+b+c != n) || (d+c+e != n) || (f+e+g) != n || (h+g+i) != n || (j+i+b) != n {
				continue
			}
			// Each solution can be described uniquely starting from the group of three
			// with the numerically lowest external node and working clockwise.
			// So we specify that a < min(d, f, h, j)
			if a < tools.Min(d, f, h, j) {
				solution := Ring{
					// As shown in the summation test above, the
					// 5-gon ring is represented as this pattern:
					// {a b c} {d c e} {f e g} {h g i} {j i b}
					// The problem asks for it flattened into one string.
					a, b, c, d, c, e, f, e, g, h, g, i, j, i, b,
				}
				s := strings.Join(tools.IntsToStrings(solution), "")
				if s > max && len(s) == strlen {
					max = s
				}
			}
		}
	}
	return max
}

func main() {
	ans := problem68()
	fmt.Println(ans)
}
<|endoftext|>


<commit_before>// Copyright 2017 Istio 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 dot provides serialization utilities for a servicegraph using the
// dot format.
package dot

import (
	"bytes"
	"fmt"
	"io"
	"strings"
	"text/template"

	"istio.io/mixer/example/servicegraph"
)

var htmlTmpl = `<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Tiny example</title>
  </head>
  <body>

    <script src="/js/viz/viz-lite.js"></script>

    <script type="text/graphviz" id="cluster">
{{.}}
    </script>

    <script>

    document.body.innerHTML += Viz(document.getElementById("cluster").innerHTML, "svg");

    </script>

  </body>
</html>`

var charReplacer = strings.NewReplacer("/", "_", ".", "_", " ", "_")

// GenerateRaw writes out a dot graph in text form.
func GenerateRaw(w io.Writer, g *servicegraph.Dynamic) error {
	return generateDot(w, g)
}

// GenerateHTML writes out HTML that will visually display a graph based
// on a js rendering of dot.
func GenerateHTML(w io.Writer, g *servicegraph.Dynamic) error {
	var dotBuf bytes.Buffer
	if err := generateDot(&dotBuf, g); err != nil {
		return err
	}
	tmpl, err := template.New("html").Parse(htmlTmpl)
	if err != nil {
		return err
	}
	return tmpl.Execute(w, dotBuf.String())
}

func generateDot(w io.Writer, g *servicegraph.Dynamic) error {
	var dotBuffer bytes.Buffer
	if _, err := dotBuffer.WriteString("digraph \"istio-servicegraph\" {\n"); err != nil {
		return err
	}
	for _, e := range g.Edges {
		label := labelStr(e.Labels)
		if _, err := dotBuffer.WriteString(fmt.Sprintf("%s -> %s [label=\"%s\"];\n", idStr(e.Source), idStr(e.Target), label)); err != nil {
			return err
		}
	}
	for n := range g.Nodes {
		if _, err := dotBuffer.WriteString(fmt.Sprintf("%s [label=\"%s\"];\n", idStr(n), n)); err != nil {
			return err
		}
	}
	if _, err := dotBuffer.WriteString("}\n"); err != nil {
		return err
	}
	_, err := w.Write(dotBuffer.Bytes())
	return err
}

func idStr(s string) string {
	return charReplacer.Replace(s)
}

func labelStr(m map[string]string) string {
	var labelBuf bytes.Buffer
	for k, v := range m {
		labelBuf.WriteString(fmt.Sprintf("%s: %s, ", k, v))
	}
	return strings.TrimRight(labelBuf.String(), ", ")
}
<commit_msg>Update dot generation to double-quote node names (#883)<commit_after>// Copyright 2017 Istio 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 dot provides serialization utilities for a servicegraph using the
// dot format.
package dot

import (
	"bytes"
	"fmt"
	"io"
	"strings"
	"text/template"

	"istio.io/mixer/example/servicegraph"
)

var htmlTmpl = `<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Tiny example</title>
  </head>
  <body>

    <script src="/js/viz/viz-lite.js"></script>

    <script type="text/graphviz" id="cluster">
{{.}}
    </script>

    <script>

    document.body.innerHTML += Viz(document.getElementById("cluster").innerHTML, "svg");

    </script>

  </body>
</html>`

var charReplacer = strings.NewReplacer("/", "_", ".", "_", " ", "_")

// GenerateRaw writes out a dot graph in text form.
func GenerateRaw(w io.Writer, g *servicegraph.Dynamic) error {
	return generateDot(w, g)
}

// GenerateHTML writes out HTML that will visually display a graph based
// on a js rendering of dot.
func GenerateHTML(w io.Writer, g *servicegraph.Dynamic) error {
	var dotBuf bytes.Buffer
	if err := generateDot(&dotBuf, g); err != nil {
		return err
	}
	tmpl, err := template.New("html").Parse(htmlTmpl)
	if err != nil {
		return err
	}
	return tmpl.Execute(w, dotBuf.String())
}

func generateDot(w io.Writer, g *servicegraph.Dynamic) error {
	var dotBuffer bytes.Buffer
	if _, err := dotBuffer.WriteString("digraph \"istio-servicegraph\" {\n"); err != nil {
		return err
	}
	for _, e := range g.Edges {
		label := labelStr(e.Labels)
		if _, err := dotBuffer.WriteString(fmt.Sprintf("%q -> %q [label=%q];\n", idStr(e.Source), idStr(e.Target), label)); err != nil {
			return err
		}
	}
	for n := range g.Nodes {
		if _, err := dotBuffer.WriteString(fmt.Sprintf("%q [label=%q];\n", idStr(n), n)); err != nil {
			return err
		}
	}
	if _, err := dotBuffer.WriteString("}\n"); err != nil {
		return err
	}
	_, err := w.Write(dotBuffer.Bytes())
	return err
}

func idStr(s string) string {
	return charReplacer.Replace(s)
}

func labelStr(m map[string]string) string {
	var labelBuf bytes.Buffer
	for k, v := range m {
		labelBuf.WriteString(fmt.Sprintf("%s: %s, ", k, v))
	}
	return strings.TrimRight(labelBuf.String(), ", ")
}
<|endoftext|>


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

package tao

import (
	"io"
	"os"
	"path"

	"code.google.com/p/gcfg"

	"cloudproxy/tao/auth"
	"cloudproxy/util"
)

// Domain manages domain-wide authorization policies and configuration for a
// single Tao administrative domain. Configuration includes a name, domain guard
// type, ACLs or other guard-specific policy data, and a key pair for signing
// policy data.
//
// Except for a password used to encrypt the policy private key, top-level
// configuration data for Domain is stored in a text file, typically named
// "tao.config". This configuration file contains the locations of all other
// files and directories, e.g. configuration files for the domain guard. File
// and directory paths within the tao.config file are relative to the location
// of the tao.config file itself.
type Domain struct {
	Config     DomainConfig
	ConfigPath string
	Keys       *Keys
	Guard      Guard
}

// DomainConfig holds the presistent configuration data for a domain.
type DomainConfig struct {

	// Policy-agnostic configuration
	Domain struct {
		// Name of the domain
		Name string
		// Path to the password-protected signing key
		PolicyKeysPath string
		// Type of guard to use for domain-wide policy decisions
		GuardType string
	}

	// Details used for the domain signing key x509 certificate
	X509Details X509Details

	// Policy-specific configuration (optional)
	// ACLGuard ACLGuardConfig

	// Policy-specific configuration (optional)
	DatalogGuard DatalogGuardConfig
}

// Print prints the configuration to out.
func (cfg DomainConfig) Print(out io.Writer) error {
	return util.PrintAsGitConfig(out, cfg, "Tao Domain Configuration file")
}

// SetDefaults sets each blank field of cfg to a reasonable default value.
func (cfg *DomainConfig) SetDefaults() {
	if cfg.Domain.Name == "" {
		cfg.Domain.Name = "Tao example domain"
	}
	if cfg.Domain.PolicyKeysPath == "" {
		cfg.Domain.PolicyKeysPath = "policy_keys"
	}
	if cfg.Domain.GuardType == "" {
		cfg.Domain.GuardType = "DenyAll"
	}
	if cfg.X509Details.CommonName == "" {
		cfg.X509Details.CommonName = cfg.Domain.Name
	}
	switch cfg.Domain.GuardType {
	case "ACLs":
		//(&cfg.ACLGuard).SetDefaults()
	case "Datalog":
		//(&cfg.DatalogGuard).SetDefaults()
	}
}

// String returns the name of the domain.
func (d *Domain) String() string {
	return d.Config.Domain.Name
}

// Subprincipal returns a subprincipal suitable for contextualizing a program.
func (d *Domain) Subprincipal() auth.SubPrin {
	e := auth.PrinExt{
		Name: "Domain",
		Arg: []auth.Term{
			d.Keys.VerifyingKey.ToPrincipal(),
			auth.Str(d.Config.Domain.GuardType),
		},
	}
	return auth.SubPrin{e}
}

// CreateDomain initializes a new Domain, writing its configuration files to
// a directory. This creates the directory if needed, creates a policy key pair
// (encrypted with the given password when stored on disk), and initializes a
// default guard of the appropriate type if needed. Any parameters left empty in
// cfg will be set to reasonable default values.
func CreateDomain(cfg DomainConfig, configPath string, password []byte) (*Domain, error) {
	(&cfg).SetDefaults()

	configDir := path.Dir(configPath)
	err := os.MkdirAll(configDir, 0777)
	if err != nil {
		return nil, err
	}

	keypath := path.Join(configDir, cfg.Domain.PolicyKeysPath)
	keys, err := NewOnDiskPBEKeys(Signing, password, keypath, NewX509Name(cfg.X509Details))
	if err != nil {
		return nil, err
	}

	var guard Guard
	switch cfg.Domain.GuardType {
	case "ACLs":
		return nil, newError("acl guard not yet implemented")
	case "Datalog":
		return nil, newError("datalog guard not yet implemented")
	case "AllowAll":
		guard = LiberalGuard
	case "DenyAll":
		guard = ConservativeGuard
	default:
		return nil, newError("unrecognized guard type: %s", cfg.Domain.GuardType)
	}

	d := &Domain{cfg, configPath, keys, guard}
	err = d.Save()
	if err != nil {
		return nil, err
	}
	return d, nil
}

// Save writes all domain configuration and policy data.
func (d *Domain) Save() error {
	file, err := util.CreatePath(d.ConfigPath, 0777, 0666)
	if err != nil {
		return err
	}
	d.Config.Print(file)
	file.Close()
	return d.Guard.Save(d.Keys.SigningKey)
}

// LoadDomain initialize a Domain from an existing configuration file. If
// password is nil, the object will be "locked", meaning that the policy private
// signing key will not be available, new ACL entries or attestations can not be
// signed, etc. Otherwise, password will be used to unlock the policy private
// signing key.
func LoadDomain(configPath string, password []byte) (*Domain, error) {
	var cfg DomainConfig
	err := gcfg.ReadFileInto(&cfg, configPath)
	if err != nil {
		return nil, err
	}

	keys, err := NewOnDiskPBEKeys(Signing, password, cfg.Domain.PolicyKeysPath, nil)
	if err != nil {
		return nil, err
	}

	var guard Guard
	switch cfg.Domain.GuardType {
	case "ACLs":
		return nil, newError("acl guard not yet implemented")
	case "Datalog":
		return nil, newError("datalog guard not yet implemented")
	case "AllowAll":
		guard = LiberalGuard
	case "DenyAll":
		guard = ConservativeGuard
	}

	return &Domain{cfg, configPath, keys, guard}, nil
}
<commit_msg>Add ACLGuard support to Domain<commit_after>// Copyright (c) 2014, Kevin Walsh.  All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package tao

import (
	"io"
	"os"
	"path"

	"code.google.com/p/gcfg"

	"cloudproxy/tao/auth"
	"cloudproxy/util"
)

// Domain manages domain-wide authorization policies and configuration for a
// single Tao administrative domain. Configuration includes a name, domain guard
// type, ACLs or other guard-specific policy data, and a key pair for signing
// policy data.
//
// Except for a password used to encrypt the policy private key, top-level
// configuration data for Domain is stored in a text file, typically named
// "tao.config". This configuration file contains the locations of all other
// files and directories, e.g. configuration files for the domain guard. File
// and directory paths within the tao.config file are relative to the location
// of the tao.config file itself.
type Domain struct {
	Config     DomainConfig
	ConfigPath string
	Keys       *Keys
	Guard      Guard
}

// DomainConfig holds the presistent configuration data for a domain.
type DomainConfig struct {

	// Policy-agnostic configuration
	Domain struct {
		// Name of the domain
		Name string
		// Path to the password-protected signing key
		PolicyKeysPath string
		// Type of guard to use for domain-wide policy decisions
		GuardType string
	}

	// Details used for the domain signing key x509 certificate
	X509Details X509Details

	// Policy-specific configuration (optional)
	ACLGuard ACLGuardConfig

	// Policy-specific configuration (optional)
	DatalogGuard DatalogGuardConfig
}

// Print prints the configuration to out.
func (cfg DomainConfig) Print(out io.Writer) error {
	return util.PrintAsGitConfig(out, cfg, "Tao Domain Configuration file")
}

// SetDefaults sets each blank field of cfg to a reasonable default value.
func (cfg *DomainConfig) SetDefaults() {
	if cfg.Domain.Name == "" {
		cfg.Domain.Name = "Tao example domain"
	}
	if cfg.Domain.PolicyKeysPath == "" {
		cfg.Domain.PolicyKeysPath = "policy_keys"
	}
	if cfg.Domain.GuardType == "" {
		cfg.Domain.GuardType = "DenyAll"
	}
	if cfg.X509Details.CommonName == "" {
		cfg.X509Details.CommonName = cfg.Domain.Name
	}
	// TODO(tmroeder): should this be here? There are currently no reasonable
	// defaults for ACLGuardConfig, since it consists solely of the path to the
	// signed rules file.
	switch cfg.Domain.GuardType {
	case "Datalog":
		//(&cfg.DatalogGuard).SetDefaults()
	}
}

// String returns the name of the domain.
func (d *Domain) String() string {
	return d.Config.Domain.Name
}

// Subprincipal returns a subprincipal suitable for contextualizing a program.
func (d *Domain) Subprincipal() auth.SubPrin {
	e := auth.PrinExt{
		Name: "Domain",
		Arg: []auth.Term{
			d.Keys.VerifyingKey.ToPrincipal(),
			auth.Str(d.Config.Domain.GuardType),
		},
	}
	return auth.SubPrin{e}
}

// CreateDomain initializes a new Domain, writing its configuration files to
// a directory. This creates the directory if needed, creates a policy key pair
// (encrypted with the given password when stored on disk), and initializes a
// default guard of the appropriate type if needed. Any parameters left empty in
// cfg will be set to reasonable default values.
func CreateDomain(cfg DomainConfig, configPath string, password []byte) (*Domain, error) {
	(&cfg).SetDefaults()

	configDir := path.Dir(configPath)
	err := os.MkdirAll(configDir, 0777)
	if err != nil {
		return nil, err
	}

	keypath := path.Join(configDir, cfg.Domain.PolicyKeysPath)
	keys, err := NewOnDiskPBEKeys(Signing, password, keypath, NewX509Name(cfg.X509Details))
	if err != nil {
		return nil, err
	}

	var guard Guard
	switch cfg.Domain.GuardType {
	case "ACLs":
		guard = NewACLGuard(cfg.ACLGuard)
	case "Datalog":
		return nil, newError("datalog guard not yet implemented")
	case "AllowAll":
		guard = LiberalGuard
	case "DenyAll":
		guard = ConservativeGuard
	default:
		return nil, newError("unrecognized guard type: %s", cfg.Domain.GuardType)
	}

	d := &Domain{cfg, configPath, keys, guard}
	err = d.Save()
	if err != nil {
		return nil, err
	}
	return d, nil
}

// Save writes all domain configuration and policy data.
func (d *Domain) Save() error {
	file, err := util.CreatePath(d.ConfigPath, 0777, 0666)
	if err != nil {
		return err
	}
	d.Config.Print(file)
	file.Close()
	return d.Guard.Save(d.Keys.SigningKey)
}

// LoadDomain initialize a Domain from an existing configuration file. If
// password is nil, the object will be "locked", meaning that the policy private
// signing key will not be available, new ACL entries or attestations can not be
// signed, etc. Otherwise, password will be used to unlock the policy private
// signing key.
func LoadDomain(configPath string, password []byte) (*Domain, error) {
	var cfg DomainConfig
	err := gcfg.ReadFileInto(&cfg, configPath)
	if err != nil {
		return nil, err
	}

	keys, err := NewOnDiskPBEKeys(Signing, password, cfg.Domain.PolicyKeysPath, nil)
	if err != nil {
		return nil, err
	}

	var guard Guard
	switch cfg.Domain.GuardType {
	case "ACLs":
		var err error
		guard, err = LoadACLGuard(keys.VerifyingKey, cfg.ACLGuard)
		if err != nil {
			return nil, err
		}
	case "Datalog":
		return nil, newError("datalog guard not yet implemented")
	case "AllowAll":
		guard = LiberalGuard
	case "DenyAll":
		guard = ConservativeGuard
	}

	return &Domain{cfg, configPath, keys, guard}, nil
}
<|endoftext|>


<commit_before>package api

import (
	"fmt"
	"github.com/nais/naisd/api/app"
	v1 "k8s.io/api/core/v1"
	k8sextensions "k8s.io/api/extensions/v1beta1"
	k8smeta "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/intstr"
	"k8s.io/client-go/kubernetes"
)

const (
	defaultRedisPort          = 6379
	defaultRedisExporterPort  = 9121
	defaultRedisExporterImage = "oliver006/redis_exporter:v1.0.3-alpine"
	defaultRedisImage         = "redis:5-alpine"
)

type Redis struct {
	Enabled  bool
	Image    string
	Limits   ResourceList
	Requests ResourceList
}

func updateDefaultRedisValues(redis Redis) Redis {
	if redis.Image == "" {
		redis.Image = defaultRedisImage
	}
	if len(redis.Limits.Cpu) == 0 {
		redis.Limits.Cpu = "100m"
	}
	if len(redis.Limits.Memory) == 0 {
		redis.Limits.Memory = "128Mi"
	}
	if len(redis.Requests.Cpu) == 0 {
		redis.Requests.Cpu = "100m"
	}
	if len(redis.Requests.Memory) == 0 {
		redis.Requests.Memory = "128Mi"
	}
	return redis
}

func createRedisPodSpec(redis Redis) v1.PodSpec {
	return v1.PodSpec{
		Containers: []v1.Container{
			{
				Name:  "redis",
				Image: redis.Image,
				Resources: createResourceLimits(redis.Requests.Cpu, redis.Requests.Memory,
					redis.Limits.Cpu, redis.Limits.Memory),
				ImagePullPolicy: v1.PullIfNotPresent,
				Ports: []v1.ContainerPort{
					{
						ContainerPort: int32(defaultRedisPort),
						Name:          DefaultPortName,
						Protocol:      v1.ProtocolTCP,
					},
				},
			},
			{
				Name:  "exporter",
				Image: defaultRedisExporterImage,
				Resources: createResourceLimits("100m", "100Mi",
					"100m", "100Mi"),
				ImagePullPolicy: v1.PullIfNotPresent,
				Ports: []v1.ContainerPort{
					{
						ContainerPort: int32(defaultRedisExporterPort),
						Name:          DefaultPortName,
						Protocol:      v1.ProtocolTCP,
					},
				},
			},
		},
	}
}

func createRedisDeploymentSpec(resourceName string, spec app.Spec, redis Redis) k8sextensions.DeploymentSpec {
	objectMeta := generateObjectMeta(spec)
	objectMeta.Name = resourceName
	objectMeta.Annotations = map[string]string{
		"prometheus.io/scrape": "true",
		"prometheus.io/port":   string(defaultRedisExporterPort),
		"prometheus.io/path":   "/metrics",
	}

	return k8sextensions.DeploymentSpec{
		Replicas: int32p(1),
		Selector: &k8smeta.LabelSelector{
			MatchLabels: createPodSelector(spec),
		},
		Strategy: k8sextensions.DeploymentStrategy{
			Type: k8sextensions.RecreateDeploymentStrategyType,
		},
		ProgressDeadlineSeconds: int32p(300),
		RevisionHistoryLimit:    int32p(10),
		Template: v1.PodTemplateSpec{
			ObjectMeta: objectMeta,
			Spec:       createRedisPodSpec(redis),
		},
	}
}

func createRedisDeploymentDef(resourceName string, spec app.Spec, redis Redis, existingDeployment *k8sextensions.Deployment) *k8sextensions.Deployment {
	existingDeployment.Spec = createRedisDeploymentSpec(resourceName, spec, redis)
	return existingDeployment
}

func createOrUpdateRedisInstance(spec app.Spec, redis Redis, k8sClient kubernetes.Interface) (*k8sextensions.Deployment, error) {
	redisName := fmt.Sprintf("%s-redis", spec.ResourceName())
	existingDeployment, err := getExistingDeployment(redisName, spec.Namespace, k8sClient)

	if err != nil {
		return nil, fmt.Errorf("unable to get existing deployment: %s", err)
	}

	deploymentDef := createRedisDeploymentDef(redisName, spec, redis, existingDeployment)
	deploymentDef.Name = fmt.Sprintf("%s-redis", spec.ResourceName())

	return createOrUpdateDeploymentResource(deploymentDef, spec.Namespace, k8sClient)
}

func createRedisServiceDef(spec app.Spec) *v1.Service {
	return &v1.Service{
		TypeMeta: k8smeta.TypeMeta{
			Kind:       "Service",
			APIVersion: "v1",
		},
		ObjectMeta: generateObjectMeta(spec),
		Spec: v1.ServiceSpec{
			Type:     v1.ServiceTypeClusterIP,
			Selector: createPodSelector(spec),
			Ports: []v1.ServicePort{
				{
					Name:     DefaultPortName,
					Protocol: v1.ProtocolTCP,
					Port:     6379,
					TargetPort: intstr.IntOrString{
						Type:   intstr.String,
						StrVal: DefaultPortName,
					},
				},
			},
		},
	}
}

func createOrUpdateRedisService(spec app.Spec, k8sClient kubernetes.Interface) (*v1.Service, error) {
	redisName := fmt.Sprintf("%s-redis", spec.ResourceName())
	service, err := getExistingService(redisName, spec.Namespace, k8sClient)

	if err != nil {
		return nil, fmt.Errorf("unable to get existing service: %s", err)
	} else if service == nil {
		service = createRedisServiceDef(spec)
		service.Name = redisName
	}

	service.ObjectMeta = addLabelsToObjectMeta(service.ObjectMeta, spec)
	return createOrUpdateServiceResource(service, spec.Namespace, k8sClient)
}
<commit_msg>Tok ikke høyde for at ressurs ikke fantes<commit_after>package api

import (
	"fmt"
	"github.com/nais/naisd/api/app"
	v1 "k8s.io/api/core/v1"
	k8sextensions "k8s.io/api/extensions/v1beta1"
	k8smeta "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/intstr"
	"k8s.io/client-go/kubernetes"
)

const (
	defaultRedisPort          = 6379
	defaultRedisExporterPort  = 9121
	defaultRedisExporterImage = "oliver006/redis_exporter:v1.0.3-alpine"
	defaultRedisImage         = "redis:5-alpine"
)

type Redis struct {
	Enabled  bool
	Image    string
	Limits   ResourceList
	Requests ResourceList
}

func updateDefaultRedisValues(redis Redis) Redis {
	if redis.Image == "" {
		redis.Image = defaultRedisImage
	}
	if len(redis.Limits.Cpu) == 0 {
		redis.Limits.Cpu = "100m"
	}
	if len(redis.Limits.Memory) == 0 {
		redis.Limits.Memory = "128Mi"
	}
	if len(redis.Requests.Cpu) == 0 {
		redis.Requests.Cpu = "100m"
	}
	if len(redis.Requests.Memory) == 0 {
		redis.Requests.Memory = "128Mi"
	}
	return redis
}

func createRedisPodSpec(redis Redis) v1.PodSpec {
	return v1.PodSpec{
		Containers: []v1.Container{
			{
				Name:  "redis",
				Image: redis.Image,
				Resources: createResourceLimits(redis.Requests.Cpu, redis.Requests.Memory,
					redis.Limits.Cpu, redis.Limits.Memory),
				ImagePullPolicy: v1.PullIfNotPresent,
				Ports: []v1.ContainerPort{
					{
						ContainerPort: int32(defaultRedisPort),
						Name:          DefaultPortName,
						Protocol:      v1.ProtocolTCP,
					},
				},
			},
			{
				Name:  "exporter",
				Image: defaultRedisExporterImage,
				Resources: createResourceLimits("100m", "100Mi",
					"100m", "100Mi"),
				ImagePullPolicy: v1.PullIfNotPresent,
				Ports: []v1.ContainerPort{
					{
						ContainerPort: int32(defaultRedisExporterPort),
						Name:          DefaultPortName,
						Protocol:      v1.ProtocolTCP,
					},
				},
			},
		},
	}
}

func createRedisDeploymentSpec(resourceName string, spec app.Spec, redis Redis) k8sextensions.DeploymentSpec {
	objectMeta := generateObjectMeta(spec)
	objectMeta.Name = resourceName
	objectMeta.Annotations = map[string]string{
		"prometheus.io/scrape": "true",
		"prometheus.io/port":   string(defaultRedisExporterPort),
		"prometheus.io/path":   "/metrics",
	}

	return k8sextensions.DeploymentSpec{
		Replicas: int32p(1),
		Selector: &k8smeta.LabelSelector{
			MatchLabels: createPodSelector(spec),
		},
		Strategy: k8sextensions.DeploymentStrategy{
			Type: k8sextensions.RecreateDeploymentStrategyType,
		},
		ProgressDeadlineSeconds: int32p(300),
		RevisionHistoryLimit:    int32p(10),
		Template: v1.PodTemplateSpec{
			ObjectMeta: objectMeta,
			Spec:       createRedisPodSpec(redis),
		},
	}
}

func createRedisDeploymentDef(resourceName string, spec app.Spec, redis Redis, existingDeployment *k8sextensions.Deployment) *k8sextensions.Deployment {
	deploymentSpec := createRedisDeploymentSpec(resourceName, spec, redis)
	if existingDeployment != nil {
		existingDeployment.ObjectMeta = addLabelsToObjectMeta(existingDeployment.ObjectMeta, spec)
		existingDeployment.Spec = deploymentSpec
		return existingDeployment
	} else {
		return &k8sextensions.Deployment{
			TypeMeta: k8smeta.TypeMeta{
				Kind:       "Deployment",
				APIVersion: "apps/v1beta1",
			},
			ObjectMeta: generateObjectMeta(spec),
			Spec:       deploymentSpec,
		}
	}
}

func createOrUpdateRedisInstance(spec app.Spec, redis Redis, k8sClient kubernetes.Interface) (*k8sextensions.Deployment, error) {
	redisName := fmt.Sprintf("%s-redis", spec.ResourceName())
	existingDeployment, err := getExistingDeployment(redisName, spec.Namespace, k8sClient)

	if err != nil {
		return nil, fmt.Errorf("unable to get existing deployment: %s", err)
	}

	deploymentDef := createRedisDeploymentDef(redisName, spec, redis, existingDeployment)
	deploymentDef.Name = fmt.Sprintf("%s-redis", spec.ResourceName())

	return createOrUpdateDeploymentResource(deploymentDef, spec.Namespace, k8sClient)
}

func createRedisServiceDef(spec app.Spec) *v1.Service {
	return &v1.Service{
		TypeMeta: k8smeta.TypeMeta{
			Kind:       "Service",
			APIVersion: "v1",
		},
		ObjectMeta: generateObjectMeta(spec),
		Spec: v1.ServiceSpec{
			Type:     v1.ServiceTypeClusterIP,
			Selector: createPodSelector(spec),
			Ports: []v1.ServicePort{
				{
					Name:     DefaultPortName,
					Protocol: v1.ProtocolTCP,
					Port:     6379,
					TargetPort: intstr.IntOrString{
						Type:   intstr.String,
						StrVal: DefaultPortName,
					},
				},
			},
		},
	}
}

func createOrUpdateRedisService(spec app.Spec, k8sClient kubernetes.Interface) (*v1.Service, error) {
	redisName := fmt.Sprintf("%s-redis", spec.ResourceName())
	service, err := getExistingService(redisName, spec.Namespace, k8sClient)

	if err != nil {
		return nil, fmt.Errorf("unable to get existing service: %s", err)
	} else if service == nil {
		service = createRedisServiceDef(spec)
		service.Name = redisName
	}

	service.ObjectMeta = addLabelsToObjectMeta(service.ObjectMeta, spec)
	return createOrUpdateServiceResource(service, spec.Namespace, k8sClient)
}
<|endoftext|>


<commit_before>package frontend

import (
	"database/sql"
	"fmt"
	"html/template"
	"net"
	"net/http"
	"net/http/fcgi"
	"os"
	"sort"
	"strings"
	"time"

	"github.com/kvu787/goschedule/goschedule/shared"
	"github.com/kvu787/goschedule/lib"
)

var appDb *sql.DB
var switchDatabase *sql.DB
var conn string

func Serve(connString string, switchDb *sql.DB, local bool, frontendRoot string, port int) error {
	conn = connString
	switchDatabase = switchDb
	if err := os.Chdir(os.ExpandEnv(frontendRoot)); err != nil {
		fmt.Println(err)
		return err
	}
	if local {
		http.HandleFunc("/", router)
		if err := http.ListenAndServe(fmt.Sprintf(":%d", port), nil); err != nil {
			fmt.Println(err)
			return err
		}
	} else {
		listener, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", port))
		if err != nil {
			return err
		}
		http.HandleFunc("/", router)
		if err := fcgi.Serve(listener, nil); err != nil {
			return err
		}
	}
	return nil
}

var routing = [][]interface{}{
	{"/", indexHandler},
	{"/test_ajax", ajaxHandler},
	{"/schedule", deptsHandler},
	{"/schedule/:dept", classesHandler},
	{"/schedule/:dept/:class", sectsHandler},
	{"/assets/:type/:file", assetHandler},
}

type routeHandler func(http.ResponseWriter, *http.Request, map[string]string)

func router(w http.ResponseWriter, r *http.Request) {
	// determine application db
	appNum, err := shared.GetSwitch(switchDatabase)
	if err != nil {
		panic(fmt.Sprintf("Failed to query switch database for app db number in frontend.router: %v", err))
	}
	appDb, err = sql.Open("postgres", fmt.Sprintf(conn, appNum))
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	defer appDb.Close()
	// process request
	path := r.URL.Path
	var matched bool
	for _, tuple := range routing {
		handler := tuple[1].(func(http.ResponseWriter, *http.Request, map[string]string))
		if ro := route(tuple[0].(string)); ro.match(path) {
			handler(w, r, ro.parse(path))
			matched = true
		}
	}
	if !matched {
		fmt.Fprintf(w, "No route matched for:\n%q", r.URL.Path)
	}
}

func ajaxHandler(w http.ResponseWriter, r *http.Request, params map[string]string) {
	w.Header().Set("Content-Type", "text/javascript; charset=utf-8")
	fmt.Fprintf(w, `alert('works!');`)
}

// CREDIT: http://stackoverflow.com/questions/11467731/is-it-possible-to-have-nested-templates-in-go-using-the-standard-library-googl
func indexHandler(w http.ResponseWriter, r *http.Request, params map[string]string) {
	t := template.Must(template.ParseFiles(
		"templates/index.html",
		"templates/base.html",
	))
	t.ExecuteTemplate(w, "base", nil)
}

func deptsHandler(w http.ResponseWriter, r *http.Request, params map[string]string) {
	var data = make(map[string][]goschedule.Dept)
	// get colleges
	collegeRecords, err := goschedule.Select(appDb, goschedule.College{}, "ORDER BY abbreviation")
	if err != nil {
		panic(err)
	}
	var collegeNames []string
	var collegesNamesToAbbreviations = make(map[string]string)
	for _, v := range collegeRecords {
		college := v.(goschedule.College)
		// create list of college names
		collegeNames = append(collegeNames, college.Name)
		// create map of college names to abbreviations
		collegesNamesToAbbreviations[college.Name] = college.Abbreviation
	}
	for _, collegeName := range collegeNames {
		// get depts
		deptRecords, err := goschedule.Select(appDb, goschedule.Dept{}, fmt.Sprintf("WHERE collegekey = '%s'", collegesNamesToAbbreviations[collegeName]))
		if err != nil {
			panic(err)
		}
		// create map of college names to depts
		for _, v := range deptRecords {
			data[collegeName] = append(data[collegeName], v.(goschedule.Dept))
		}
	}
	t := template.Must(template.New("").Funcs(template.FuncMap{
		"title": strings.Title,
		"upper": strings.ToUpper,
	}).ParseFiles(
		"templates/depts.html",
		"templates/base.html",
	))
	// sort slice of college names
	sort.Strings(collegeNames)
	viewBag := map[string]interface{}{
		"collegeNames":         collegeNames,
		"collegeAbbreviations": collegesNamesToAbbreviations,
		"collegesMap":          data,
	}
	t.ExecuteTemplate(w, "base", viewBag)
}

func classesHandler(w http.ResponseWriter, r *http.Request, params map[string]string) {
	classRecords, err := goschedule.Select(appDb, goschedule.Class{}, fmt.Sprintf("WHERE deptkey = '%s' ORDER BY code", params["dept"]))
	if err != nil {
		panic(err)
	}
	var classes []goschedule.Class
	for _, v := range classRecords {
		classes = append(classes, v.(goschedule.Class))
	}
	t := template.Must(template.New("").Funcs(template.FuncMap{
		"title": strings.Title,
		"upper": strings.ToUpper,
	}).ParseFiles(
		"templates/classes.html",
		"templates/base.html",
	))
	viewBag := map[string]interface{}{
		"classes": classes,
		"dept":    params["dept"],
	}
	t.ExecuteTemplate(w, "base", viewBag)
}

func sectsHandler(w http.ResponseWriter, r *http.Request, params map[string]string) {
	dept := strings.Split(strings.ToLower(r.URL.Path), "/")[2]
	class := strings.Split(strings.ToLower(r.URL.Path), "/")[3]
	sectRecords, err := goschedule.Select(appDb, goschedule.Sect{}, fmt.Sprintf("WHERE classkey = '%s' ORDER BY section", class))
	if err != nil {
		panic(err)
	}
	var sects []goschedule.Sect
	for _, v := range sectRecords {
		sects = append(sects, v.(goschedule.Sect))
	}
	t := template.Must(template.New("").Funcs(template.FuncMap{
		"upper": strings.ToUpper,
		"lower": strings.ToLower,
	}).ParseFiles(
		"templates/sects.html",
		"templates/base.html",
	))
	viewBag := make(map[string]interface{})
	viewBag["dept"] = dept
	viewBag["class"] = class
	viewBag["sects"] = sects
	t.ExecuteTemplate(w, "base", viewBag)
}

func assetHandler(w http.ResponseWriter, r *http.Request, params map[string]string) {
	filePath := fmt.Sprintf("assets/%s/%s", params["type"], params["file"])
	staticFile, err := os.Open(filePath)
	if err != nil {
		fmt.Fprintf(w, "404, file not found error: %v", err.Error())
	} else {
		http.ServeContent(w, r, params["file"], time.Now(), staticFile)
	}
}
<commit_msg>bugfix: frontend using wrong db<commit_after>package frontend

import (
	"database/sql"
	"fmt"
	"html/template"
	"net"
	"net/http"
	"net/http/fcgi"
	"os"
	"sort"
	"strings"
	"time"

	"github.com/kvu787/goschedule/goschedule/shared"
	"github.com/kvu787/goschedule/lib"
)

var appDb *sql.DB
var switchDatabase *sql.DB
var conn string

func Serve(connString string, switchDb *sql.DB, local bool, frontendRoot string, port int) error {
	conn = connString
	switchDatabase = switchDb
	if err := os.Chdir(os.ExpandEnv(frontendRoot)); err != nil {
		return err
	}
	if local {
		http.HandleFunc("/", router)
		if err := http.ListenAndServe(fmt.Sprintf(":%d", port), nil); err != nil {
			return err
		}
	} else {
		listener, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", port))
		if err != nil {
			return err
		}
		http.HandleFunc("/", router)
		if err := fcgi.Serve(listener, nil); err != nil {
			return err
		}
	}
	return nil
}

var routing = [][]interface{}{
	{"/", indexHandler},
	{"/search", searchHandler},
	{"/schedule", deptsHandler},
	{"/schedule/:dept", classesHandler},
	{"/schedule/:dept/:class", sectsHandler},
	{"/assets/:type/:file", assetHandler},
}

type routeHandler func(http.ResponseWriter, *http.Request, map[string]string)

func router(w http.ResponseWriter, r *http.Request) {
	// determine application db
	appNum, err := shared.GetSwitch(switchDatabase)
	if err != nil {
		panic(fmt.Sprintf("Failed to query switch database for app db number in frontend.router: %v", err))
	}
	if appNum == 1 {
		appNum = 2
	} else {
		appNum = 1
	}
	appDb, err = sql.Open("postgres", fmt.Sprintf(conn, appNum))
	if err != nil {
		panic(err)
	}
	defer appDb.Close()
	// process request
	path := r.URL.Path
	var matched bool
	for _, tuple := range routing {
		handler := tuple[1].(func(http.ResponseWriter, *http.Request, map[string]string))
		if ro := route(tuple[0].(string)); ro.match(path) {
			handler(w, r, ro.parse(path))
			matched = true
		}
	}
	if !matched {
		fmt.Fprintf(w, "No route matched for:\n%q", r.URL.Path)
	}
}

func searchHandler(w http.ResponseWriter, r *http.Request, params map[string]string) {
	w.Header().Set("Content-Type", "text/javascript; charset=utf-8")
	fmt.Fprintf(w, `alert('works!');`)
}

// CREDIT: http://stackoverflow.com/questions/11467731/is-it-possible-to-have-nested-templates-in-go-using-the-standard-library-googl
func indexHandler(w http.ResponseWriter, r *http.Request, params map[string]string) {
	t := template.Must(template.ParseFiles(
		"templates/index.html",
		"templates/base.html",
	))
	t.ExecuteTemplate(w, "base", nil)
}

func deptsHandler(w http.ResponseWriter, r *http.Request, params map[string]string) {
	var data = make(map[string][]goschedule.Dept)
	// get colleges
	collegeRecords, err := goschedule.Select(appDb, goschedule.College{}, "ORDER BY abbreviation")
	if err != nil {
		panic(err)
	}
	var collegeNames []string
	var collegesNamesToAbbreviations = make(map[string]string)
	for _, v := range collegeRecords {
		college := v.(goschedule.College)
		// create list of college names
		collegeNames = append(collegeNames, college.Name)
		// create map of college names to abbreviations
		collegesNamesToAbbreviations[college.Name] = college.Abbreviation
	}
	for _, collegeName := range collegeNames {
		// get depts
		deptRecords, err := goschedule.Select(appDb, goschedule.Dept{}, fmt.Sprintf("WHERE collegekey = '%s'", collegesNamesToAbbreviations[collegeName]))
		if err != nil {
			panic(err)
		}
		// create map of college names to depts
		for _, v := range deptRecords {
			data[collegeName] = append(data[collegeName], v.(goschedule.Dept))
		}
	}
	t := template.Must(template.New("").Funcs(template.FuncMap{
		"title": strings.Title,
		"upper": strings.ToUpper,
	}).ParseFiles(
		"templates/depts.html",
		"templates/base.html",
	))
	// sort slice of college names
	sort.Strings(collegeNames)
	viewBag := map[string]interface{}{
		"collegeNames":         collegeNames,
		"collegeAbbreviations": collegesNamesToAbbreviations,
		"collegesMap":          data,
	}
	t.ExecuteTemplate(w, "base", viewBag)
}

func classesHandler(w http.ResponseWriter, r *http.Request, params map[string]string) {
	classRecords, err := goschedule.Select(appDb, goschedule.Class{}, fmt.Sprintf("WHERE deptkey = '%s' ORDER BY code", params["dept"]))
	if err != nil {
		panic(err)
	}
	var classes []goschedule.Class
	for _, v := range classRecords {
		classes = append(classes, v.(goschedule.Class))
	}
	t := template.Must(template.New("").Funcs(template.FuncMap{
		"title": strings.Title,
		"upper": strings.ToUpper,
	}).ParseFiles(
		"templates/classes.html",
		"templates/base.html",
	))
	viewBag := map[string]interface{}{
		"classes": classes,
		"dept":    params["dept"],
	}
	t.ExecuteTemplate(w, "base", viewBag)
}

func sectsHandler(w http.ResponseWriter, r *http.Request, params map[string]string) {
	dept := strings.Split(strings.ToLower(r.URL.Path), "/")[2]
	class := strings.Split(strings.ToLower(r.URL.Path), "/")[3]
	sectRecords, err := goschedule.Select(appDb, goschedule.Sect{}, fmt.Sprintf("WHERE classkey = '%s' ORDER BY section", class))
	if err != nil {
		panic(err)
	}
	var sects []goschedule.Sect
	for _, v := range sectRecords {
		sects = append(sects, v.(goschedule.Sect))
	}
	t := template.Must(template.New("").Funcs(template.FuncMap{
		"upper": strings.ToUpper,
		"lower": strings.ToLower,
	}).ParseFiles(
		"templates/sects.html",
		"templates/base.html",
	))
	viewBag := make(map[string]interface{})
	viewBag["dept"] = dept
	viewBag["class"] = class
	viewBag["sects"] = sects
	t.ExecuteTemplate(w, "base", viewBag)
}

func assetHandler(w http.ResponseWriter, r *http.Request, params map[string]string) {
	filePath := fmt.Sprintf("assets/%s/%s", params["type"], params["file"])
	staticFile, err := os.Open(filePath)
	if err != nil {
		fmt.Fprintf(w, "404, file not found error: %v", err.Error())
	} else {
		http.ServeContent(w, r, params["file"], time.Now(), staticFile)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/xml"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"strings"
)

// Structs for XML building
type Package struct {
	Xmlns   string     `xml:"xmlns,attr"`
	Types   []MetaType `xml:"types"`
	Version string     `xml:"version"`
}

type MetaType struct {
	Members []string `xml:"members"`
	Name    string   `xml:"name"`
}

func createPackage() Package {
	return Package{
		Version: strings.TrimPrefix(apiVersion, "v"),
		Xmlns:   "http://soap.sforce.com/2006/04/metadata",
	}
}

type metapath struct {
	path       string
	name       string
	hasFolder  bool
	onlyFolder bool
	extension  string
}

var metapaths = []metapath{
	metapath{path: "actionLinkGroupTemplates", name: "ActionLinkGroupTemplate"},
	metapath{path: "analyticSnapshots", name: "AnalyticSnapshot"},
	metapath{path: "applications", name: "CustomApplication"},
	metapath{path: "appMenus", name: "AppMenu"},
	metapath{path: "approvalProcesses", name: "ApprovalProcess"},
	metapath{path: "assignmentRules", name: "AssignmentRules"},
	metapath{path: "authproviders", name: "AuthProvider"},
	metapath{path: "aura", name: "AuraDefinitionBundle", hasFolder: true, onlyFolder: true},
	metapath{path: "autoResponseRules", name: "AutoResponseRules"},
	metapath{path: "callCenters", name: "CallCenter"},
	metapath{path: "cachePartitions", name: "PlatformCachePartition"},
	metapath{path: "certs", name: "Certificate"},
	metapath{path: "channelLayouts", name: "ChannelLayout"},
	metapath{path: "classes", name: "ApexClass"},
	metapath{path: "communities", name: "Community"},
	metapath{path: "components", name: "ApexComponent"},
	metapath{path: "connectedApps", name: "ConnectedApp"},
	metapath{path: "corsWhitelistOrigins", name: "CorsWhitelistOrigin"},
	metapath{path: "customApplicationComponents", name: "CustomApplicationComponent"},
	metapath{path: "customMetadata", name: "CustomMetadata"},
	metapath{path: "customPermissions", name: "CustomPermission"},
	metapath{path: "dashboards", name: "Dashboard", hasFolder: true},
	metapath{path: "dataSources", name: "ExternalDataSource"},
	metapath{path: "datacategorygroups", name: "DataCategoryGroup"},
	metapath{path: "delegateGroups", name: "DelegateGroup"},
	metapath{path: "documents", name: "Document", hasFolder: true},
	metapath{path: "EmbeddedServiceConfig", name: "EmbeddedServiceConfig"},
	metapath{path: "email", name: "EmailTemplate", hasFolder: true},
	metapath{path: "escalationRules", name: "EscalationRules"},
	metapath{path: "feedFilters", name: "CustomFeedFilter"},
	metapath{path: "flexipages", name: "FlexiPage"},
	metapath{path: "flowDefinitions", name: "FlowDefinition"},
	metapath{path: "flows", name: "Flow"},
	metapath{path: "globalPicklists", name: "GlobalPicklist"},
	metapath{path: "groups", name: "Group"},
	metapath{path: "homePageComponents", name: "HomePageComponent"},
	metapath{path: "homePageLayouts", name: "HomePageLayout"},
	metapath{path: "installedPackages", name: "InstalledPackage"},
	metapath{path: "labels", name: "CustomLabels"},
	metapath{path: "layouts", name: "Layout"},
	metapath{path: "LeadConvertSettings", name: "LeadConvertSettings"},
	metapath{path: "letterhead", name: "Letterhead"},
	metapath{path: "matchingRules", name: "MatchingRules"},
	metapath{path: "namedCredentials", name: "NamedCredential"},
	metapath{path: "objects", name: "CustomObject"},
	metapath{path: "objectTranslations", name: "CustomObjectTranslation"},
	metapath{path: "pages", name: "ApexPage"},
	metapath{path: "pathAssistants", name: "PathAssistant"},
	metapath{path: "permissionsets", name: "PermissionSet"},
	metapath{path: "postTemplates", name: "PostTemplate"},
	metapath{path: "profiles", name: "Profile", extension: ".profile"},
	metapath{path: "postTemplates", name: "PostTemplate"},
  metapath{path: "postTemplates", name: "PostTemplate"},
  metapath{path: "profiles", name: "Profile"},
	metapath{path: "queues", name: "Queue"},
	metapath{path: "quickActions", name: "QuickAction"},
	metapath{path: "remoteSiteSettings", name: "RemoteSiteSetting"},
	metapath{path: "reports", name: "Report", hasFolder: true},
	metapath{path: "reportTypes", name: "ReportType"},
	metapath{path: "roles", name: "Role"},
	metapath{path: "scontrols", name: "Scontrol"},
	metapath{path: "settings", name: "Settings"},
	metapath{path: "sharingRules", name: "SharingRules"},
	metapath{path: "siteDotComSites", name: "SiteDotCom"},
	metapath{path: "sites", name: "CustomSite"},
	metapath{path: "staticresources", name: "StaticResource"},
	metapath{path: "synonymDictionaries", name: "SynonymDictionary"},
	metapath{path: "tabs", name: "CustomTab"},
	metapath{path: "triggers", name: "ApexTrigger"},
	metapath{path: "weblinks", name: "CustomPageWebLink"},
	metapath{path: "workflows", name: "Workflow"},
}

type PackageBuilder struct {
	IsPush   bool
	Metadata map[string]MetaType
	Files    ForceMetadataFiles
}

func NewPushBuilder() PackageBuilder {
	pb := PackageBuilder{IsPush: true}
	pb.Metadata = make(map[string]MetaType)
	pb.Files = make(ForceMetadataFiles)

	return pb
}

func NewFetchBuilder() PackageBuilder {
	pb := PackageBuilder{IsPush: false}
	pb.Metadata = make(map[string]MetaType)
	pb.Files = make(ForceMetadataFiles)

	return pb
}

// Build and return package.xml
func (pb PackageBuilder) PackageXml() []byte {
	p := createPackage()

	for _, metaType := range pb.Metadata {
		p.Types = append(p.Types, metaType)
	}

	byteXml, _ := xml.MarshalIndent(p, "", "    ")
	byteXml = append([]byte(xml.Header), byteXml...)
	//if err := ioutil.WriteFile("mypackage.xml", byteXml, 0644); err != nil {
	//ErrorAndExit(err.Error())
	//}
	return byteXml
}

// Returns the full ForceMetadataFiles container
func (pb *PackageBuilder) ForceMetadataFiles() ForceMetadataFiles {
	pb.Files["package.xml"] = pb.PackageXml()
	return pb.Files
}

// Returns the source file path for a given metadata file path.
func MetaPathToSourcePath(mpath string) (spath string) {
	spath = strings.TrimSuffix(mpath, "-meta.xml")
	if spath == mpath {
		return
	}

	_, err := os.Stat(spath)
	if err != nil {
		spath = mpath
	}
	return
}

// Add a file to the builder
func (pb *PackageBuilder) AddFile(fpath string) (fname string, err error) {
	fpath, err = filepath.Abs(fpath)
	if err != nil {
		return
	}
	_, err = os.Stat(fpath)
	if err != nil {
		return
	}

	isDestructiveChanges, err := regexp.MatchString("destructiveChanges(Pre|Post)?"+regexp.QuoteMeta(".")+"xml", fpath)
	if err != nil {
		return
	}

	fpath = MetaPathToSourcePath(fpath)
	metaName, fname := getMetaTypeFromPath(fpath)
	if !isDestructiveChanges && !strings.HasSuffix(fpath, "-meta.xml") {
		pb.AddMetaToPackage(metaName, fname)
	}

	// If it's a push, we want to actually add the files
	if pb.IsPush {
		if isDestructiveChanges {
			err = pb.addDestructiveChanges(fpath)
		} else {
			err = pb.addFileToWorkingDir(metaName, fpath)
		}
	}

	return
}

// Adds the file to a temp directory for deploy
func (pb *PackageBuilder) addFileToWorkingDir(metaName string, fpath string) (err error) {
	// Get relative dir from source
	srcDir := filepath.Dir(filepath.Dir(fpath))
	for _, mp := range metapaths {
		if metaName == mp.name && mp.hasFolder {
			srcDir = filepath.Dir(srcDir)
		}
	}
	frel, _ := filepath.Rel(srcDir, fpath)

	// Try to find meta file
	hasMeta := true
	fmeta := fpath + "-meta.xml"
	fmetarel := ""
	if _, err = os.Stat(fmeta); err != nil {
		if os.IsNotExist(err) {
			hasMeta = false
		} else {
			// Has error
			return
		}
	} else {
		// Should be present since we worked back to srcDir
		fmetarel, _ = filepath.Rel(srcDir, fmeta)
	}

	fdata, err := ioutil.ReadFile(fpath)
	if err != nil {
		return
	}

	pb.Files[frel] = fdata
	if hasMeta {
		fdata, err = ioutil.ReadFile(fmeta)
		pb.Files[fmetarel] = fdata
		return
	}

	return
}

func (pb *PackageBuilder) addDestructiveChanges(fpath string) (err error) {
	fdata, err := ioutil.ReadFile(fpath)
	if err != nil {
		return
	}

	frel, _ := filepath.Rel(filepath.Dir(fpath), fpath)
	pb.Files[frel] = fdata

	return
}

func (pb *PackageBuilder) contains(members []string, name string) bool {
	for _, a := range members {
		if a == name {
			return true
		}
	}
	return false
}

// Adds a metadata name to the pending package
func (pb *PackageBuilder) AddMetaToPackage(metaName string, name string) {
	mt := pb.Metadata[metaName]
	if mt.Name == "" {
		mt.Name = metaName
	}

	if !pb.contains(mt.Members, name) {
		mt.Members = append(mt.Members, name)
		pb.Metadata[metaName] = mt
	}
}

// Gets metadata type name and target name from a file path
func getMetaTypeFromPath(fpath string) (metaName string, name string) {
	fpath, err := filepath.Abs(fpath)
	if err != nil {
		ErrorAndExit("Cound not find " + fpath)
	}
	if _, err := os.Stat(fpath); err != nil {
		ErrorAndExit("Cound not open " + fpath)
	}

	// Get the metadata type and name for the file
	metaName, fileName := getMetaForPath(fpath)
	name = strings.TrimSuffix(fileName, filepath.Ext(fileName))
	//name = strings.TrimSuffix(name, filepath.Ext(name))
	return
}

// Gets partial path based on a meta type name
func getPathForMeta(metaname string) string {
	for _, mp := range metapaths {
		if strings.EqualFold(mp.name, metaname) {
			return mp.path
		}
	}

	// Unknown, so use metaname
	return metaname
}

func findMetapathForFile(file string) (path metapath) {
	parentDir := filepath.Dir(file)
	parentName := filepath.Base(parentDir)
	grandparentName := filepath.Base(filepath.Dir(parentDir))
	fileExtension := filepath.Ext(file)

	for _, mp := range metapaths {
		if mp.hasFolder && grandparentName == mp.path {
			return mp
		}
		if mp.path == parentName {
			return mp
		}
	}

	// Hmm, maybe we can use the extension to determine the type
	for _, mp := range metapaths {
		if mp.extension == fileExtension {
			return mp
		}
	}
	return
}

// Gets meta type and name based on a path
func getMetaForPath(path string) (metaName string, objectName string) {
	parentDir := filepath.Dir(path)
	parentName := filepath.Base(parentDir)
	grandparentName := filepath.Base(filepath.Dir(parentDir))
	fileName := filepath.Base(path)

	for _, mp := range metapaths {
		if mp.hasFolder && grandparentName == mp.path {
			metaName = mp.name
			if mp.onlyFolder {
				objectName = parentName
			} else {
				objectName = parentName + "/" + fileName
			}
			return
		}
		if mp.path == parentName {
			metaName = mp.name
			objectName = fileName
			return
		}
	}

	// Unknown, so use path
	metaName = parentName
	objectName = fileName
	return
}
<commit_msg>go fmt<commit_after>package main

import (
	"encoding/xml"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"strings"
)

// Structs for XML building
type Package struct {
	Xmlns   string     `xml:"xmlns,attr"`
	Types   []MetaType `xml:"types"`
	Version string     `xml:"version"`
}

type MetaType struct {
	Members []string `xml:"members"`
	Name    string   `xml:"name"`
}

func createPackage() Package {
	return Package{
		Version: strings.TrimPrefix(apiVersion, "v"),
		Xmlns:   "http://soap.sforce.com/2006/04/metadata",
	}
}

type metapath struct {
	path       string
	name       string
	hasFolder  bool
	onlyFolder bool
	extension  string
}

var metapaths = []metapath{
	metapath{path: "actionLinkGroupTemplates", name: "ActionLinkGroupTemplate"},
	metapath{path: "analyticSnapshots", name: "AnalyticSnapshot"},
	metapath{path: "applications", name: "CustomApplication"},
	metapath{path: "appMenus", name: "AppMenu"},
	metapath{path: "approvalProcesses", name: "ApprovalProcess"},
	metapath{path: "assignmentRules", name: "AssignmentRules"},
	metapath{path: "authproviders", name: "AuthProvider"},
	metapath{path: "aura", name: "AuraDefinitionBundle", hasFolder: true, onlyFolder: true},
	metapath{path: "autoResponseRules", name: "AutoResponseRules"},
	metapath{path: "callCenters", name: "CallCenter"},
	metapath{path: "cachePartitions", name: "PlatformCachePartition"},
	metapath{path: "certs", name: "Certificate"},
	metapath{path: "channelLayouts", name: "ChannelLayout"},
	metapath{path: "classes", name: "ApexClass"},
	metapath{path: "communities", name: "Community"},
	metapath{path: "components", name: "ApexComponent"},
	metapath{path: "connectedApps", name: "ConnectedApp"},
	metapath{path: "corsWhitelistOrigins", name: "CorsWhitelistOrigin"},
	metapath{path: "customApplicationComponents", name: "CustomApplicationComponent"},
	metapath{path: "customMetadata", name: "CustomMetadata"},
	metapath{path: "customPermissions", name: "CustomPermission"},
	metapath{path: "dashboards", name: "Dashboard", hasFolder: true},
	metapath{path: "dataSources", name: "ExternalDataSource"},
	metapath{path: "datacategorygroups", name: "DataCategoryGroup"},
	metapath{path: "delegateGroups", name: "DelegateGroup"},
	metapath{path: "documents", name: "Document", hasFolder: true},
	metapath{path: "EmbeddedServiceConfig", name: "EmbeddedServiceConfig"},
	metapath{path: "email", name: "EmailTemplate", hasFolder: true},
	metapath{path: "escalationRules", name: "EscalationRules"},
	metapath{path: "feedFilters", name: "CustomFeedFilter"},
	metapath{path: "flexipages", name: "FlexiPage"},
	metapath{path: "flowDefinitions", name: "FlowDefinition"},
	metapath{path: "flows", name: "Flow"},
	metapath{path: "globalPicklists", name: "GlobalPicklist"},
	metapath{path: "groups", name: "Group"},
	metapath{path: "homePageComponents", name: "HomePageComponent"},
	metapath{path: "homePageLayouts", name: "HomePageLayout"},
	metapath{path: "installedPackages", name: "InstalledPackage"},
	metapath{path: "labels", name: "CustomLabels"},
	metapath{path: "layouts", name: "Layout"},
	metapath{path: "LeadConvertSettings", name: "LeadConvertSettings"},
	metapath{path: "letterhead", name: "Letterhead"},
	metapath{path: "matchingRules", name: "MatchingRules"},
	metapath{path: "namedCredentials", name: "NamedCredential"},
	metapath{path: "objects", name: "CustomObject"},
	metapath{path: "objectTranslations", name: "CustomObjectTranslation"},
	metapath{path: "pages", name: "ApexPage"},
	metapath{path: "pathAssistants", name: "PathAssistant"},
	metapath{path: "permissionsets", name: "PermissionSet"},
	metapath{path: "postTemplates", name: "PostTemplate"},
	metapath{path: "profiles", name: "Profile", extension: ".profile"},
	metapath{path: "postTemplates", name: "PostTemplate"},
	metapath{path: "postTemplates", name: "PostTemplate"},
	metapath{path: "profiles", name: "Profile"},
	metapath{path: "queues", name: "Queue"},
	metapath{path: "quickActions", name: "QuickAction"},
	metapath{path: "remoteSiteSettings", name: "RemoteSiteSetting"},
	metapath{path: "reports", name: "Report", hasFolder: true},
	metapath{path: "reportTypes", name: "ReportType"},
	metapath{path: "roles", name: "Role"},
	metapath{path: "scontrols", name: "Scontrol"},
	metapath{path: "settings", name: "Settings"},
	metapath{path: "sharingRules", name: "SharingRules"},
	metapath{path: "siteDotComSites", name: "SiteDotCom"},
	metapath{path: "sites", name: "CustomSite"},
	metapath{path: "staticresources", name: "StaticResource"},
	metapath{path: "synonymDictionaries", name: "SynonymDictionary"},
	metapath{path: "tabs", name: "CustomTab"},
	metapath{path: "triggers", name: "ApexTrigger"},
	metapath{path: "weblinks", name: "CustomPageWebLink"},
	metapath{path: "workflows", name: "Workflow"},
}

type PackageBuilder struct {
	IsPush   bool
	Metadata map[string]MetaType
	Files    ForceMetadataFiles
}

func NewPushBuilder() PackageBuilder {
	pb := PackageBuilder{IsPush: true}
	pb.Metadata = make(map[string]MetaType)
	pb.Files = make(ForceMetadataFiles)

	return pb
}

func NewFetchBuilder() PackageBuilder {
	pb := PackageBuilder{IsPush: false}
	pb.Metadata = make(map[string]MetaType)
	pb.Files = make(ForceMetadataFiles)

	return pb
}

// Build and return package.xml
func (pb PackageBuilder) PackageXml() []byte {
	p := createPackage()

	for _, metaType := range pb.Metadata {
		p.Types = append(p.Types, metaType)
	}

	byteXml, _ := xml.MarshalIndent(p, "", "    ")
	byteXml = append([]byte(xml.Header), byteXml...)
	//if err := ioutil.WriteFile("mypackage.xml", byteXml, 0644); err != nil {
	//ErrorAndExit(err.Error())
	//}
	return byteXml
}

// Returns the full ForceMetadataFiles container
func (pb *PackageBuilder) ForceMetadataFiles() ForceMetadataFiles {
	pb.Files["package.xml"] = pb.PackageXml()
	return pb.Files
}

// Returns the source file path for a given metadata file path.
func MetaPathToSourcePath(mpath string) (spath string) {
	spath = strings.TrimSuffix(mpath, "-meta.xml")
	if spath == mpath {
		return
	}

	_, err := os.Stat(spath)
	if err != nil {
		spath = mpath
	}
	return
}

// Add a file to the builder
func (pb *PackageBuilder) AddFile(fpath string) (fname string, err error) {
	fpath, err = filepath.Abs(fpath)
	if err != nil {
		return
	}
	_, err = os.Stat(fpath)
	if err != nil {
		return
	}

	isDestructiveChanges, err := regexp.MatchString("destructiveChanges(Pre|Post)?"+regexp.QuoteMeta(".")+"xml", fpath)
	if err != nil {
		return
	}

	fpath = MetaPathToSourcePath(fpath)
	metaName, fname := getMetaTypeFromPath(fpath)
	if !isDestructiveChanges && !strings.HasSuffix(fpath, "-meta.xml") {
		pb.AddMetaToPackage(metaName, fname)
	}

	// If it's a push, we want to actually add the files
	if pb.IsPush {
		if isDestructiveChanges {
			err = pb.addDestructiveChanges(fpath)
		} else {
			err = pb.addFileToWorkingDir(metaName, fpath)
		}
	}

	return
}

// Adds the file to a temp directory for deploy
func (pb *PackageBuilder) addFileToWorkingDir(metaName string, fpath string) (err error) {
	// Get relative dir from source
	srcDir := filepath.Dir(filepath.Dir(fpath))
	for _, mp := range metapaths {
		if metaName == mp.name && mp.hasFolder {
			srcDir = filepath.Dir(srcDir)
		}
	}
	frel, _ := filepath.Rel(srcDir, fpath)

	// Try to find meta file
	hasMeta := true
	fmeta := fpath + "-meta.xml"
	fmetarel := ""
	if _, err = os.Stat(fmeta); err != nil {
		if os.IsNotExist(err) {
			hasMeta = false
		} else {
			// Has error
			return
		}
	} else {
		// Should be present since we worked back to srcDir
		fmetarel, _ = filepath.Rel(srcDir, fmeta)
	}

	fdata, err := ioutil.ReadFile(fpath)
	if err != nil {
		return
	}

	pb.Files[frel] = fdata
	if hasMeta {
		fdata, err = ioutil.ReadFile(fmeta)
		pb.Files[fmetarel] = fdata
		return
	}

	return
}

func (pb *PackageBuilder) addDestructiveChanges(fpath string) (err error) {
	fdata, err := ioutil.ReadFile(fpath)
	if err != nil {
		return
	}

	frel, _ := filepath.Rel(filepath.Dir(fpath), fpath)
	pb.Files[frel] = fdata

	return
}

func (pb *PackageBuilder) contains(members []string, name string) bool {
	for _, a := range members {
		if a == name {
			return true
		}
	}
	return false
}

// Adds a metadata name to the pending package
func (pb *PackageBuilder) AddMetaToPackage(metaName string, name string) {
	mt := pb.Metadata[metaName]
	if mt.Name == "" {
		mt.Name = metaName
	}

	if !pb.contains(mt.Members, name) {
		mt.Members = append(mt.Members, name)
		pb.Metadata[metaName] = mt
	}
}

// Gets metadata type name and target name from a file path
func getMetaTypeFromPath(fpath string) (metaName string, name string) {
	fpath, err := filepath.Abs(fpath)
	if err != nil {
		ErrorAndExit("Cound not find " + fpath)
	}
	if _, err := os.Stat(fpath); err != nil {
		ErrorAndExit("Cound not open " + fpath)
	}

	// Get the metadata type and name for the file
	metaName, fileName := getMetaForPath(fpath)
	name = strings.TrimSuffix(fileName, filepath.Ext(fileName))
	//name = strings.TrimSuffix(name, filepath.Ext(name))
	return
}

// Gets partial path based on a meta type name
func getPathForMeta(metaname string) string {
	for _, mp := range metapaths {
		if strings.EqualFold(mp.name, metaname) {
			return mp.path
		}
	}

	// Unknown, so use metaname
	return metaname
}

func findMetapathForFile(file string) (path metapath) {
	parentDir := filepath.Dir(file)
	parentName := filepath.Base(parentDir)
	grandparentName := filepath.Base(filepath.Dir(parentDir))
	fileExtension := filepath.Ext(file)

	for _, mp := range metapaths {
		if mp.hasFolder && grandparentName == mp.path {
			return mp
		}
		if mp.path == parentName {
			return mp
		}
	}

	// Hmm, maybe we can use the extension to determine the type
	for _, mp := range metapaths {
		if mp.extension == fileExtension {
			return mp
		}
	}
	return
}

// Gets meta type and name based on a path
func getMetaForPath(path string) (metaName string, objectName string) {
	parentDir := filepath.Dir(path)
	parentName := filepath.Base(parentDir)
	grandparentName := filepath.Base(filepath.Dir(parentDir))
	fileName := filepath.Base(path)

	for _, mp := range metapaths {
		if mp.hasFolder && grandparentName == mp.path {
			metaName = mp.name
			if mp.onlyFolder {
				objectName = parentName
			} else {
				objectName = parentName + "/" + fileName
			}
			return
		}
		if mp.path == parentName {
			metaName = mp.name
			objectName = fileName
			return
		}
	}

	// Unknown, so use path
	metaName = parentName
	objectName = fileName
	return
}
<|endoftext|>


<commit_before>package packer

import (
	"encoding/json"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"sort"
	"strings"

	packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
	"github.com/hashicorp/packer-plugin-sdk/pathing"
	pluginsdk "github.com/hashicorp/packer-plugin-sdk/plugin"
)

// PluginConfig helps load and use packer plugins
type PluginConfig struct {
	KnownPluginFolders []string
	PluginMinPort      int
	PluginMaxPort      int
	Builders           BuilderSet
	Provisioners       ProvisionerSet
	PostProcessors     PostProcessorSet
	DataSources        DatasourceSet
}

// PACKERSPACE is used to represent the spaces that separate args for a command
// without being confused with spaces in the path to the command itself.
const PACKERSPACE = "-PACKERSPACE-"

// Discover discovers plugins.
//
// Search the directory of the executable, then the plugins directory, and
// finally the CWD, in that order. Any conflicts will overwrite previously
// found plugins, in that order.
// Hence, the priority order is the reverse of the search order - i.e., the
// CWD has the highest priority.
func (c *PluginConfig) Discover() error {
	if c.Builders == nil {
		c.Builders = MapOfBuilder{}
	}
	if c.Provisioners == nil {
		c.Provisioners = MapOfProvisioner{}
	}
	if c.PostProcessors == nil {
		c.PostProcessors = MapOfPostProcessor{}
	}
	if c.DataSources == nil {
		c.DataSources = MapOfDatasource{}
	}

	// If we are already inside a plugin process we should not need to
	// discover anything.
	if os.Getenv(pluginsdk.MagicCookieKey) == pluginsdk.MagicCookieValue {
		return nil
	}

	// TODO: use KnownPluginFolders here. TODO probably after JSON is deprecated
	// so that we can keep the current behavior just the way it is.

	// Next, look in the same directory as the executable.
	exePath, err := os.Executable()
	if err != nil {
		log.Printf("[ERR] Error loading exe directory: %s", err)
	} else {
		if err := c.discoverExternalComponents(filepath.Dir(exePath)); err != nil {
			return err
		}
	}

	// Next, look in the default plugins directory inside the configdir/.packer.d/plugins.
	dir, err := pathing.ConfigDir()
	if err != nil {
		log.Printf("[ERR] Error loading config directory: %s", err)
	} else {
		if err := c.discoverExternalComponents(filepath.Join(dir, "plugins")); err != nil {
			return err
		}
	}

	// Next, look in the CWD.
	if err := c.discoverExternalComponents("."); err != nil {
		return err
	}

	// Check whether there is a custom Plugin directory defined. This gets
	// absolute preference.
	if packerPluginPath := os.Getenv("PACKER_PLUGIN_PATH"); packerPluginPath != "" {
		sep := ":"
		if runtime.GOOS == "windows" {
			// on windows, PATH is semicolon-separated
			sep = ";"
		}
		plugPaths := strings.Split(packerPluginPath, sep)
		for _, plugPath := range plugPaths {
			if err := c.discoverExternalComponents(plugPath); err != nil {
				return err
			}
		}
	}

	return nil
}

func (c *PluginConfig) discoverExternalComponents(path string) error {
	var err error

	if !filepath.IsAbs(path) {
		path, err = filepath.Abs(path)
		if err != nil {
			return err
		}
	}
	var externallyUsed []string

	pluginPaths, err := c.discoverSingle(filepath.Join(path, "packer-builder-*"))
	if err != nil {
		return err
	}
	for pluginName, pluginPath := range pluginPaths {
		newPath := pluginPath // this needs to be stored in a new variable for the func below
		c.Builders.Set(pluginName, c.Client(newPath).Builder)
		externallyUsed = append(externallyUsed, pluginName)
	}
	if len(externallyUsed) > 0 {
		sort.Strings(externallyUsed)
		log.Printf("[INFO] using external builders: %v", externallyUsed)
		externallyUsed = nil
	}

	pluginPaths, err = c.discoverSingle(filepath.Join(path, "packer-post-processor-*"))
	if err != nil {
		return err
	}
	for pluginName, pluginPath := range pluginPaths {
		newPath := pluginPath // this needs to be stored in a new variable for the func below
		c.PostProcessors.Set(pluginName, c.Client(newPath).PostProcessor)
		externallyUsed = append(externallyUsed, pluginName)
	}
	if len(externallyUsed) > 0 {
		sort.Strings(externallyUsed)
		log.Printf("using external post-processors %v", externallyUsed)
		externallyUsed = nil
	}

	pluginPaths, err = c.discoverSingle(filepath.Join(path, "packer-provisioner-*"))
	if err != nil {
		return err
	}
	for pluginName, pluginPath := range pluginPaths {
		newPath := pluginPath // this needs to be stored in a new variable for the func below
		c.Provisioners.Set(pluginName, c.Client(newPath).Provisioner)
		externallyUsed = append(externallyUsed, pluginName)
	}
	if len(externallyUsed) > 0 {
		sort.Strings(externallyUsed)
		log.Printf("using external provisioners %v", externallyUsed)
	}

	pluginPaths, err = c.discoverSingle(filepath.Join(path, "packer-datasource-*"))
	if err != nil {
		return err
	}
	for pluginName, pluginPath := range pluginPaths {
		newPath := pluginPath // this needs to be stored in a new variable for the func below
		c.DataSources.Set(pluginName, c.Client(newPath).Datasource)
		externallyUsed = append(externallyUsed, pluginName)
	}
	if len(externallyUsed) > 0 {
		sort.Strings(externallyUsed)
		log.Printf("using external datasource %v", externallyUsed)
	}

	pluginPaths, err = c.discoverSingle(filepath.Join(path, "packer-plugin-*"))
	if err != nil {
		return err
	}

	for pluginName, pluginPath := range pluginPaths {
		if err := c.DiscoverMultiPlugin(pluginName, pluginPath); err != nil {
			return err
		}
	}

	return nil
}

func (c *PluginConfig) discoverSingle(glob string) (map[string]string, error) {
	matches, err := filepath.Glob(glob)
	if err != nil {
		return nil, err
	}

	res := make(map[string]string)

	prefix := filepath.Base(glob)
	prefix = prefix[:strings.Index(prefix, "*")]
	for _, match := range matches {
		file := filepath.Base(match)

		// skip folders like packer-plugin-sdk
		if stat, err := os.Stat(file); err == nil && stat.IsDir() {
			continue
		}

		// On Windows, ignore any plugins that don't end in .exe.
		// We could do a full PATHEXT parse, but this is probably good enough.
		if runtime.GOOS == "windows" && strings.ToLower(filepath.Ext(file)) != ".exe" {
			log.Printf(
				"[DEBUG] Ignoring plugin match %s, no exe extension",
				match)
			continue
		}

		// If the filename has a ".", trim up to there
		if idx := strings.Index(file, ".exe"); idx >= 0 {
			file = file[:idx]
		}

		// Look for foo-bar-baz. The plugin name is "baz"
		pluginName := file[len(prefix):]
		log.Printf("[DEBUG] Discovered plugin: %s = %s", pluginName, match)
		res[pluginName] = match
	}

	return res, nil
}

// DiscoverMultiPlugin takes the description from a multiplugin binary and
// makes the plugins available to use in Packer. Each plugin found in the
// binary will be addressable using `${pluginName}-${builderName}` for example.
// pluginName could be manually set. It usually is a cloud name like amazon.
// pluginName can be extrapolated from the filename of the binary; so
// if the "packer-plugin-amazon" binary had an "ebs" builder one could use
// the "amazon-ebs" builder.
func (c *PluginConfig) DiscoverMultiPlugin(pluginName, pluginPath string) error {
	out, err := exec.Command(pluginPath, "describe").Output()
	if err != nil {
		return err
	}
	var desc pluginsdk.SetDescription
	if err := json.Unmarshal(out, &desc); err != nil {
		return err
	}

	pluginPrefix := pluginName + "-"

	for _, builderName := range desc.Builders {
		builderName := builderName // copy to avoid pointer overwrite issue
		key := pluginPrefix + builderName
		if builderName == pluginsdk.DEFAULT_NAME {
			key = pluginName
		}
		c.Builders.Set(key, func() (packersdk.Builder, error) {
			return c.Client(pluginPath, "start", "builder", builderName).Builder()
		})
	}

	if len(desc.Builders) > 0 {
		log.Printf("[INFO] found external %v builders from %s plugin", desc.Builders, pluginName)
	}

	for _, postProcessorName := range desc.PostProcessors {
		postProcessorName := postProcessorName // copy to avoid pointer overwrite issue
		key := pluginPrefix + postProcessorName
		if postProcessorName == pluginsdk.DEFAULT_NAME {
			key = pluginName
		}
		c.PostProcessors.Set(key, func() (packersdk.PostProcessor, error) {
			return c.Client(pluginPath, "start", "post-processor", postProcessorName).PostProcessor()
		})
	}

	if len(desc.PostProcessors) > 0 {
		log.Printf("[INFO] found external %v post-processors from %s plugin", desc.PostProcessors, pluginName)
	}

	for _, provisionerName := range desc.Provisioners {
		provisionerName := provisionerName // copy to avoid pointer overwrite issue
		key := pluginPrefix + provisionerName
		if provisionerName == pluginsdk.DEFAULT_NAME {
			key = pluginName
		}
		c.Provisioners.Set(key, func() (packersdk.Provisioner, error) {
			return c.Client(pluginPath, "start", "provisioner", provisionerName).Provisioner()
		})
	}
	if len(desc.Provisioners) > 0 {
		log.Printf("found external %v provisioner from %s plugin", desc.Provisioners, pluginName)
	}

	for _, datasourceName := range desc.Datasources {
		datasourceName := datasourceName // copy to avoid pointer overwrite issue
		c.DataSources.Set(pluginPrefix+datasourceName, func() (packersdk.Datasource, error) {
			return c.Client(pluginPath, "start", "datasource", datasourceName).Datasource()
		})
	}
	if len(desc.Datasources) > 0 {
		log.Printf("found external %v datasource from %s plugin", desc.Datasources, pluginName)
	}

	return nil
}

func (c *PluginConfig) Client(path string, args ...string) *PluginClient {
	originalPath := path

	// Check for special case using `packer plugin PLUGIN`
	if strings.Contains(path, PACKERSPACE) {
		parts := strings.Split(path, PACKERSPACE)
		path = parts[0]
		args = parts[1:]
	}

	// First attempt to find the executable by consulting the PATH.
	path, err := exec.LookPath(path)
	if err != nil {
		// If that doesn't work, look for it in the same directory
		// as the `packer` executable (us).
		log.Printf("[INFO] exec.LookPath: %s : %v. Checking same directory as executable.", path, err)
		exePath, err := os.Executable()
		if err != nil {
			log.Printf("Couldn't get current exe path: %s", err)
		} else {
			log.Printf("Current exe path: %s", exePath)
			path = filepath.Join(filepath.Dir(exePath), filepath.Base(originalPath))
		}
	}

	// If everything failed, just use the original path and let the error
	// bubble through.
	if path == "" {
		path = originalPath
	}

	if strings.Contains(originalPath, PACKERSPACE) {
		log.Printf("[TRACE] Starting internal plugin %s", args[len(args)-1])
	} else {
		log.Printf("[TRACE] Starting external plugin %s %s", path, strings.Join(args, " "))
	}
	var config PluginClientConfig
	config.Cmd = exec.Command(path, args...)
	config.Managed = true
	config.MinPort = c.PluginMinPort
	config.MaxPort = c.PluginMaxPort
	return NewClient(&config)
}
<commit_msg>Fix issue when loading single plugin type<commit_after>package packer

import (
	"encoding/json"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"sort"
	"strings"

	packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
	"github.com/hashicorp/packer-plugin-sdk/pathing"
	pluginsdk "github.com/hashicorp/packer-plugin-sdk/plugin"
)

// PluginConfig helps load and use packer plugins
type PluginConfig struct {
	KnownPluginFolders []string
	PluginMinPort      int
	PluginMaxPort      int
	Builders           BuilderSet
	Provisioners       ProvisionerSet
	PostProcessors     PostProcessorSet
	DataSources        DatasourceSet
}

// PACKERSPACE is used to represent the spaces that separate args for a command
// without being confused with spaces in the path to the command itself.
const PACKERSPACE = "-PACKERSPACE-"

// Discover discovers plugins.
//
// Search the directory of the executable, then the plugins directory, and
// finally the CWD, in that order. Any conflicts will overwrite previously
// found plugins, in that order.
// Hence, the priority order is the reverse of the search order - i.e., the
// CWD has the highest priority.
func (c *PluginConfig) Discover() error {
	if c.Builders == nil {
		c.Builders = MapOfBuilder{}
	}
	if c.Provisioners == nil {
		c.Provisioners = MapOfProvisioner{}
	}
	if c.PostProcessors == nil {
		c.PostProcessors = MapOfPostProcessor{}
	}
	if c.DataSources == nil {
		c.DataSources = MapOfDatasource{}
	}

	// If we are already inside a plugin process we should not need to
	// discover anything.
	if os.Getenv(pluginsdk.MagicCookieKey) == pluginsdk.MagicCookieValue {
		return nil
	}

	// TODO: use KnownPluginFolders here. TODO probably after JSON is deprecated
	// so that we can keep the current behavior just the way it is.

	// Next, look in the same directory as the executable.
	exePath, err := os.Executable()
	if err != nil {
		log.Printf("[ERR] Error loading exe directory: %s", err)
	} else {
		if err := c.discoverExternalComponents(filepath.Dir(exePath)); err != nil {
			return err
		}
	}

	// Next, look in the default plugins directory inside the configdir/.packer.d/plugins.
	dir, err := pathing.ConfigDir()
	if err != nil {
		log.Printf("[ERR] Error loading config directory: %s", err)
	} else {
		if err := c.discoverExternalComponents(filepath.Join(dir, "plugins")); err != nil {
			return err
		}
	}

	// Next, look in the CWD.
	if err := c.discoverExternalComponents("."); err != nil {
		return err
	}

	// Check whether there is a custom Plugin directory defined. This gets
	// absolute preference.
	if packerPluginPath := os.Getenv("PACKER_PLUGIN_PATH"); packerPluginPath != "" {
		sep := ":"
		if runtime.GOOS == "windows" {
			// on windows, PATH is semicolon-separated
			sep = ";"
		}
		plugPaths := strings.Split(packerPluginPath, sep)
		for _, plugPath := range plugPaths {
			if err := c.discoverExternalComponents(plugPath); err != nil {
				return err
			}
		}
	}

	return nil
}

func (c *PluginConfig) discoverExternalComponents(path string) error {
	var err error

	if !filepath.IsAbs(path) {
		path, err = filepath.Abs(path)
		if err != nil {
			return err
		}
	}
	var externallyUsed []string

	pluginPaths, err := c.discoverSingle(filepath.Join(path, "packer-builder-*"))
	if err != nil {
		return err
	}
	for pluginName, pluginPath := range pluginPaths {
		newPath := pluginPath // this needs to be stored in a new variable for the func below
		c.Builders.Set(pluginName, func() (packersdk.Builder, error) {
			return c.Client(newPath).Builder()
		})
		externallyUsed = append(externallyUsed, pluginName)
	}
	if len(externallyUsed) > 0 {
		sort.Strings(externallyUsed)
		log.Printf("[INFO] using external builders: %v", externallyUsed)
		externallyUsed = nil
	}

	pluginPaths, err = c.discoverSingle(filepath.Join(path, "packer-post-processor-*"))
	if err != nil {
		return err
	}
	for pluginName, pluginPath := range pluginPaths {
		newPath := pluginPath // this needs to be stored in a new variable for the func below
		c.PostProcessors.Set(pluginName, func() (packersdk.PostProcessor, error) {
			return c.Client(newPath).PostProcessor()
		})
		externallyUsed = append(externallyUsed, pluginName)
	}
	if len(externallyUsed) > 0 {
		sort.Strings(externallyUsed)
		log.Printf("using external post-processors %v", externallyUsed)
		externallyUsed = nil
	}

	pluginPaths, err = c.discoverSingle(filepath.Join(path, "packer-provisioner-*"))
	if err != nil {
		return err
	}
	for pluginName, pluginPath := range pluginPaths {
		newPath := pluginPath // this needs to be stored in a new variable for the func below
		c.Provisioners.Set(pluginName, func() (packersdk.Provisioner, error) {
			return c.Client(newPath).Provisioner()
		})
		externallyUsed = append(externallyUsed, pluginName)
	}
	if len(externallyUsed) > 0 {
		sort.Strings(externallyUsed)
		log.Printf("using external provisioners %v", externallyUsed)
		externallyUsed = nil
	}

	pluginPaths, err = c.discoverSingle(filepath.Join(path, "packer-datasource-*"))
	if err != nil {
		return err
	}
	for pluginName, pluginPath := range pluginPaths {
		newPath := pluginPath // this needs to be stored in a new variable for the func below
		c.DataSources.Set(pluginName, c.Client(newPath).Datasource)
		externallyUsed = append(externallyUsed, pluginName)
	}
	if len(externallyUsed) > 0 {
		sort.Strings(externallyUsed)
		log.Printf("using external datasource %v", externallyUsed)
		externallyUsed = nil
	}

	pluginPaths, err = c.discoverSingle(filepath.Join(path, "packer-plugin-*"))
	if err != nil {
		return err
	}

	for pluginName, pluginPath := range pluginPaths {
		if err := c.DiscoverMultiPlugin(pluginName, pluginPath); err != nil {
			return err
		}
	}

	return nil
}

func (c *PluginConfig) discoverSingle(glob string) (map[string]string, error) {
	matches, err := filepath.Glob(glob)
	if err != nil {
		return nil, err
	}

	res := make(map[string]string)

	prefix := filepath.Base(glob)
	prefix = prefix[:strings.Index(prefix, "*")]
	for _, match := range matches {
		file := filepath.Base(match)

		// skip folders like packer-plugin-sdk
		if stat, err := os.Stat(file); err == nil && stat.IsDir() {
			continue
		}

		// On Windows, ignore any plugins that don't end in .exe.
		// We could do a full PATHEXT parse, but this is probably good enough.
		if runtime.GOOS == "windows" && strings.ToLower(filepath.Ext(file)) != ".exe" {
			log.Printf(
				"[DEBUG] Ignoring plugin match %s, no exe extension",
				match)
			continue
		}

		// If the filename has a ".", trim up to there
		if idx := strings.Index(file, ".exe"); idx >= 0 {
			file = file[:idx]
		}

		// Look for foo-bar-baz. The plugin name is "baz"
		pluginName := file[len(prefix):]
		log.Printf("[DEBUG] Discovered plugin: %s = %s", pluginName, match)
		res[pluginName] = match
	}

	return res, nil
}

// DiscoverMultiPlugin takes the description from a multiplugin binary and
// makes the plugins available to use in Packer. Each plugin found in the
// binary will be addressable using `${pluginName}-${builderName}` for example.
// pluginName could be manually set. It usually is a cloud name like amazon.
// pluginName can be extrapolated from the filename of the binary; so
// if the "packer-plugin-amazon" binary had an "ebs" builder one could use
// the "amazon-ebs" builder.
func (c *PluginConfig) DiscoverMultiPlugin(pluginName, pluginPath string) error {
	out, err := exec.Command(pluginPath, "describe").Output()
	if err != nil {
		return err
	}
	var desc pluginsdk.SetDescription
	if err := json.Unmarshal(out, &desc); err != nil {
		return err
	}

	pluginPrefix := pluginName + "-"

	for _, builderName := range desc.Builders {
		builderName := builderName // copy to avoid pointer overwrite issue
		key := pluginPrefix + builderName
		if builderName == pluginsdk.DEFAULT_NAME {
			key = pluginName
		}
		c.Builders.Set(key, func() (packersdk.Builder, error) {
			return c.Client(pluginPath, "start", "builder", builderName).Builder()
		})
	}

	if len(desc.Builders) > 0 {
		log.Printf("[INFO] found external %v builders from %s plugin", desc.Builders, pluginName)
	}

	for _, postProcessorName := range desc.PostProcessors {
		postProcessorName := postProcessorName // copy to avoid pointer overwrite issue
		key := pluginPrefix + postProcessorName
		if postProcessorName == pluginsdk.DEFAULT_NAME {
			key = pluginName
		}
		c.PostProcessors.Set(key, func() (packersdk.PostProcessor, error) {
			return c.Client(pluginPath, "start", "post-processor", postProcessorName).PostProcessor()
		})
	}

	if len(desc.PostProcessors) > 0 {
		log.Printf("[INFO] found external %v post-processors from %s plugin", desc.PostProcessors, pluginName)
	}

	for _, provisionerName := range desc.Provisioners {
		provisionerName := provisionerName // copy to avoid pointer overwrite issue
		key := pluginPrefix + provisionerName
		if provisionerName == pluginsdk.DEFAULT_NAME {
			key = pluginName
		}
		c.Provisioners.Set(key, func() (packersdk.Provisioner, error) {
			return c.Client(pluginPath, "start", "provisioner", provisionerName).Provisioner()
		})
	}
	if len(desc.Provisioners) > 0 {
		log.Printf("found external %v provisioner from %s plugin", desc.Provisioners, pluginName)
	}

	for _, datasourceName := range desc.Datasources {
		datasourceName := datasourceName // copy to avoid pointer overwrite issue
		c.DataSources.Set(pluginPrefix+datasourceName, func() (packersdk.Datasource, error) {
			return c.Client(pluginPath, "start", "datasource", datasourceName).Datasource()
		})
	}
	if len(desc.Datasources) > 0 {
		log.Printf("found external %v datasource from %s plugin", desc.Datasources, pluginName)
	}

	return nil
}

func (c *PluginConfig) Client(path string, args ...string) *PluginClient {
	originalPath := path

	// Check for special case using `packer plugin PLUGIN`
	if strings.Contains(path, PACKERSPACE) {
		parts := strings.Split(path, PACKERSPACE)
		path = parts[0]
		args = parts[1:]
	}

	// First attempt to find the executable by consulting the PATH.
	path, err := exec.LookPath(path)
	if err != nil {
		// If that doesn't work, look for it in the same directory
		// as the `packer` executable (us).
		log.Printf("[INFO] exec.LookPath: %s : %v. Checking same directory as executable.", path, err)
		exePath, err := os.Executable()
		if err != nil {
			log.Printf("Couldn't get current exe path: %s", err)
		} else {
			log.Printf("Current exe path: %s", exePath)
			path = filepath.Join(filepath.Dir(exePath), filepath.Base(originalPath))
		}
	}

	// If everything failed, just use the original path and let the error
	// bubble through.
	if path == "" {
		path = originalPath
	}

	if strings.Contains(originalPath, PACKERSPACE) {
		log.Printf("[TRACE] Starting internal plugin %s", args[len(args)-1])
	} else {
		log.Printf("[TRACE] Starting external plugin %s %s", path, strings.Join(args, " "))
	}
	var config PluginClientConfig
	config.Cmd = exec.Command(path, args...)
	config.Managed = true
	config.MinPort = c.PluginMinPort
	config.MaxPort = c.PluginMaxPort
	return NewClient(&config)
}
<|endoftext|>


<commit_before><commit_msg>Dump hello LLVM IR.<commit_after><|endoftext|>


<commit_before><commit_msg>minor<commit_after><|endoftext|>


<commit_before>// Package forge provides an api to deal with parsing configuration files.
//
// Config file example:
//
//     # example.cfg
//     top_level = "a string";
//     primary {
//       primary_int = 500;
//       sub_section {
//         sub_float = 50.5;  # End of line comment
//       }
//     }
//     secondary {
//       secondary_bool = true;
//       secondary_null = null;
//
//       # Reference other config value
//       local_ref = .secondary_null;
//       global_ref = primary.sub_section.sub_float;
//
//       # Include all files matching the provided pattern
//       include "/etc/app/*.cfg";
//     }
//
//
// Config file format:
//
//     IDENTIFIER: [_a-zA-Z]+
//     NUMBERS: [0-9]+
//
//     BOOL: 'true' | 'false'
//     NULL: 'null'
//     INTEGER: NUMBERS | ('-' NUMBERS)
//     FLOAT: (NUMBERS '.' NUMBERS) | ('-' NUMBERS . NUMBERS)
//     STRING: '"' .* '"'
//     REFERENCE: [IDENTIFIER] ('.' IDENTIFIER)+
//     VALUE: BOOL | NULL | INTEGER | FLOAT | STRING | REFERENCE
//
//     INCLUDE: 'include ' STRING ';'
//     DIRECTIVE: (IDENTIFIER '=' VALUE | INCLUDE) ';'
//     SECTION: IDENTIFIER '{' (DIRECTIVE | SECTION)* '}'
//     COMMENT: '#' .* NEWLINE '\n'
//
//     CONFIG_FILE: (COMMENT | DIRECTIVE | SECTION)*
//
//
// Values
//  * String:
//      Any value enclosed in double quotes (single quotes not allowed) (e.g. "string")
//  * Integer:
//      Any number without decimal places (e.g. 500)
//  * Float:
//      Any number with decimal places (e.g. 500.55)
//  * Boolean:
//      The identifiers 'true' or 'false' of any case (e.g. TRUE, True, true, FALSE, False, false)
//  * Null:
//      The identifier 'null' of any case (e.g. NULL, Null, null)
//  * Global reference:
//      An identifier which may contain periods, the references are resolved from the global
//      section (e.g. global_value, section.sub_section.value)
//  * Local reference:
//      An identifier which main contain periods which starts with a period, the references
//      are resolved from the settings current section (e.g. .value, .sub_section.value)
//
// Directives
//  * Comment:
//      A comment is a pound symbol ('#') followed by any text any which ends with a newline (e.g. '# I am a comment\n')
//      A comment can either be on a line of it's own or at the end of any line. Nothing can come after the comment
//      until after the newline.
//  * Directive:
//      A directive is a setting, a identifier and a value. They are in the format '<identifier> = <value>;'
//      All directives must end in a semicolon. The value can be any of the types defined above.
//  * Section:
//      A section is a grouping of directives under a common name. They are in the format '<section_name> { <directives> }'.
//      All sections must be wrapped in brackets ('{', '}') and must all have a name. They do not end in a semicolon.
//      Sections may be left empty, they do not have to contain any directives.
//  * Include:
//      An include statement tells the config parser to include the contents of another config file where the include
//      statement is defined. Includes are in the format 'include "<pattern>";'. The <pattern> can be any glob
//      like pattern which is compatible with `path.filepath.Match` http://golang.org/pkg/path/filepath/#Match
//
package forge

import (
	"bytes"
	"io"
	"strings"
)

// ParseBytes takes a []byte representation of the config file, parses it
// and responds with `*Section` and potentially an `error` if it cannot
// properly parse the config
func ParseBytes(data []byte) (*Section, error) {
	return ParseReader(bytes.NewReader(data))
}

// ParseFile takes a string filename for the config file, parses it
// and responds with `*Section` and potentially an `error` if it cannot
// properly parse the configf
func ParseFile(filename string) (*Section, error) {
	parser, err := NewFileParser(filename)
	if err != nil {
		return nil, err
	}
	err = parser.Parse()
	if err != nil {
		return nil, err
	}

	return parser.GetSettings(), nil
}

// ParseReader takes an `io.Reader` representation of the config file, parses it
// and responds with `*Section` and potentially an `error` if it cannot
// properly parse the config
func ParseReader(reader io.Reader) (*Section, error) {
	parser := NewParser(reader)
	err := parser.Parse()
	if err != nil {
		return nil, err
	}

	return parser.GetSettings(), nil
}

// ParseString takes a string representation of the config file, parses it
// and responds with `*Section` and potentially an `error` if it cannot
// properly parse the config
func ParseString(data string) (*Section, error) {
	return ParseReader(strings.NewReader(data))
}
<commit_msg>update syntax format doc<commit_after>// Package forge provides an api to deal with parsing configuration files.
//
// Config file example:
//
//     # example.cfg
//     top_level = "a string";
//     primary {
//       primary_int = 500;
//       sub_section {
//         sub_float = 50.5;  # End of line comment
//       }
//     }
//     secondary {
//       secondary_bool = true;
//       secondary_null = null;
//
//       # Reference other config value
//       local_ref = .secondary_null;
//       global_ref = primary.sub_section.sub_float;
//
//       # Include all files matching the provided pattern
//       include "/etc/app/*.cfg";
//     }
//
//
// Config file format:
//
//     IDENTIFIER: [_a-zA-Z]+
//     NUMBERS: [0-9]+
//
//     BOOL: 'true' | 'false'
//     NULL: 'null'
//     INTEGER: ('-')? NUMBERS
//     FLOAT: ('-')? NUMBERS '.' NUMBERS
//     STRING: '"' .* '"'
//     REFERENCE: (IDENTIFIER)? ('.' IDENTIFIER)+
//     VALUE: BOOL | NULL | INTEGER | FLOAT | STRING | REFERENCE
//
//     INCLUDE: 'include ' STRING ';'
//     DIRECTIVE: (IDENTIFIER '=' VALUE | INCLUDE) ';'
//     SECTION: IDENTIFIER '{' (DIRECTIVE | SECTION)* '}'
//     COMMENT: '#' .* NEWLINE '\n'
//
//     CONFIG_FILE: (COMMENT | DIRECTIVE | SECTION)*
//
//
// Values
//  * String:
//      Any value enclosed in double quotes (single quotes not allowed) (e.g. "string")
//  * Integer:
//      Any number without decimal places (e.g. 500)
//  * Float:
//      Any number with decimal places (e.g. 500.55)
//  * Boolean:
//      The identifiers 'true' or 'false' of any case (e.g. TRUE, True, true, FALSE, False, false)
//  * Null:
//      The identifier 'null' of any case (e.g. NULL, Null, null)
//  * Global reference:
//      An identifier which may contain periods, the references are resolved from the global
//      section (e.g. global_value, section.sub_section.value)
//  * Local reference:
//      An identifier which main contain periods which starts with a period, the references
//      are resolved from the settings current section (e.g. .value, .sub_section.value)
//
// Directives
//  * Comment:
//      A comment is a pound symbol ('#') followed by any text any which ends with a newline (e.g. '# I am a comment\n')
//      A comment can either be on a line of it's own or at the end of any line. Nothing can come after the comment
//      until after the newline.
//  * Directive:
//      A directive is a setting, a identifier and a value. They are in the format '<identifier> = <value>;'
//      All directives must end in a semicolon. The value can be any of the types defined above.
//  * Section:
//      A section is a grouping of directives under a common name. They are in the format '<section_name> { <directives> }'.
//      All sections must be wrapped in brackets ('{', '}') and must all have a name. They do not end in a semicolon.
//      Sections may be left empty, they do not have to contain any directives.
//  * Include:
//      An include statement tells the config parser to include the contents of another config file where the include
//      statement is defined. Includes are in the format 'include "<pattern>";'. The <pattern> can be any glob
//      like pattern which is compatible with `path.filepath.Match` http://golang.org/pkg/path/filepath/#Match
//
package forge

import (
	"bytes"
	"io"
	"strings"
)

// ParseBytes takes a []byte representation of the config file, parses it
// and responds with `*Section` and potentially an `error` if it cannot
// properly parse the config
func ParseBytes(data []byte) (*Section, error) {
	return ParseReader(bytes.NewReader(data))
}

// ParseFile takes a string filename for the config file, parses it
// and responds with `*Section` and potentially an `error` if it cannot
// properly parse the configf
func ParseFile(filename string) (*Section, error) {
	parser, err := NewFileParser(filename)
	if err != nil {
		return nil, err
	}
	err = parser.Parse()
	if err != nil {
		return nil, err
	}

	return parser.GetSettings(), nil
}

// ParseReader takes an `io.Reader` representation of the config file, parses it
// and responds with `*Section` and potentially an `error` if it cannot
// properly parse the config
func ParseReader(reader io.Reader) (*Section, error) {
	parser := NewParser(reader)
	err := parser.Parse()
	if err != nil {
		return nil, err
	}

	return parser.GetSettings(), nil
}

// ParseString takes a string representation of the config file, parses it
// and responds with `*Section` and potentially an `error` if it cannot
// properly parse the config
func ParseString(data string) (*Section, error) {
	return ParseReader(strings.NewReader(data))
}
<|endoftext|>


<commit_before>package nss

import (
	"bytes"
	"net"
)

func Fuzz(data []byte) int {
	// This example won't build as is, because ParseNSSConf function is not exported
	// from net package. To build this example, you need to patch net package to
	// rename parseNSSConf to ParseNSSConf first.
	/*
	if net.ParseNSSConf(bytes.NewReader(data)) == nil {
		return 0
	}
	*/
	return 1
}
<commit_msg>fix nss example yet again<commit_after>package nss

/*
import (
	"bytes"
	"net"
)
*/

func Fuzz(data []byte) int {
	// This example won't build as is, because ParseNSSConf function is not exported
	// from net package. To build this example, you need to patch net package to
	// rename parseNSSConf to ParseNSSConf first.
	/*
	if net.ParseNSSConf(bytes.NewReader(data)) == nil {
		return 0
	}
	*/
	return 1
}
<|endoftext|>


<commit_before><commit_msg>fix manifestpath for verify install. (#28345)<commit_after><|endoftext|>